nRF24L01+ to transmit Joystick position for DC Motor Control

Hi all,

Trying to use nRF24L01 modules to transmit the x/y positions of a joystick to drive 2 DC motors through an L298N driver. (Using 2 UNOs) (Joystick moves in y-direction = both motors forwards/backwards, x-direction = one forwards one backwards).

The code for driving the motors works perfectly fine when the joystick is connected to the same UNO as the motors, however I am having trouble now I have introduced another UNO and the nRF24l01 modules.

When wired up, both motors constantly turn in one direction at full speed, regardless of the position of the joystick on the other UNO.

I have read that a 10µF capacitor across VCC/GND can help, but not sure if it is the code?

Cheers!

Transmitter Code:

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

RF24 radio(7, 8); // CE, CSN
const byte address[6] = "00001";

char xyData[32] = "";
String xAxis, yAxis;

void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.stopListening();
}

void loop() {
  
  xAxis = analogRead(A0); // Read Joysticks X-axis
  yAxis = analogRead(A1); // Read Joysticks Y-axis
  // X value
  xAxis.toCharArray(xyData, 5); // Put the String (X Value) into a character array
  radio.write(&xyData, sizeof(xyData)); // Send the array data (X value) to the other NRF24L01 modile
  // Y value
  yAxis.toCharArray(xyData, 5);
  radio.write(&xyData, sizeof(xyData));
  delay(20);
}

Receiver Code:

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

#define enA 9   
#define in1 3
#define in2 4
#define enB 10   
#define in3 5
#define in4 6

RF24 radio(7, 8); // CE, CSN
const byte address[6] = "00001";

char receivedData[32] = "";
int  xAxis, yAxis;

int motorSpeedA = 0;
int motorSpeedB = 0;

void setup() {
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
}

void loop() {

  if (radio.available()) {   // If the NRF240L01 module received data
    radio.read(&receivedData, sizeof(receivedData)); // Read the data and put it into character array
    xAxis = atoi(&receivedData[0]); // Convert the data from the character array (received X value) into integer
    delay(10);
    radio.read(&receivedData, sizeof(receivedData));
    yAxis = atoi(&receivedData[0]);
    delay(10);
  }
  
  if (yAxis < 470 || yAxis > 550) {

    // Y-axis used for forward and backward control
    if (yAxis < 470) {
      // Set Motor A Backward
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);
      // Set Motor B Backward
      digitalWrite(in3, HIGH);
      digitalWrite(in4, LOW);
      // Convert the declining Y-axis readings for going backward from 470 to 0 into 0 to 255 value for the PWM signal for increasing the motor speed
      motorSpeedA = map(yAxis, 470, 0, 0, 255);
      motorSpeedB = map(yAxis, 470, 0, 0, 255);
    }
    else if (yAxis > 550) {
      // Set Motor A forward
      digitalWrite(in1, LOW);
      digitalWrite(in2, HIGH);
      // Set Motor B forward
      digitalWrite(in3, LOW);
      digitalWrite(in4, HIGH);
      // Convert the increasing Y-axis readings for going forward from 550 to 1023 into 0 to 255 value for the PWM signal for increasing the motor speed
      motorSpeedA = map(yAxis, 550, 1023, 0, 255);
      motorSpeedB = map(yAxis, 550, 1023, 0, 255);
    }
    // If joystick stays in middle the motors are not moving
    else {
      motorSpeedA = 0;
      motorSpeedB = 0;
    }
  }

  else if (yAxis > 470 && yAxis < 550) {

    // X-axis used for left and right control
    if (xAxis < 470) {
      // Set Motor A Backward
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);
      // Set Motor B Forward
      digitalWrite(in3, LOW);
      digitalWrite(in4, HIGH);
      // Convert the declining X-axis readings for going backward from 470 to 0 into 0 to 255 value for the PWM signal for increasing the motor speed
      motorSpeedA = map(xAxis, 470, 0, 0, 255);
      motorSpeedB = map(xAxis, 470, 0, 0, 255);
    }
    else if (xAxis > 550) {
      // Set Motor A forward
      digitalWrite(in1, LOW);
      digitalWrite(in2, HIGH);
      // Set Motor B Backward
      digitalWrite(in3, HIGH);
      digitalWrite(in4, LOW);
      // Convert the increasing X-axis readings for going forward from 550 to 1023 into 0 to 255 value for the PWM signal for increasing the motor speed
      motorSpeedA = map(xAxis, 550, 1023, 0, 255);
      motorSpeedB = map(xAxis, 550, 1023, 0, 255);
    }
    // If joystick stays in middle the motors are not moving
    else {
      motorSpeedA = 0;
      motorSpeedB = 0;
    }
  }
  else {
    motorSpeedA = 0;
    motorSpeedB = 0;
  }


  // Prevent buzzing at low speeds (Adjust according to your motors. My motors couldn't start moving if PWM value was below value of 70)
  if (motorSpeedA < 50) {
    motorSpeedA = 0;
  }
  if (motorSpeedB < 50) {
    motorSpeedB = 0;
  }
  analogWrite(enA, motorSpeedA); // Send PWM signal to motor A
  analogWrite(enB, motorSpeedB); // Send PWM signal to motor B
}

