0

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 pion 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
halfer
  • 19,824
  • 17
  • 99
  • 186
Misha
  • 556
  • 1
  • 8
  • 25
  • Please show us your code. It is hard to suggest improvements on things one cannot see. – Roland Smith May 16 '16 at 09:43
  • just a thought though.since you are in pi, How about using a seperate thread for transmission? threads are cool. but can go messy easily too. – Ccr May 16 '16 at 11:57

2 Answers2

0

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 w.r.t 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.

Roland Smith
  • 42,427
  • 3
  • 64
  • 94
  • Hi Roland, I have edited my original post and added the code. Thank you for your reply, much appretiated – Misha May 16 '16 at 11:54
  • hmmm, ok I will give the binary string a try. thanks. With regards to the baud rate, yes, I have it in my code. But through experimental means I have determined that any baud rate higher than 4800 fails to transmit over the 433MHz transmitter receiver. Is the RF link kit low quality and inadequate and thus causing low baud rates? – Misha May 16 '16 at 12:39
  • Hi Roland. Thank you for your response, the 60Hz you mentioned is accurate. I get a main loop sample rate of about 58Hz. I will change the code to the binary string and see what results I can get. Further more do you know of any transmitter receivers that can function at higher baud rates? something with massively higher baud rate specs? – Misha May 16 '16 at 13:12
  • One data-sheet I found listed 5 kbit/s as a typical speed. That means you're going to have to be very frugal with bits. – Roland Smith May 16 '16 at 13:26
  • Roland, another curious thing I am struggling to understand is: for the same baud rate (4800) the transmitted signal would be come worse and worse in integrity the more digits I added to the string. From 10/12 digits the signal would decode into rubbish on the receiver end. – Misha May 16 '16 at 13:29
  • That probably has to do with how the transceiver is built. But that's outside of my experience and skill set, so I can't help you there. – Roland Smith May 16 '16 at 13:33
  • Roland thank you very much. you have been of great help regarding the serial signalling!!! Do you think it is necessary to investigate PWM RF signalling methods? How do they do it in the "10 Channel Remotes" for RC Aircraft? – Misha May 16 '16 at 13:37
  • The problem I have is I need (for now) to control 5 motors, which need to receiver a number between 0 and 99. I am still super new to this area, so I am not sure what the most efficient way is to get that data across. – Misha May 16 '16 at 13:40
  • W.r.t remotes: not a clue. It's outside my field. But with regards to the motor signals, would it be OK to use steps of 6.26 for the signal? Then you could fit 0-100 in 4 bits... – Roland Smith May 16 '16 at 13:45
0

(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.

halfer
  • 19,824
  • 17
  • 99
  • 186