【问题标题】:RF motor/servo control射频电机/伺服控制
【发布时间】:2016-09-12 00:10:00
【问题描述】:

在过去的几周里,我一直在为此烦恼,无法在网上找到有关我应该如何执行此操作的有用信息。

目标:

  • 从一个pi 驱动多个伺服/RC 电机无线 到另一个pi
  • 本质上,我想使用pi 构建一个RC 遥控器,并在接收器端使用第二个pi

到目前为止我做了什么:

  • 我已经能够使用 串行库 以及两个 Pi 上的 Tx 和 Rx 引脚通过廉价的 433MHz 接收器/发送器成功发送串行数据。但是,我需要同时发送至少六对两位数字(即 12 个数字)。这可以使用pi/arduino 上的串行库来完成,但它会导致主连续程序循环的采样率减慢到 200Hz 以下,这是一个问题。

下一步和问题:

  • 由于串行数据传输无法正常工作,我正在考虑将 PWM 信号直接嵌入到 RF 信号中。 (据我所知,这就是爱好 RC 控制器的工作原理)。
  • pi(据我所知)在发送准确的 PWM 信号方面是垃圾,在正确接收它们方面更糟糕。
  • 澄清一下,我必须通过射频模块执行此操作,而不是通过网络。

我该怎么做?

也许使用两个 Arduino 来进行传输和接收?

有没有可以买的“盾牌”?

是否有图书馆可以为我做到这一点? (Piadruino?)

已编辑: Roland 感谢您的回复

我已经添加了当前的串行传输代码。我不认为这是最有效的方法。如果在另一个 PWM 信号之间有一个暂停传输 PWM 信号,则可以发送更多数据而不仅仅是发送位。我不完全确定,但我认为这就是遥控 RC 飞机控制器发送信号的方式。

请注意,我插入的代码是从一个包含多个模块和几百行代码的更大程序的简单摘录。我确实认为下面几行是串行发送器的核心。

import serial

bProgramLoop = True
while (bProgramLoop == True):

    #...lots of code...

    iThrustPort = int(fThrustPort)
    iThrustStrb = int(fThrustStrb)
    iThrustTail = int(fThrustTail)
    iPortMotorAngle = int(fPortMotorAngle) + 50
    iStrbMotorAngle = int(fStrbMotorAngle) + 50

    sPortMotorSignal = '{:02d}'.format(iThrustPort)
    sStrbMotorSignal = '{:02d}'.format(iThrustStrb)
    sTailMotorSignal = '{:02d}'.format(iThrustTail)
    sPortAngleSignal = '{:02d}'.format(iPortMotorAngle)
    sStrbAngleSignal = '{:02d}'.format(iStrbMotorAngle)

    sSignal = sPortMotorSignal + sStrbMotorSignal + sTailMotorSignal + sPortAngleSignal + sStrbAngleSignal

    oSer.write(sSignal) #where sSignal = 1234567890 for example or any combination of numbers from 0 to 9

【问题讨论】:

  • 请向我们展示您的代码。很难对看不见的东西提出改进建议。
  • 只是一个想法。既然你在 pi 中,使用单独的线程进行传输怎么样?线程很酷。但也很容易弄乱。

标签: python arduino raspberry-pi wireless pwm


【解决方案1】:

串口波特率

在您的评论中,您提到了 4800 的波特率。对于串行端口而言,这非常低。串行端口使用两级(二进制)信令,因此以比特/秒为单位的数据速率等于以波特为单位的符号速率。

但我查看的一个收发器数据表将 5 kbits/s 列为典型传输速度,将 9.6 kbit/s 作为最大速率。也许您可以尝试改进天线以提高传输率?

但是 4800 波特串行意味着您不会获得超过 4800/8 = 600 字节/秒的带宽(这不考虑停止位和奇偶校验位之类的东西)。使用 10 字节的消息,您最多应该得到 60Hz。一个 5 字节的消息可以将其提高到 120 Hz。因此,发射器似乎是限制因素。

这意味着你必须节俭每一点!

打包数据

您的代码将数据作为连接的十进制字符串传输。对于 5 个数字,这需要 10 个字节。可以把它减半:

让我们在 0-100 范围内生成 5 个 2 位数字。

