Radio control



Accessing quadcopter memory over radio

The usual method of controlling quadcopters is to transmit a train of PPM signals from a radio transmitter, measure the length of the individual pulses on a microcontroller, via a radio receiver .  As part of my DIY ethos, and as a learning exercise, I have made the above controller with an nrf24l01 moduled and an Arduino Nano.  In a nutshell, the Arduino Nano captures the 2D joystick positions, used for yaw, throttle, pitch and roll, and the button presses.  A data packet is then sent by radio to the Quadcopter.  In fact there is a more powerful implementation going on.  What is interesting is how the controller sends data to the Quadcopter - it actually manipulates the memory directly on the Quadcopter AVR - how does it do that?

Well, first of all the Quadcopter defines the memory addresses that the controller has access to by setting recording a pointer to the desired variable - note that the cast means that it doesn't matter whether the variable is a float, int, or arbitrary memory structure (struct, union, etc).

Quadcopter side:
uint8_t *radio_pointers[MAX_PTR];

void setup_addressing(void)
{
radio_pointers[0] = (uint8_t *)&pitch_pid.kp;
radio_pointers[1] = (uint8_t *)&pitch_pid.ki;
radio_pointers[2] = (uint8_t *)&pitch_pid.kd;
radio_pointers[3] = (uint8_t *)&throttle;
radio_pointers[4] = (uint8_t *)&serial_output;
radio_pointers[5] = (uint8_t *)&radio_pitch;
radio_pointers[6] = (uint8_t *)&pitch_rate_p;
radio_pointers[7] = (uint8_t *)&pitch_rmsd;
radio_pointers[8] = (uint8_t *)&autotune;
}

On the radio controller side, we can then package up data to send:


Radio controller side:
void package_var(uint8_t *data, uint8_t index, void *var, uint8_t memlen)
{
  uint8_t *mem_ptr;
  mem_ptr = (uint8_t *)var;

  data[0] = index;
  for (uint8_t i=0; i<memlen; i++) data[i+1] = *(mem_ptr++);

  payload_len = 1+memlen;
}

Which is called on the radio controller like so:

Usage:

float a=-15.2345;
uint8_t data[32];

package_var(&data, 5, &a, sizeof(float));

This results in a data package in the data array that is 1+the size of the variable to be transmitted - the first byte corresponds to the entry in the Quadcopter radio_pointers list - i.e. in this case entry 5 would tell the quadcopter to set the quadcopter variable radio_pitch to -15.2345.  This data package can be then transmitted to the quadcopter, where it needs interpreting and unpacking.

The quadcopter then receives the data payload and handles it - it finds the desired offset in the radio_pointers array, gets the address in the quadcopter AVR memory and then writes the radio data payload directly into the memory - no messing about with special cases.  What I like about this is the ability to send complex structures and it requires no special handling - it is just memory and because the chips are the same in Arduino Nano and the Quadcopter (Atmega328), and because the compiler is the same, there is no need to worry about Endianness or how data types are structured in memory (because it is the same on both chips!).  So on the quadcopter side:

Quadcopter side:
void handle_radio_comms(void)
{
uint8_t paylen, offset;
uint8_t data_array[10];
 uint8_t *mem_ptr;

paylen = getDynamicPayloadSize();
nrf24_getData(data_array); // Read in dynamic length payload into temp data_array

if (paylen<=1) return;

offset = data_array[0]; // First byte is length of data packet

mem_ptr = (uint8_t *)radio_pointers[offset]; // Pointer points to the given pointer stored in array
for (uint8_t i=0;i<paylen-1;i++)
{
*(mem_ptr) = data_array[i+1]; // Write memory address that pointer points to with data
mem_ptr++; // Increment address of pointer by one byte
}
}

And it is as easy as that - the radio controller I have built, can manipulate the memory "directly" on the quadcopter! This is potentially very powerful - by opening up certain variables to radio control, I can program PID parameters and any other setting remotely, without having to physically connect the quadcopter to a PC, or re-compile and flash the Quadcopter just because I want to tweak a variable.

Comments

Popular posts from this blog

Getting started with the Pro Micro Arduino Board

Arduino and Raspberry Pi serial communciation