Code produces impossible result but works after reset

I’ve been working on a robotics project and have tested the platform without using the wireless system and it works great but for some reason when the RF modules are hooked up and the transmitting Arduino is powered on the code breaks. What is weird is that resetting the transmitter causes it to work without any issues. As a side note both the transmitter and receiver use UNO boards and the RF modules are nRF24L01

Here is the code (both the transmitter and receiver in one)

#include <SPI.h>
#include "RF24.h"


#define MODE_TRANSMITTER 1
#define MODE_RECEIVER 0

// Edit here to change mode
#define MODE MODE_TRANSMITTER
#define DEBUG_ENABLE 1

RF24 radio(7, 8);


byte addresses[][6] = {"1Node", "2Node"};
void setup() {
#if DEBUG_ENABLE
  Serial.begin(115200);
#endif
  radio.begin();

  radio.setPALevel(RF24_PA_HIGH);

  // Open Pipes according to radio mode
#if MODE
  radio.openWritingPipe(addresses[1]);
  radio.openReadingPipe(1, addresses[0]);
#else
  radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1, addresses[1]);
#endif
  radio.startListening();
}




void loop() {
#if MODE
  // Transmitter Role
  radio.stopListening();

  // Joystick Mixing
  int throttle, direction = 0;
  int leftMotor, rightMotor = 0;
  throttle = constrain((512 - analogRead(A0)) / 2, -255, 255);
  direction = constrain(-(512 - analogRead(A1)) / 2, -255, 255);
  leftMotor = constrain(throttle + direction, -255, 255);
  rightMotor = constrain(throttle - direction, -255, 255);

#if DEBUG_ENABLE
  // Debugging Info
  Serial.print("Throttle: ");
  Serial.println(throttle, DEC);
  Serial.print("Direction: ");
  Serial.println(direction, DEC);
  Serial.print("LeftVal: ");
  Serial.println(leftMotor, DEC);
  Serial.print("RightVal: ");
  Serial.println(rightMotor, DEC);
#endif

  // Splitting into channels
  uint8_t LF, LR, RF, RR = 0;
  if (leftMotor >= 0 && rightMotor >= 0) {
    LF = leftMotor;
    RF = rightMotor;
    LR, RR = 0;
  }
  else if (leftMotor >= 0 && rightMotor < 0) {
    LF = leftMotor;
    RR = abs(rightMotor);
    LR, RF = 0;
  }
  else if (leftMotor < 0 && rightMotor >= 0) {
    LR = abs(leftMotor);
    RF = rightMotor;
    RR, LF = 0;
  }
  else {
    LR = abs(leftMotor);
    RR = abs(rightMotor);
    LF, RF = 0;
  }

  // Radio Transmission
  uint8_t data[] = {LF, LR, RF, RR};

#if DEBUG_ENABLE
  if (!radio.write(&data, sizeof(uint32_t))) {
    Serial.println("Error Sending Data");
  }
  else {
    Serial.print("Send OK, Data: ");
    Serial.println(data[0], DEC);
    Serial.println(data[1], DEC);
    Serial.println(data[2], DEC);
    Serial.println(data[3], DEC);
  }
#else
  radio.write(&data, sizeof(uint32_t));
#endif
  delay(15);


#else
  // Receiver Role

  // Radio Receive
  uint32_t data;
  if (radio.available()) {
    while (radio.available()) {
      radio.read( &data, sizeof(uint32_t));
    }
    // Debug
    Serial.print("Data Received: ");
    Serial.println(data, DEC);

    // Write to channels
    uint8_t *chunk = (uint8_t*)&data;
    analogWrite(5, chunk[0]);
    analogWrite(6, chunk[1]);
    analogWrite(9, chunk[2]);
    analogWrite(10, chunk[3]);

#if DEBUG_ENABLE
    // Debug
    Serial.println("Chunks:");
    Serial.println(chunk[0], HEX);
    Serial.println(chunk[1], HEX);
    Serial.println(chunk[2], HEX);
    Serial.println(chunk[3], HEX);
#endif

  }
#endif
}

I suspect the issue is at the if block in the transmitter section. Because of the way it is set up only one R/L of LF,LR,RF,RR should be able to be greater than zero at a time, yet in practice three of them end up greater than zero depending on the position of the joystick.

Example of debug output:

Throttle: -147
Direction: 40
LeftVal: -107
RightVal: -187
Send OK, Data: 17
107
0
187

The data is 17, 107, 0, 187 which shouldn’t be possible but it does this every time the transmitter is powered up and then works fine if it is reset. This obviously isn’t being caused by a sync error between the transceivers because the debug info is taken from the transmit side.

Id like to know what is causing this problem since in the final design pressing the reset button wont be an option. Also, if anyone has suggestions on making the if block more elegant or replacing it entirely would be greatly appreciated.

Try this test code:

void setup() {
  int LR, RR = 0;
  Serial.begin (115200);
  LR = 1;
  RR = 2;
  LR, RR = 0;
  Serial.print ("LR = ");
  Serial.println (LR);
  Serial.print ("RR = ");
  Serial.println (RR);  
}
void loop() { }

What do you expect to be printed? Zero for both LR and RR?

I get:

LR = 1
RR = 0

This line in your code (and you have a few of them) doesn't set both variables to zero:

LR, RR = 0;

I was under the impression that all values in the comma separated list would be set to 0 but obviously it does not. I replaced all of those occurrences with the standard x = j notation and it now works fine. It still is kind of strange why it worked after a reset.

Now its time to go test this thing and hopefully not hit any more cars. :slight_smile:

It is very rare for the code to do anything other than what it is supposed to do, which is not always the same as what you think it will do. When you get "impossible" results, that should be a red flag that you need to review your code, do some reading on c syntax, to figure out what your code really does, as opposed to what you think it does. Things like this:

  int throttle, direction = 0;
  int leftMotor, rightMotor = 0;

are surely NOT doing what you think they are....

Regards,
Ray L.

sams_projects:
I was under the impression that all values in the comma separated list would be set to 0 but obviously it does not.

What you may have seen elsewhere is this:

LR = RR = 0;

That sets them both to zero.

I've been researching your issue for the last half an hour. See here for example.

The comma operator is evaluated left to right, with the right-most value retained as the value and type of the result.

eg.

foo = 1, 2, 3, 4;

The variable foo would be 4 in this case, and the other values discarded. In your example:

LR, RR = 0;

Evaluating from left to right it "evaluates" LR (and discards the result) and then "evaluates" RR which becomes the result of the lvalue. Then zero is assigned to RR.

  uint8_t LF, LR, RF, RR = 0;
  if (leftMotor >= 0 && rightMotor >= 0) {
    LF = leftMotor;
    RF = rightMotor;
    LR, RR = 0;
  }
  else if (leftMotor >= 0 && rightMotor < 0) {
    LF = leftMotor;
    RR = abs(rightMotor);
    LR, RF = 0;
  }
  else if (leftMotor < 0 && rightMotor >= 0) {
    LR = abs(leftMotor);
    RF = rightMotor;
    RR, LF = 0;
  }
  else {
    LR = abs(leftMotor);
    RR = abs(rightMotor);
    LF, RF = 0;
  }

Could be written shorter (and more functional) as

  uint8_t LF = 0, LR = 0, RF = 0, RR = 0;
  if (leftMotor >= 0) {
    LF = leftMotor;
  } else {
    LR = abs(leftMotor);
  }
  if (rightMotor >= 0) {
    RF = rightMotor;
  } else {
    RR = abs(rightMotor);
  }