Struct data misalignment during RF transmission

Hi all,

So, I'm building a remote controlled robot using an Arduino Uno R4 Minima as a remote and an Arduino Nano for the "on-board" things. The two is communicating using nRF24L01 modules.

I want to send 3 datapieces to the robot in one package (the values of 3 potmeter on the remote to control different servos on the robot). I make a struct and send it via radio like so:

struct Data_Package {
  int pot0;
  int pot1;
  int pot2;
};
  
Data_Package data;

/////////////////// setting up radio blah blah //////////////////////

  int potValue0= analogRead(A0);
  int angleValue0 = map(potValue0, 0, 1023, 65, 0);

  int potValue1 = analogRead(A1);
  int angleValue1 = map(potValue1, 0, 1023, 0, 45);

  int potValue2 = analogRead(A2);
  int angleValue2 = map(potValue2, 0, 1023, 0, 100);

  data.pot0 = angleValue0;
  data.pot1 = angleValue1;
  data.pot2 = angleValue2;

radio.write(&data, sizeof(Data_Package));

On the receiving device I use this code to get the data out of the message:

void loop() {
  if (radio.available()) {
    // Read data package
    radio.read(&data, sizeof(Data_Package));
}

However, when I check the content of the struct it seems to be misaligned?

When I transform the data back into the same struct I get the following data:

Sent vs Received
pot0 ---------> pot0
pot1 ---------> 0
pot2 ---------> pot1

The third value of the struct is missing entirely and the second value takes up the place of the third. The data I'm sending is pure int, always between the given limits. When I check the contents of the struct on the sending device it seems to be fine. The error is either on the receiving end or lost in the void.

Any idea how to get my missing data? My robot is pretty sad without it.

How many bytes is an int on the R4 compared to an int on the Nano ?

Try using uint16_t as the data type on both instead of int

4 Likes

Also consider __attribute__((packed))

1 Like

FWIW, it is considered bad software engineering practice to directly emit a struct like this.

A better option would be to serialize the struct into a buffer manually, and parse it manually on the other side. Then you can control the exact positioning of the bytes. For example, something along the lines of:

char msg[6];
msg[0] = (angleValue0 >> 8) & 0xff;
msg[1] = angleValue0 & 0xff;
msg[2] = (angleValue1 >> 8) & 0xff;
// etc.

The struct approach you're using sometimes works for two programs where the architectures have the same endianness, same compiler, same struct layouts, etc. But that's not very reliable. The physical layout of structs in C is implementation-dependent. So it's better to use a different approach.

Hey, This worked! Thank you so much. I ended up using int16_t though. I only need to send / receive numbers between -45 and + 100.

Thanks again!

I wondered about that, but as the transmitting system will have no idea about the size of the data on the receiving end I can't see how it would work

Normally both the TX and RX would have the same declaration for struct:

struct __attribute__((packed)) Data_Package {
  uint16_t pot0;
  uint16_t pot1;
  uint16_t pot2;
};

That guarantees an identical memory image for the struct across all boards in the Arduino ecosystem as all processors in it are Little-Endian.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.