简体   繁体   中英

RF motor/servo control

I have been wrecking my head over this the last weeks and cannot find useful information online on how I should do this.

The Goal:

  • Drive several servo/RC motors wireless from one pi to another pi .
  • In essence, I want to build a RC remote control using a pi , with a second pi on the receiver end.

What I have done so far:

  • I have been able to use the serial library and the Tx and Rx pins on the two Pi to successfully send serial data over a cheap 433MHz receiver/transmitter. However, I need to send over at least six pairs of two-digit numbers simultaneously(ie 12 numbers). This can be done using the serial library on the pi/arduino , but it causes the sample rate of the main continuous program loop to slow down to below 200Hz, which is a problem.

Next step and problems:

  • Since the serial data transmission is not working adequately I was thinking of embedding PWM signals directly into the RF signal. (As far as I can figure out this is how the hobby RC controllers work anyway).
  • The pi (as far as I know) is rubbish at sending accurate PWM signals and even worse at picking them up correctly.
  • Just to clarify I have to do this over a RF module, not over the web.

How can I do this?

Perhaps using two Arduinos to do the transmission and receiving?

Are there "shields" that I could buy?

Are there libraries that could do this for me? ( Pi or adruino ?)

Edited: Roland thank you for your reply

I have added the current serial transmission code. I dont think this is the most efficient way of doing it. If one transmits PWM signals with a pause between another PWM signal one can send far more data instead of just sending bits. I am not entirely sure, but I thought that is how the Remote Control RC aircraft controllers send their signals.

Please note that the code I have inserted is a simple extract from a much larger program with several modules and a couple of hundred lines of code. I do think the few lines below are at the heart of the serial transmitter.

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

Serial baud rate

In your comment you mention a baud rate of 4800. That is very low for a serial port. Serial ports use two-level (binary) signaling, so the data rate in bits per second is equal to the symbol rate in baud.

But one data-sheet I looked at for a transceiver listed 5 kbits/s as a typical transfer speed, and 9.6 kbit/s as the maximum rate. Maybe you could try improving the antennae to up the transfer rate?

But 4800 baud serial means you won't get more than 4800/8 = 600 bytes/s bandwidth (and that is disregarding things like stop bits and parity bits). With a 10 byte message you should get at most 60Hz. A 5-byte message could improve that to 120 Hz. So it seems that the transmitter is the limiting factor.

This means you have to be frugal with every bit!

Packing the data

Your code transmits the data as a concatenated decimal string. For 5 numbers this takes 10 bytes. It is possible to cut this in half:

Let's generate 5 2-digit numbers in the range 0-100.

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]

Two digit decimal numbers just need one byte to store them. Even two-digit hexadecimal numbers would fit in a byte. So let's combine the numbers into a byte string.

In [4]: import struct

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

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

You could send this 5-byte string in a single serial write call, and unpack them on the receiving end.

Let's compare the two concpts wrt speed. I have wrapped both your original code and my struct solution in functions, so I can easily use IPython's %timeit magic command to measure them.

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

(This is on an intel core2 processor. The ARM chip in the Pi will probably be slower.) Generating the binary string takes approximately 25% less time than generating the text string.

But from these times you can see that these are probably not performance critical. They can assemble data at >30 kHz. The Pi would have to be 150 times slower for this to be time-critical.

What is important is the binary string is half as long as the text string, so I would expect it to transmit approximately twice as fast.

What you should carefully think about is how many different signal levels do you actually need for each signal? Four bits give you 2⁴ = 16 levels, while 8 bits give you 2⁸ = 256 levels. If your application could live with 16 signal levels, you could pack your messages in 5*4= 20 bits.

(Posted on behalf of the OP) .

I have solved the serial data transmission problem explained above. For exact details go to another post of mine: Serial data transmission input-output delay with Raspberry Pi

I hope this helps anyone. This way you can transmit data over a serial connection whether over a RF link module or over direct wiring with no time delay.

Please note that a lot of the RF link modules have a max transfer rate of 4800baud for a stable and good connection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM