Receiving Wrong Walue with nRF24 Transceiver

Hello there,

I have been working on a tracked robot for several weeks now and it has been going fairly well until today.

I am using a pair of nRF24 transceivers (with capacitors) and a joystick for remote control. The joystick is wired to a Nano while the robot is managed by an Uno and a L298N motor controller.

Today I decided to make a mount for my controller as up until this point it has just been a loose board and joystick. After screwing the board down and plugging the battery back in, I noticed my robot was behaving strangely and spinning in place. This is a feature of my code but is only supposed to happen when the joystick is deflected directly right or left, in this case it was in the neutral position. I have reviewed my code and cannot find anything I might have accidentally changed, such as adding a character somewhere and it being wrong but still compiling (it can happen I guess?). I also did not unplug any of the wires and I know it was wired and working correctly last time I used it.

When I checked the serial monitor, the transmitter was outputting expected values but my receiver was reading in the y-axis ~ +67.

Below are my transmitter and receiver code as well as their respective serial outputs.

Robot_Tx.ino

/**
 * August 11, 2020
 * Battle Bot Radio Reciever
 * Gareth Koch
 * 
 * nRF24 Wiring
 * GND  -----  GND
 * VCC  ----- 3.3V
 * CE   -----    8
 * CSN  -----    9
 * SCK  -----   13
 * MOSI -----   11
 * MISO -----   12
 * 
 * Joystick Wiring
 * GND  -----  GND
 * VCC  -----  +5V
 * VRX  -----   A0
 * VRY  -----   A1
 */

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

const byte address[6] = {'T', 'A', 'L', 'E', 'K', 'K'};

// Create radio and set CE and CSE pins to 8 and 9 respectively
RF24 radio(8, 9);

struct Joystick
{
  byte x;
  byte y;
};

// Variable of above struct
Joystick joystick;

void setup()
{
  Serial.begin(9600);
  
  // Start radio
  radio.begin();
  Serial.println("Radio begin");
  // Set data rate
  radio.setDataRate(RF24_250KBPS);
  Serial.println("Data rate: 250kbps");
  // Set address
  radio.openWritingPipe(address);
  Serial.print("Address set");

  // Set channel values to "middle" of 0-255
  joystick.x = 127;
  joystick.y = 127;
}

void loop()
{
  joystick.x = map (analogRead(A0), 0, 1023, 0, 255);
  joystick.y = map (analogRead(A1), 0, 1023, 0, 255);

  radio.write(&joystick, sizeof(Joystick));
  Serial.print("x: ");
  Serial.print(joystick.x);
  Serial.print(" y: ");
  Serial.print(joystick.y);
  Serial.print(" A0: ");
  Serial.print(analogRead(A0));
  Serial.print(" A1: ");
  Serial.println(analogRead(A1));
}

Tx Serial
18:52:37.000 → A0: 509 x: 126 A1: 529 y: 132
18:52:37.033 → A0: 509 x: 126 A1: 530 y: 132

Robot_Rx.ino

/**
   August 15, 2020
   Battle Bot Radio Reciever
   Gareth Koch

   nRF24 Wiring
   GND  -----  GND
   VCC  ----- 3.3V
   CE   -----    8
   CSN  -----    9
   SCK  -----   13
   MOSI -----   11
   MISO -----   12

   L298N Wiring
   +12V -----   9V
   GND  -----  GND
   +5V  -----  +5V
   ENA  -----   10
   IN1  -----    7
   IN2  -----    6
   IN3  -----    5
   IN4  -----    4
   ENB  -----    3

*/

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

// Define left motor pins
#define Len 10
#define L1 6
#define L2 7

// Define right motor pins
#define Ren 3
#define R1 4
#define R2 5

// Set address for radio
// This must be the same for both the transmitter and receiver
const byte address[6] = {'T', 'A', 'L', 'E', 'K', 'K'};

// Create radio and set CE and CSE pins to 8 and 9 respectively
RF24 radio(8, 9);

// Joystick data format to be read
struct Joystick
{
  byte x;
  byte y;
};
// Variable of above struct
Joystick joystick;

// Check if a joystick axis is in the neutral position
bool isCentered(int value) {
  return (value > 120 && value < 135);
}

