nRF24L01 read joystick data and broadcast to 2 other nRF24L01 connection lost

EDIT: major edit on the post.
I was trying to make a network A → B ->C unidirectional.

After I got Robin2 code I realized I could make a A <-> B,C bidirectional network.

So what I am trying to do now is get radio A to broadcast an analog data to B and C simultaneously so B and C control a servo/motor. So latency is critical here.
after I was able to get this working I am having a new problem: suddenly the motor goes full throttle and I need to restart the ESC and the arduino.

I’m using an arduino Nano chinese clone and a nRF24L01 on each node. in B and C arduino is powered by the ESC 5V port and on the A it’s powered by a 2S lipo.

Usually I’ve seen RC cars going out of control like that when the battery levels are low and they would lose connection to the radio, but it’s happening with all bateries charged.

slave code

// HandController - the slave or the receiver

    // http://tmrh20.github.io/RF24/

    //~ - CONNECTIONS: nRF24L01 Modules See:
    //~ http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
    //~ 1 - GND
    //~ 2 - VCC 3.3V !!! NOT 5V
    //~ 3 - CE to Arduino pin 9
    //~ 4 - CSN to Arduino pin 10
    //~ 5 - SCK to Arduino pin 13
    //~ 6 - MOSI to Arduino pin 11
    //~ 7 - MISO to Arduino pin 12
    //~ 8 - UNUSED

#include <SPI.h>
//~ #include <TMRh20nRF24L01.h>
//~ #include <TMRh20RF24.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>
#define CE_PIN   9
#define CSN_PIN 10

Servo myservo;  // create servo object to control a servo 

// NOTE: the "LL" at the end of the constant is "LongLong" type

const uint64_t   deviceID = 0xE8E8F0F0E1LL; // Define the ID for this slave

int valChange = 1;
int val;
int average;
int xAxis;
int yAxis;
int val3 = 90;
int contador = 0;

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

int dataReceived[2];
int ackData[2] = {12,23};
boolean rad = false;

