D4G AI Racing Part 3.5: Sending Channel Data to the Arduino


The red arrows denote serial data going from the computer to the Arduino

The previous part 3 covered a lot of technical detail about how PPM is used to encode the radio control signals for the different channels, but omitted how the data is sent from the computer to the Arduino controller. Just to recap, part 3 covered communicating from the Arduino to the Taranis Trainer port using PPM, so I've added this part 3.5 to fill in with the computer to Arduino part. This is shown by the red arrows in the image above.

All the details of the code are in the Arduino PPM part of the GitHub repository: https://github.com/maptube/rogue (look under the Arduino subproject for the PPM sketch).

Going back to the PPM protocol in the last post, there are 8 channels, sent in a frame of 22,500uS (22.5 milliseconds). The connection between the computer and the Arduino uses a virtual serial port via the USB connection. The default speed for this type of connection is generally 9600 baud, which is fast enough to get debugging information from the Arduino and to send simple information, but let's do some calculations to see how it would perform with our radio control channel data.

9600 baud = 9600 bits per second, but, using the "8n1" protocol, there are 8 data bits, no parity and one stop bit, so 9 bits per character sent.

In 22.5ms (the PPM frame rate), we can send 9600 bits/sec * (22.5/1000 sec) = 216 bits.

Given 8 channels, that equates to 27 bits per channel. Radio control transmitters generally use around 10 or 11 bits to encode their stick data (it's in the OpenTX source code), so sending data to the Arduino at 9600 baud is entirely feasible.

Now we need to come up with a protocol for encoding the data and sending it over a serial stream that uses 8 bit words (plus one stop bit). Serial data is basically just a stream of characters, but we want to send the maximum amount of information in the minimum number of bits.

The system I've designed transmits two different types of byte, identified by whether the byte starts with a 1 or a zero.

Firstly, the channel number and the four most significant bits of the channel data are sent follows:

0CCC  HHHH  (e.g. 0001 0000 is channel 1, data high=0)

Then the remaining low seven bits of the channel data are sent:

1LLL  LLLL (e.g. 1000 1111 is data low=15)

C=Channel, H=Data high bits, L=Data low bits

This means sending two bytes per channel (8+1, 8+1 = 18 serial bits) for every channel. Eight channels can be encoded in 144 bits, which is well within our 216 bit budget for the PPM frame time and plenty of channels for most radio control applications. Also, the beauty of this system is that, we only need to send the data for the channels that are actually being used. The unused channels can simply be omitted.

Using the three "CCC" bits for the channel means we can encode 0..7 for the channel number, giving 8 channels in total. The full set of 11 channel data bits, "HHHHLLLLLLL", which are split across the two bytes, encode the data for the stick position. While this is 11 bits, the top bit is used as a sign bit, so the data value can range from -1024 to +1023. Zero is used to code the centre position of the stick, with -1024 at the extreme low end and +1023 at the extreme high end. This is because, with 10 data bits and 1 sign bit, %011 1111 1111 = 0x3ff = 1023 and %100 0000 0000 = 0x400 = -1024 in twos complement arithmetic.

The following code is the C# function used to send the data to the serial port, which is simple enough to convert to any programming language:

byte b1 = (byte)( (channel << 4) | ((servo>>7)&0x0f) );

byte b2 = (byte)(0x80 | (servo&0x7f));

byte[] buffer = new byte[] { b1, b2 };

port.Write(buffer, 0, 2);

Look in the Project Rogue, "LeapUnityController" and the "SerialCOM" script for the full code.

One final point, but although I stated earlier that 9600 baud is fast enough, I have used this reliably at 115,200 baud, which is the maximum my Arduino can cope with.

That's really all there is to it, but it's a necessary step towards computer control of a radio control transmitter. You can find a sneak preview of what this can be used for below.

Comments