void setup()
{
  Serial.begin(9600);

  //Start radio
  radio.begin();
  Serial.println("Radio begin");
  // Set data rate
  radio.setDataRate(RF24_250KBPS);
  Serial.println("Data rate: 250kbps");
  // Set address
  radio.openReadingPipe(1, address);
  Serial.println("Address set");
  // Set radio to be receiver
  radio.startListening();

  // Set channel values to "middle" of 0-255
  joystick.x = 127;
  joystick.y = 127;

  // Set pinouts for motor controller
  pinMode(L1, OUTPUT);
  pinMode(L2, OUTPUT);
  pinMode(Len, OUTPUT);
  pinMode(R1, OUTPUT);
  pinMode(R2, OUTPUT);
  pinMode(Ren, OUTPUT);
}

void loop() {
  while (radio.available()) {
    // Read joystick data
    radio.read(&joystick, sizeof(Joystick));

    /*
      // Test data received
      x_value = joystick.x;
      y_value = joystick.y;
      Serial.print("x: ");
      Serial.print(x_value);
      Serial.print(" y: ");
      Serial.println(y_value);
    */

    // Actually move
    control(joystick.x, joystick.y);
  }
}


void control (int x, int y) {
  // Define forward velocity in terms of x axis
  int fwSpeed = map(x, 0, 255, -255, 255);
  // Define left and right motor velocity in terms of forward velocity
  int lSpeed = fwSpeed;
  int rSpeed = fwSpeed;

  // If joystick is in neutral position, do not move
  if (isCentered(x) && isCentered(y)) {
    lSpeed = 0;
    rSpeed = 0;
  // Turn in place if no forward velocity
  } else if (isCentered(x)) {
    lSpeed = map(y, 0, 255, 255, -255);
    rSpeed = - lSpeed;
  // Scale forward velocity of right and left motors relative to y axis
  } else {
    if (y < 120) {
      // left turn
      rSpeed = fwSpeed - map(y, 135, 255, 0, fwSpeed);
    }
    else if (y > 135) {
      lSpeed = fwSpeed - map(y, 0, 120, fwSpeed, 0);
    }
  }
  
  // Test motor input/output
  Serial.print("x: ");
  Serial.print(x);
  Serial.print(" ");
  Serial.print("y: ");
  Serial.print(y);
  Serial.print(" ");
  Serial.print("L: ");
  Serial.print(lSpeed);
  Serial.print(" ");
  Serial.print("R: ");
  Serial.println(rSpeed);
  
  // Process final "speed" values to movement
  trackMove(lSpeed, rSpeed);
}

void trackMove(int lSpe, int rSpe) {
  if (lSpe > 8) {
    // Move forward
    digitalWrite(L1, HIGH);
    digitalWrite(L2, LOW);
    analogWrite(Len, lSpe);
  } else if (lSpe < -8) {
    // Move backwards
    digitalWrite(L1, LOW);
    digitalWrite(L2, HIGH);
    analogWrite(Len, -lSpe);
  } else {
    digitalWrite(L1, LOW);
    digitalWrite(L2, LOW);
    analogWrite(Len, 0);
  }

  if (rSpe > 8) {
    // Move forward
    digitalWrite(R1, HIGH);
    digitalWrite(R2, LOW);
    analogWrite(Ren, rSpe);
  } else if (rSpe < -8) {
    // Move backwards
    digitalWrite(R1, LOW);
    digitalWrite(R2, HIGH);
    analogWrite(Ren, -rSpe);
  } else {
    digitalWrite(R1, LOW);
    digitalWrite(R2, LOW);
    analogWrite(Ren, 0);
  }
}

void halt() {
  // Stop
  digitalWrite(L1, LOW);
  digitalWrite(L2, LOW);
  analogWrite(Len, 0);
  digitalWrite(R1, LOW);
  digitalWrite(R2, LOW);
  analogWrite(Ren, 0);
}

Rx Serial
18:52:37.018 → x: 127 y: 198 L: -141 R: 141
18:52:37.053 → x: 127 y: 198 L: -141 R: 141

Any insight into potential causes or solutions would be greatly appreciated.

Thank you for your time.

Am I missing soemthing ? In the TX you are reading the x and y values and printing them out BUT you never assign them to the structure's x and y so they never get sent!

The TX code you posted could not possibly produce the output shown. Please post the correct code.

Apologies, I had reformatted my serials so make the relevant values beside each other. The only difference was the order of the serial.prints but here’s the most recent code with the same behaviour still happening.