void setup() {
    myservo.attach(8);
    Serial.begin(9600);
    delay(1000);
    Serial.println("Receiver 1 Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1,deviceID);
    radio.enableAckPayload();
    radio.writeAckPayload(1, ackData, sizeof(ackData));
    radio.startListening();
}

void loop() {
  if ( radio.available() ) {
        radio.read( dataReceived, sizeof(dataReceived) );
        delay(1);
        xAxis = dataReceived[0];
        yAxis = dataReceived[1];
        radio.writeAckPayload(1, ackData, sizeof(ackData));
        ackData[0] += valChange; // this just increments so you can see that new data is being sent
        Serial.print("X axis= ");
        Serial.print(dataReceived[0]);
        Serial.print(" Y axis= ");
        Serial.print(dataReceived[1]);
        val = map(xAxis, 1023, 0, 0, 179);
        val3 = map(val,90,179,90,105);
        myservo.write(val3);
        Serial.print(" - ");
        Serial.println (val3);  
        contador = (0);  
  }
  
   else {
    contador = (contador +1);
    delay(1);
  }
   
  if (contador > 300) {
    myservo.write(90);
    Serial.println("sem sinal");
    Serial.println("sem sinal");
    Serial.println("sem sinal");
    Serial.println("sem sinal");
    Serial.println("sem sinal");
    contador = (0);
    delay(1);
  }
}

transmitter code

// TrackControl - the master or the transmitter

 // http://tmrh20.github.io/RF24/

 //~ - CONNECTIONS: nRF24L01 Modules See:
 //~ http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
 //~ 1 - GND
 //~ 2 - VCC 3.3V !!! NOT 5V
 //~ 3 - CE to Arduino pin 9
 //~ 4 - CSN to Arduino pin 10
 //~ 5 - SCK to Arduino pin 13
 //~ 6 - MOSI to Arduino pin 11
 //~ 7 - MISO to Arduino pin 12
 //~ 8 - UNUSED

#include <SPI.h>
//~ #include <TMRh20nRF24L01.h>
//~ #include <TMRh20RF24.h>
#include <nRF24L01.h>
#include <RF24.h>


#define CE_PIN   9
#define CSN_PIN 10
#define JOYSTICK_X A0
#define JOYSTICK_Y A1

// NOTE: the "LL" at the end of the constant is "LongLong" type
// These are the IDs of each of the slaves
const uint64_t slaveID[2] = {0xE8E8F0F0E1LL, 0xE8E8F0F0E2LL} ;

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

int dataToSend[2];
int joystick[2];
int ackMessg[6];
byte ackMessgLen = 4; // NB this 4 is the number of bytes in the 2 ints that will be recieved

void setup() {

    Serial.begin(9600);
    Serial.println("Track Control Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.enableAckPayload();
    radio.setRetries(3,5); // delay, count
}

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

void loop() {
  
  joystick[0] = analogRead(JOYSTICK_X);
  joystick[1] = analogRead(JOYSTICK_Y);

    radio.openWritingPipe(slaveID[0]); // calls the first slave
                                       
    bool rslt;
    rslt = radio.write( joystick, sizeof(joystick) );
    if ( radio.isAckPayloadAvailable() ) {
        radio.read(ackMessg,ackMessgLen);
        Serial.print("Acknowledge received: ");
        Serial.print(ackMessg[0]);
        Serial.print("  ");
        Serial.println(ackMessg[1]);
    }


   delay(1);

    radio.openWritingPipe(slaveID[1]); // calls the second slave
    bool rslt2;
    rslt2 = radio.write( joystick, sizeof(joystick) );
    if ( radio.isAckPayloadAvailable() ) {
        radio.read(ackMessg,ackMessgLen);
        Serial.print("Acknowledge received: ");
        Serial.print(ackMessg[0]);
        Serial.print("  ");
        Serial.println(ackMessg[1]);
    }
                                       
   delay(1);

    Serial.print("\nRSLT 1 (1 = success) ");
    Serial.print(rslt);
    Serial.print("RSLT 2 (1 = success) ");
    Serial.print(rslt2);
    Serial.print("X axis= ");
    Serial.print(joystick[0]);
    Serial.print("Y axis=  ");
    Serial.println(joystick[1]);
   
 }

I know it’s messy, but it kinda work most of the time.

PPM_in_example.ino (2.38 KB)

tx_example.ino (2.58 KB)

Controle_remoto_gtb2_com_arduino_e_nrf24.ino (1.94 KB)

Ryuudan:
the examples work fine by themselves, but as soon as i try to put they together and read the PPM and re-transmit it through the nrf24 the code doesnt work and I cant find why.

What, exactly, do you mean by "the code doesn't work"?
Which of your sketches runs on Arduino B and which runs on Arduino C?

I can't think of any reason why you could not use an nRF24 on A and have the transmission simultaneously acted on by B and C.

Post the code that you tried.

You could also arrange for A to poll B and C at frequent intervals (say 10 times per second) if it is necessary for B and C to send data back to A. In this context the pair of programs in this link may be useful.

...R

Thx for the replies.

I could not find how to use 1 rf24 to send data to 2 rf24 in a broadcast way.

from your code Robin2 I understood that you have to make a loop with a FOR and open writing pipe for every receiver you have one at a time.

So you cannot broadcast at the same time, but you can very rapidly keep changing to whom you send the data.

so would it be something like this?

read analog input
open writing pipe to 1 and send
close writing pipe
open writing pipe to 2 and send
close writing pipe

is it that simple? I’m going to test it. I lost months looking for this solution. Hope it works.

ok, So I got Robin2 code and adapted it a little bit to my specific application.

now What it does is:
it reads the analog input from the joystick, sends it to one RF24, read the ack, then proceeds to send the same data to the second RF24, reads the ack and repeats.

the slave keeps on reading, gets the data, writes it to the servo/motor and if it loses connection for more than 300 cycles (300ms) it writes neutral position to the servo/motor so it doesnt go out of control

Problems I’m having now:
slave listen one time and report no signal around 5-6 times, so it’s hard to make a condition based on radio.available. That’s why I put the counter, so if it reports no signal for more than 300 consecutive times it stops the motor. Even then my motor is losing control randomly and I have to restart it manually.

I can’t understand why the motor are randomly going out of control and accelerating max. They just suddenly go full throttle.

slave code

// HandController - the slave or the receiver

    // http://tmrh20.github.io/RF24/

    //~ - CONNECTIONS: nRF24L01 Modules See:
    //~ http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
    //~ 1 - GND
    //~ 2 - VCC 3.3V !!! NOT 5V
    //~ 3 - CE to Arduino pin 9
    //~ 4 - CSN to Arduino pin 10
    //~ 5 - SCK to Arduino pin 13
    //~ 6 - MOSI to Arduino pin 11
    //~ 7 - MISO to Arduino pin 12
    //~ 8 - UNUSED

#include <SPI.h>
//~ #include <TMRh20nRF24L01.h>
//~ #include <TMRh20RF24.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>
#define CE_PIN   9
#define CSN_PIN 10

Servo myservo;  // create servo object to control a servo 

// NOTE: the "LL" at the end of the constant is "LongLong" type

const uint64_t   deviceID = 0xE8E8F0F0E1LL; // Define the ID for this slave

int valChange = 1;
int val;
int average;
int xAxis;
int yAxis;
int val3 = 90;
int contador = 0;

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

int dataReceived[2];
int ackData[2] = {12,23};
boolean rad = false;

void setup() {
    myservo.attach(8);
    Serial.begin(9600);
    delay(1000);
    Serial.println("Receiver 1 Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.openReadingPipe(1,deviceID);
    radio.enableAckPayload();
    radio.writeAckPayload(1, ackData, sizeof(ackData));
    radio.startListening();
}

void loop() {
  if ( radio.available() ) {
        radio.read( dataReceived, sizeof(dataReceived) );
        delay(1);
        xAxis = dataReceived[0];
        yAxis = dataReceived[1];
        radio.writeAckPayload(1, ackData, sizeof(ackData));
        ackData[0] += valChange; // this just increments so you can see that new data is being sent
        Serial.print("X axis= ");
        Serial.print(dataReceived[0]);
        Serial.print(" Y axis= ");
        Serial.print(dataReceived[1]);
        val = map(xAxis, 1023, 0, 0, 179);
        val3 = map(val,90,179,90,105);
        myservo.write(val3);
        Serial.print(" - ");
        Serial.println (val3);  
        contador = (0);  
  }
  
   else {
    contador = (contador +1);
    delay(1);
  }
   
  if (contador > 300) {
    myservo.write(90);
    Serial.println("sem sinal");
    Serial.println("sem sinal");
    Serial.println("sem sinal");
    Serial.println("sem sinal");
    Serial.println("sem sinal");
    contador = (0);
    delay(1);
  }
}

transmitter code

// TrackControl - the master or the transmitter

 // http://tmrh20.github.io/RF24/

 //~ - CONNECTIONS: nRF24L01 Modules See:
 //~ http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
 //~ 1 - GND
 //~ 2 - VCC 3.3V !!! NOT 5V
 //~ 3 - CE to Arduino pin 9
 //~ 4 - CSN to Arduino pin 10
 //~ 5 - SCK to Arduino pin 13
 //~ 6 - MOSI to Arduino pin 11
 //~ 7 - MISO to Arduino pin 12
 //~ 8 - UNUSED

#include <SPI.h>
//~ #include <TMRh20nRF24L01.h>
//~ #include <TMRh20RF24.h>
#include <nRF24L01.h>
#include <RF24.h>


#define CE_PIN   9
#define CSN_PIN 10
#define JOYSTICK_X A0
#define JOYSTICK_Y A1

// NOTE: the "LL" at the end of the constant is "LongLong" type
// These are the IDs of each of the slaves
const uint64_t slaveID[2] = {0xE8E8F0F0E1LL, 0xE8E8F0F0E2LL} ;

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

int dataToSend[2];
int joystick[2];
int ackMessg[6];
byte ackMessgLen = 4; // NB this 4 is the number of bytes in the 2 ints that will be recieved

void setup() {

    Serial.begin(9600);
    Serial.println("Track Control Starting");
    radio.begin();
    radio.setDataRate( RF24_250KBPS );
    radio.enableAckPayload();
    radio.setRetries(3,5); // delay, count
}

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

void loop() {
  
  joystick[0] = analogRead(JOYSTICK_X);
  joystick[1] = analogRead(JOYSTICK_Y);

    radio.openWritingPipe(slaveID[0]); // calls the first slave
                                       
    bool rslt;
    rslt = radio.write( joystick, sizeof(joystick) );
    if ( radio.isAckPayloadAvailable() ) {
        radio.read(ackMessg,ackMessgLen);
        Serial.print("Acknowledge received: ");
        Serial.print(ackMessg[0]);
        Serial.print("  ");
        Serial.println(ackMessg[1]);
    }


   delay(1);

    radio.openWritingPipe(slaveID[1]); // calls the second slave
    bool rslt2;
    rslt2 = radio.write( joystick, sizeof(joystick) );
    if ( radio.isAckPayloadAvailable() ) {
        radio.read(ackMessg,ackMessgLen);
        Serial.print("Acknowledge received: ");
        Serial.print(ackMessg[0]);
        Serial.print("  ");
        Serial.println(ackMessg[1]);
    }
                                       
   delay(1);

    Serial.print("\nRSLT 1 (1 = success) ");
    Serial.print(rslt);
    Serial.print("RSLT 2 (1 = success) ");
    Serial.print(rslt2);
    Serial.print("X axis= ");
    Serial.print(joystick[0]);
    Serial.print("Y axis=  ");
    Serial.println(joystick[1]);
   
 }

I know it’s messy, but it kinda work most of the time.

TX_-_controle_remoto_wireless_1-2.ino (2.38 KB)

RX_1_controle_remoto_wireless_1-2.ino (2.32 KB)

You seem to have taken out the code in my demo that limits the frequency of transmissions - I suggest you reinstate that. In my own project (using similar code) I have code to shut down the motor if it misses 10 messages - i.e. after about 1 second.

Wireless projects can be very difficult to debug. What happens if you only have one receiver powered up? Do both of them work properly one at a time?

I presume your two receiver programs have been given different addresses? (You have only posted 1 receiver program so I cannot check).

If the system does not work reliably with a single slave then you need to concentrate on getting that working before adding the complexity of two slaves.

Have you got 10µF capacitors across Vcc and GND for the nRF24L01+ boards?

…R

Robin2:
You seem to have taken out the code in my demo that limits the frequency of transmissions - I suggest you reinstate that. In my own project (using similar code) I have code to shut down the motor if it misses 10 messages - i.e. after about 1 second.

what do you mean reinstate?
I can't wait a full second to shut down, I was hoping to reset, but even manual reseting the slave or even unplugging it from the motor, the motor still doesnt stop until I reset the ESC.

Robin2:
Wireless projects can be very difficult to debug. What happens if you only have one receiver powered up? Do both of them work properly one at a time?

Bench testing them led to no failures. One motor or both at the same time. It just happens in real-world conditions.
I can't test with only one in real-world conditions, but I will follow your suggestion and try it.
but when I was using the arduino wired to both motors they would work 100% perfect all the time. Never had this problem.

Robin2:
I presume your two receiver programs have been given different addresses? (You have only posted 1 receiver program so I cannot check).

yes.

Robin2:
If the system does not work reliably with a single slave then you need to concentrate on getting that working before adding the complexity of two slaves.

I had a remote using 2 arduinos and 2 nrf24 on the controller and 1 set in each motor. so they worked like 2 1-to-1 radios and they worked fine, but sometimes I would get lag and interference. Also like I said before, wired they work perfect. What I can't get is why the ESC is locking in full throttle and stays locked even after turning off and back on the transmitter. The code writes neutral after 300ms and even then the ESC just doesnt listen anymore to the arduino. It happens randomly and in both motors, although it seemed to happen more often with the motor that was further away from the controller.

Maybe I should just test with different ESC. who knows? might work.

Robin2:
Have you got 10µF capacitors across Vcc and GND for the nRF24L01+ boards?

yes. it was working before with 1 to 1 radio.

Ryuudan:
what do you mean reinstate?
I can't wait a full second to shut down, I was hoping to reset, but even manual reseting the slave or even unplugging it from the motor, the motor still doesnt stop until I reset the ESC.

You seem to have two different things mixed up here.

The line I have coloured blue simply means put back in the code that you took out so that there is a respectable interval between transmissions.

If you can't wait 1 second, how long can you wait?
And, perhaps more importantly, WHY can't you wait one second? (I ask that because I wonder if you have unreasonable expectations).

I don't understand your other comments - your descriptions are not clear enough. For example I have no idea what you tried for "bench testing".

If this was my problem I would follow these steps...

  • Get the master Arduino/nRF24 working with Arduino B on its own
  • Get the master Arduino/nRF24 working with Arduino C on its own (The address for C being different from B)
  • Get the master woking with both B and C.

To my mind that is the only way to identify where the problem is.

...R

Robin2:
If you can't wait 1 second, how long can you wait?
And, perhaps more importantly, WHY can't you wait one second? (I ask that because I wonder if you have unreasonable expectations).

ideally around 5ms between transmissions. Since this is controlling motors at 40km/h 1 second means crashing(possibly death, or at least injuries XD)
if I have to wait more than 200ms between transmissions it gets too noticeable, so maybe I could try 100ms.

Robin2:
I don't understand your other comments - your descriptions are not clear enough. For example I have no idea what you tried for "bench testing".

bench testing is where you put your device on the bench and test it. For me it means that you lift the wheels out of the ground so they spin freely, so if anything goes wrong theres no crash. When I did this testing I could not have the same problem, it only happened while riding.

Robin2:
If this was my problem I would follow these steps...

  • Get the master Arduino/nRF24 working with Arduino B on its own
  • Get the master Arduino/nRF24 working with Arduino C on its own (The address for C being different from B)
  • Get the master woking with both B and C.

To my mind that is the only way to identify where the problem is.

...R

yep, I guess I can try that again as that's exactly what I did. Well, if I can figure out WHAT is causing the ESC to lock in full throttle would be an advance.

Even with some problems that was the FIRST time I could get 1 nrf24 to talk to 2 nrf24 in a broadcast-like way. I still would rather have them transmit simultaneously though. i will keep on trying to find out.

Thanks again Robin2 for your help.

Ryuudan:
ideally around 5ms between transmissions. Since this is controlling motors at 40km/h 1 second means crashing(possibly death, or at least injuries XD)

I suspected something like that.

If there are risks of serious injury what you are trying to do is completely inappropriate, and, to be honest, you should be getting professional advice and not relying on free advice from us amateurs.

In my amateur opinion, no matter what wireless system you are using, you will need to have a sufficiently sophisticated onboard-vehicle system that it can operate safely without signals for a few seconds - I suggest 10 seconds to give a comfortable margin for error.

The ideal would be a system that only needs a wireless message at the start of a journey :slight_smile:

...R