In [1]: import random

In [2]: data = [random.randint(0, 101) for _ in range(5)]

In [3]: data
Out[3]: [18, 80, 55, 96, 44]

两位十进制数只需要一个字节来存储它们。即使是两位数的十六进制数也适合一个字节。所以让我们把这些数字组合成一个字节串。

In [4]: import struct

In [5]: struct.pack('5B', *data)
Out[5]: b'\x12P7`,'

In [6]: len(struct.pack('5B', *data))
Out[6]: 5

您可以在单个串行write 调用中发送这个 5 字节字符串,然后在接收端解压它们。

让我们比较两个概念 w.r.t 速度。我已经将您的原始代码和我的struct 解决方案都封装在函数中,因此我可以轻松地使用IPython 的%timeit 魔术命令来测量它们。

In [7]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:def astext():
:    data = [random.randint(0, 101) for _ in range(5)]
:    sPortMotorSignal = '{:02d}'.format(data[0])
:    sStrbMotorSignal = '{:02d}'.format(data[1])
:    sTailMotorSignal = '{:02d}'.format(data[2])
:    sPortAngleSignal = '{:02d}'.format(data[3])
:    sStrbAngleSignal = '{:02d}'.format(data[4])
:    sSignal = (sPortMotorSignal + sStrbMotorSignal + sTailMotorSignal +
:               sPortAngleSignal + sStrbAngleSignal)
:    return sSignal
:
:
:def asbinary():
:    data = [random.randint(0, 101) for _ in range(5)]
:    return struct.pack('5B', *data)
:--

In [8]: %timeit astext()
10000 loops, best of 3: 31.6 µs per loop

In [9]: %timeit asbinary()
10000 loops, best of 3: 23.5 µs per loop

In [10]: (31.6-23.5)/31.6
Out[10]: 0.2563

(这是在 intel core2 处理器上。Pi 中的 ARM 芯片可能会更慢。)生成二进制字符串所需的时间比生成文本字符串大约少 25%。

但从这些时候您可以看到,这些可能对性能并不重要。他们可以以 >30 kHz 的频率组合数据。 Pi 必须慢 150 倍才能达到时间要求。

重要的是二进制字符串的长度是文本字符串的一半,所以我希望它的传输速度大约是两倍。

您应该仔细考虑的是每个信号实际需要多少个不同的信号电平? 4 位为您提供 2⁴ = 16 级,而 8 位为您提供 2⁸ = 256 级。如果您的应用程序可以使用 16 个信号级别,您可以将消息打包为 5*4= 20 位。

【讨论】:

  • 嗨 Roland,我已经编辑了我的原始帖子并添加了代码。感谢您的回复,非常感谢
  • hmmm,好的,我试试二进制字符串。谢谢。关于波特率,是的,我的代码中有它。但通过实验手段,我已经确定任何高于 4800 的波特率都无法通过 433MHz 发射器接收器进行传输。射频链路套件是否质量低劣且不足从而导致波特率低?
  • 嗨罗兰。谢谢你的回复,你说的60Hz是准确的。我得到一个大约 58Hz 的主循环采样率。我将代码更改为二进制字符串,看看我能得到什么结果。此外,您还知道任何可以在更高波特率下工作的发射器接收器吗?波特率规格更高的东西?
  • 我发现的一个数据表将 5 kbit/s 列为典型速度。这意味着你将不得不非常节俭地使用比特。
  • Roland,我很难理解的另一个奇怪的事情是:对于相同的波特率(4800),我添加到字符串中的数字越多,传输信号的完整性就会越来越差。从 10/12 位开始,信号将在接收端解码为垃圾。
【解决方案2】:

(代表 OP 发布).

我已经解决了上面解释的串行数据传输问题。具体细节请看我的另一篇文章:Serial data transmission input-output delay with Raspberry Pi

我希望这对任何人都有帮助。通过这种方式,您可以通过串行连接传输数据,无论是通过射频链路模块还是通过直接接线,没有时间延迟。

请注意,许多射频链路模块的最大传输速率为 4800 波特,以实现稳定和良好的连接。

【讨论】:

    猜你喜欢
    • 2019-11-24
    • 2016-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多