/**
   August 11, 2020
   Battle Bot Radio Reciever
   Gareth Koch

   nRF24 Wiring
   GND  -----  GND
   VCC  ----- 3.3V
   CE   -----    8
   CSN  -----    9
   SCK  -----   13
   MOSI -----   11
   MISO -----   12

   Joystick Wiring
   GND  -----  GND
   VCC  -----  +5V
   VRX  -----   A0
   VRY  -----   A1
*/

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

const byte address[6] = {'T', 'A', 'L', 'E', 'K', 'K'};

// Create radio and set CE and CSE pins to 8 and 9 respectively
RF24 radio(8, 9);

struct Joystick
{
  byte x;
  byte y;
};

// Variable of above struct
Joystick joystick;

void setup()
{
  Serial.begin(9600);

  // Start radio
  radio.begin();
  Serial.println("Radio begin");
  // Set data rate
  radio.setDataRate(RF24_250KBPS);
  Serial.println("Data rate: 250kbps");
  // Set address
  radio.openWritingPipe(address);
  Serial.print("Address set");

  // Set channel values to "middle" of 0-255
  joystick.x = 127;
  joystick.y = 127;
}

void loop()
{
  joystick.x = map (analogRead(A0), 0, 1023, 0, 255);
  joystick.y = map (analogRead(A1), 0, 1023, 0, 255);

  radio.write(&joystick, sizeof(Joystick));
  Serial.print("A0: ");
  Serial.print(analogRead(A0));
  Serial.print(" x: ");
  Serial.print(joystick.x);
  Serial.print(" A1: ");
  Serial.print(analogRead(A1));
  Serial.print(" y: ");
  Serial.println(joystick.y);

}

I have 2 Unos with rf24 attached and and one of them has a joystick. I loaded your code and got the following in the receiver serial monitor. The values follow the joystick and so I conclude that the code works and the radios are talking.

x: 124 y: 255 L: -255 R: 255
x: 147 y: 0 L: 39 R: 82
x: 143 y: 0 L: 31 R: 65
x: 146 y: 0 L: 37 R: 78
x: 125 y: 255 L: -255 R: 255
x: 150 y: 0 L: 45 R: 95
x: 255 y: 24 L: 255 R: 490
x: 190 y: 178 L: 185 R: 125
x: 0 y: 101 L: -255 R: -327
x: 242 y: 95 L: 229 R: 305
x: 149 y: 29 L: 43 R: 80
x: 142 y: 163 L: 39 R: 29
x: 130 y: 101 L: 53 R: -53

You are sending data way too fast. Serial print may have a hard time keeping up. Slow the sending of data down some.

The results of some of the map functions are suspect to me. Maybe constrain the mapped values.

skyvan:
Am I missing soemthing ? In the TX you are reading the x and y values and printing them out BUT you never assign them to the structure's x and y so they never get sent!

I am assigning the values read by the analog inputs at the top of the void loop and then sending them.

void loop()
{
  joystick.x = map (analogRead(A0), 0, 1023, 0, 255);
  joystick.y = map (analogRead(A1), 0, 1023, 0, 255);

  radio.write(&joystick, sizeof(Joystick));
  Serial.print("A0: ");
  Serial.print(analogRead(A0));
  Serial.print(" x: ");
  Serial.print(joystick.x);
  Serial.print(" A1: ");
  Serial.print(analogRead(A1));
  Serial.print(" y: ");
  Serial.println(joystick.y);

}

It should be sufficient to send values 5 times per second, or 10 times at most.

...R
Simple nRF24L01+ Tutorial

Robin2:
It should be sufficient to send values 5 times per second, or 10 times at most.

…R
Simple nRF24L01+ Tutorial

Sorry, I don’t know much about how radios work yet. Would sending data too quickly be causing my y axis values to be changing in this manner? I have been using this transfer rate for a week and everything was working as intended.

talekk:
Sorry, I don't know much about how radios work yet. Would sending data too quickly be causing my y axis values to be changing in this manner? I have been using this transfer rate for a week and everything was working as intended.

I have never experimented to see how often data could be sent - my general approach is to send as infrequently as necessary so as not to jam up the airwaves that other people might wish to use.

On the Arduino printing too often will fill up the Serial Output Buffer and cause the Arduino to pause until it empties.

...R

Hello again,

After adjusting the data rate the issue was still persisting. It seems the issue wasn't a software one after all. I bought another radio and swapped it out with the receiver on my robot and everything began working as intended again. I'm not entirely sure what caused the malfunction with the antenna but, as they were shipped in protective bags, I suspect a static discharge damaged it.

Thank you to everyone to tried to help.