You can do it a lot more simply if you store the joystick values in an array and send the array. For example ...

Create an array (the same for both sending and receiving)

int joyPos[2];
joyPos[0] = analogRead(A0);
joyPos[1] = analogRead(A1);
radio.write(&joyPos, sizeof(joyPos));

and on the receiving side

radio.read(&joyPos, sizeof(joyPos));

which will directly put the two values into the two array elements

If you don't have proper control of the motor I suggest you write a simple program without any wireless and with the joystick and the motors on the same Arduino. Get that working first.

Then get a simple program working that sends data from one Arduino to the other without doing anything else. When the two parts work separately then make the composite program.

...R
Simple nRF24L01+ Tutorial

So I've got proper control without wireless, and now working on getting a basic program for the NRF24L01.

I have copied the example given in the tutorial in your link (as well as other even simpler versions found elsewhere) however I can't get any of them to work.

As I'm using code from examples which 100% works, and I've triple checked the NRF modules are wired up correctly, can I assume that the modules I am using are maybe damaged?

sam6003:
I have copied the example given in the tutorial in your link (as well as other even simpler versions found elsewhere) however I can't get any of them to work.

As I'm using code from examples which 100% works, and I've triple checked the NRF modules are wired up correctly, can I assume that the modules I am using are maybe damaged?

I'm confused.

Your first paragraph says "can't get any of them to work" and your second paragraph says "which 100% works". Which is correct.

If you have one of my examples working then you should be able to extend it to send your own data.

Post the code that YOU have uploaded to both of your Arduinos and say exactly what happens when you try it.

...R

Sorry so I meant "100% works" as in your code has worked for yourself/other people and therefore the code itself is not the problem.

I have tried your example but couldn't get it to work.

The other example I tried was:

Transmitter:

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

RF24 radio(7, 8); // CE, CSN

const byte address[6] = "00001";

void setup() {
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.stopListening();
}

void loop() {
  const char text[] = "Hello World";
  radio.write(&text, sizeof(text));
  delay(1000);
}

Receiver:

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

RF24 radio(7, 8); // CE, CSN

const byte address[6] = "00001";

void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
}

void loop() {
  if (radio.available()) {
    char text[32] = "";
    radio.read(&text, sizeof(text));
    Serial.println(text);
  }
}

In both cases, nothing is displayed on the serial monitor

You need to define the array that is being transmitted as the same size for both Tx and Rx. Try this in the Tx

void loop() {
  const char text[32] = "Hello World";
  radio.write(&text, sizeof(text));
  delay(1000);
}

If that does not work then try one of the examples in my tutorial without any changes. It is much easier to help with code that I am familiar with.

...R

I've just tried the 'simple one way transmission' example from your tutorial without any changes.

