Because the throughput of my radio and device is limited, I wanted to compress my control string. I decided to compress the command into an 8 bytes (quasi) string (throttle high, throttle low, pitch, roll, yaw plus/minus, yaw value, checksum, stop byte) and after parsing in four variables:
- Pitch (between -45° and 45°)
- Roll (between -45° and 45°)
- Yaw (between -180° and 180°)
- Throttle (between 1000 and ~1900)
Because Some number ranges don't fit into a single byte (0 to 255 number range), I used two instead (throttle: one byte for hundreds (1-9) and one byte for tenners (1-99); Yaw: One byte for plus or minus and one byte for 0° - 180°). I send and read these bytes as characters. Then I convert them into numbers (0-255).
I noticed that sometimes a few reads are totally out of range (e.g. value: -31001) but checksum test is OK. I don't know exactly why (maybe radio, maybe I caused unexpected behavior because of type conversions here). This is why I made an additional range test. Now the remote control seems to be reliable.
However I don't feel very nice about it, because I do signed/unsigned and! number range conversions, the checksum function is also not very reliable. Maybe someone has suggestions how to make the code better.
Code (The command stored in buffer is already red correctly until the stop byte and valid in length):
bool Receiver::parse_radio(char *buffer) {
int16_t throttle_high = (uint8_t)buffer[0]; // 1. 1 - 9
int16_t throttle_low = (uint8_t)buffer[1]; // 2. 0 - 99
int16_t pit = (uint8_t)buffer[2] - 127; // 3. -45° - 45°
int16_t rol = (uint8_t)buffer[3] - 127; // 4. -45° - 45°
int16_t yaw_pm = (uint8_t)buffer[4] - 127; // 5. -1 || +1
int16_t yaw_val = (uint8_t)buffer[5]; // 6. yaw angle in degrees 180°
int16_t chk = (uint8_t)buffer[6]; // 7. checksum
int16_t thr = 1000 + (throttle_high * 100) + throttle_low;
int16_t yaw = yaw_val * yaw_pm;
// Calculate checksum
uint8_t checksum = 0;
for(int i = 0; i < 6; i++) {
checksum = (checksum + buffer[i]) << 1; // % 256 can be saved because of the uint8_t
}
// Validity check:
// First checksum
if(checksum != chk)
return false;
// Later other values
if(yaw_pm < -1 || yaw_pm > 1)
return false;
if(rol > 45 || rol < -45)
return false;
if(pit > 45 || pit < -45)
return false;
if(yaw > 180 || yaw < -180)
return false;
if(thr > RC_THR_80P || thr < RC_THR_MIN)
return false;
// Do rest here
return true;
}