I get the "SimpleRx Starting" message in the monitor but then nothing else.

Ive tried using both the ICSP pins and pins 11-13 for MOSI, MISO and SCK connections but get the same result.

Still very new to Arduino so not sure if this makes a difference or not but when wired up, the 'on' light is on, however the 'tx' and 'rx' are both off?

sam6003:
I've just tried the 'simple one way transmission' example from your tutorial without any changes.

I get the "SimpleRx Starting" message in the monitor but then nothing else.

Post the code that YOU have uploaded to your two Arduinos.

You have told us the output from one Arduino - what are you getting from the other one?

As you are using Unos just follow the instructions in my tutorial.

...R

The code I have uploaded to the arduinos is exactly the same as in the tutorial, so for the transmitter:

// SimpleTx - the master or the transmitter

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


#define CE_PIN   9
#define CSN_PIN 10

const byte slaveAddress[5] = {'R','x','A','A','A'};


RF24 radio(CE_PIN, CSN_PIN); // Create a Radio

char dataToSend[10] = "Message 0";
char txNum = '0';


unsigned long currentMillis;
unsigned long prevMillis;
unsigned long txIntervalMillis = 1000; // send once per second


void setup() {

    Serial.begin(9600);

    Serial.println("SimpleTx Starting");

    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.setRetries(3,5); // delay, count
    radio.openWritingPipe(slaveAddress);
}

//====================

void loop() {
    currentMillis = millis();
    if (currentMillis - prevMillis >= txIntervalMillis) {
        send();
        prevMillis = millis();
    }
}

//====================

void send() {

    bool rslt;
    rslt = radio.write( &dataToSend, sizeof(dataToSend) );
        // Always use sizeof() as it gives the size as the number of bytes.
        // For example if dataToSend was an int sizeof() would correctly return 2

    Serial.print("Data Sent ");
    Serial.print(dataToSend);
    if (rslt) {
        Serial.println("  Acknowledge received");
        updateMessage();
    }
    else {
        Serial.println("  Tx failed");
    }
}

//================

void updateMessage() {
        // so you can see that new data is being sent
    txNum += 1;
    if (txNum > '9') {
        txNum = '0';
    }
    dataToSend[8] = txNum;
}

and for the receiver:

// SimpleRx - the slave or the receiver

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

#define CE_PIN   9
#define CSN_PIN 10

const byte thisSlaveAddress[5] = {'R','x','A','A','A'};

RF24 radio(CE_PIN, CSN_PIN);

char dataReceived[10]; // this must match dataToSend in the TX
bool newData = false;

//===========

void setup() {

    Serial.begin(9600);

    Serial.println("SimpleRx Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1, thisSlaveAddress);
    radio.startListening();
}

//=============

void loop() {
    getData();
    showData();
}

//==============

void getData() {
    if ( radio.available() ) {
        radio.read( &dataReceived, sizeof(dataReceived) );
        newData = true;
    }
}

void showData() {
    if (newData == true) {
        Serial.print("Data received ");
        Serial.println(dataReceived);
        newData = false;
    }
}

From the transmitter arduino I am getting:

SimpleTx Starting
Data Sent Message 0 Tx failed

I have followed your instructions word for word, and the instructions from a few other tutorials i found online, however it still doesn't seem to work? Hence why I thought originally it may be the NRF24L01 modules maybe?

sam6003:
I have followed your instructions word for word, and the instructions from a few other tutorials i found online, however it still doesn't seem to work? Hence why I thought originally it may be the NRF24L01 modules maybe?

That does suggest that one or both of the nRF24's is faulty. My programs do work for me and for other Forum members.

Have you tried the connection-check program in Reply #29 in my Tutorial?

Have you swapped the Rx and TX codes so that the roles of the nRF24's are swapped?

Unfortunately wireless problems can be difficult to debug. Having some spare modules is always a good idea.

...R

I've tried swapping the Rx and Tx code, but haven't tried the connection check program.

Will give that a go first, then if it doesn't fix it will have to get some more modules

Cheers for your help!

sam6003:
Will give that a go first, then if it doesn't fix it

The connection check will not test whether the wireless part of the nRF24 works.

...R

Have just done the connection check, this is what I get:

CheckConnection Starting

FIRST WITH THE DEFAULT ADDRESSES after power on
  Note that RF24 does NOT reset when Arduino resets - only when power is removed
  If the numbers are mostly 0x00 or 0xff it means that the Arduino is not
     communicating with the nRF24

STATUS		 = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1	 = 0xe7e7e7e7e7 0x4141417852
RX_ADDR_P2-5	 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR		 = 0xe7e7e7e7e7
RX_PW_P0-6	 = 0x00 0x20 0x00 0x00 0x00 0x00
EN_AA		 = 0x3f
EN_RXADDR	 = 0x03
RF_CH		 = 0x4c
RF_SETUP	 = 0x07
CONFIG		 = 0x0e
DYNPD/FEATURE	 = 0x00 0x00
Data Rate	 = 1MBPS
Model		 = nRF24L01+
CRC Length	 = 16 bits
PA Power	 = PA_MAX


AND NOW WITH ADDRESS AAAxR  0x41 41 41 78 52   ON P1
 and 250KBPS data rate

STATUS		 = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1	 = 0xe7e7e7e7e7 0x4141417852
RX_ADDR_P2-5	 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR		 = 0xe7e7e7e7e7
RX_PW_P0-6	 = 0x00 0x20 0x00 0x00 0x00 0x00
EN_AA		 = 0x3f
EN_RXADDR	 = 0x03
RF_CH		 = 0x4c
RF_SETUP	 = 0x27
CONFIG		 = 0x0e
DYNPD/FEATURE	 = 0x00 0x00
Data Rate	 = 250KBPS
Model		 = nRF24L01+
CRC Length	 = 16 bits
PA Power	 = PA_MAX

Hi,

Can you please post a copy of your circuits, in CAD or a picture of a hand drawn circuit in jpg, png?

What voltage are you powering the nrf units?

Thanks.. Tom.. :slight_smile:

sam6003:
Have just done the connection check, this is what I get:

I think it is working OK but please run the test again and make sure to de-power the Arduino and nRF24 before viewing the test output. Resetting the Arduino does not reset the nRF24.

...R

TomGeorge:
Can you please post a copy of your circuits, in CAD or a picture of a hand drawn circuit in jpg, png?

What voltage are you powering the nrf units?

Excuse the poor drawing, circuit is attached.

To power the units I've tried two different 11.1V battery packs, USB from my laptop, and USB from a portable phone charger.

Robin2:
I think it is working OK but please run the test again and make sure to de-power the Arduino and nRF24 before viewing the test output. Resetting the Arduino does not reset the nRF24.

Assume unplugging the usb cable and plugging back in again classes as de-powering the Arduino? if so then I've done this and the test output stays the same

Image from Reply #15 so we don't have to download it. See this Simple Image Guide

...R

You don't have a 10µF capacitor across Vcc and GND for the nRF24 - that can be essential in some cases.

It may also be worth testing by powering the nRF24 from a pair of AA alkaline cells (3v) with the GND connected to the Arduino GND. Sometimes the Arduino board cannot provide enough 3.3v power.

...R

Robin2:
You don't have a 10µF capacitor across Vcc and GND for the nRF24 - that can be essential in some cases.

How would I go about wiring that up? solder the capacitor to the 'top' of the NRF modules and then use jumper wires as normal to connect VCC to 3.3V and GND to GND?

And which capacitor would you recommend? I've had a look at past forum posts and tantalum and electrolytic are mentioned frequently?

I just use cheap electrolytic capacitors.

If you are connecting to the nRf24 with dupont jumper wires then you could use a solderless breadboard to provide extra contacts for the capacitor. Some of the caps have very thin wire so you may be able to push the legs into an Arduino socket alongside a dupont connector.

And, yes, of course you could solder it. You could solder it to the back of the nRF24 board thus leaving the pins free.

...R