nRF24L01 Sending RC Boat Hydrodynamic Motion Data

I currently have a few modules that read motion data and motor input on an RC boat. I am using it to create a neural network in python that will predict motion given a motor input and eventually produce its' own input. The only issue I am running into is that I cannot get my nRF24L01 Transceiver modules to transmit or receive data. I have tried a multitude of simple tutorials that have yielded no results and am at my wits end. The code I am attaching is the one that got the closest but still nothing. Yes, I have checked the wiring many times and tried multiple transceivers. Right now, the only possible issue I know about it the capacitor I have arcs between vcc and gnd is from a motor capacitor kit, but everywhere I read tells me to use an electrolytic capacitor; which I have ordered and will be here in two days. The problem is that I need to collect data before then... If you have suggestions on what to do with the modules or have other ideas for data transmission, I am open to anything I can get my hands on within the next few days.

Receiver:

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

// Defines CE and CSN PINs.
#define CE_PIN  9
#define CSN_PIN 10

// Address through which two modules communicate.
const byte Pipe_Address[6] = "00001";

// Variables to hold the data to be received.
// this must match "dataToSend" in the sender.
char dataReceived[32] = ""; 

// Variables to detect new incoming data.
bool newData = false;

// Create an RF24 object as a radio, while also setting the CE and CSN PINs.
RF24 radio(CE_PIN, CSN_PIN);

//________________________________________________________________________________VOID SETUP()
void setup() {
  // put your setup code here, to run once:
  
  Serial.begin(115200);
  Serial.println();
  delay(2000);

  Serial.println("This is the Receiver.");

  // initialize the radio object.
  radio.begin();

  // set the Power Amplifier level.
  // Use "RF24_PA_MIN" or "RF24_PA_LOW" if the distance between nRF24L01 modules is close to each other.
  // Use "RF24_PA_HIGH" or "RF24_PA_MAX" if the distance between nRF24L01 modules is far from each other.
  // For more details, see here : https://github.com/nRF24/RF24/blob/master/RF24.h#L26C1-L26C1
  radio.setPALevel(RF24_PA_LOW);

  // Set the transmission datarate.
  radio.setDataRate(RF24_250KBPS);

  // Set the address to receive data from the sender. The sender must use the same address.
  radio.openReadingPipe(0, Pipe_Address);

  // Set the nRF24L01 module as the receiver.
  radio.startListening();
}
//________________________________________________________________________________

//________________________________________________________________________________VOID LOOP()
void loop() {
  // put your main code here, to run repeatedly:

  // Calling the receive_Data() subroutine.
  receive_Data();

  // Calling the show_Data() subroutine.
  show_Data();
}
//________________________________________________________________________________

//________________________________________________________________________________receive_Data()
// Subroutine for receiving data.
void receive_Data() {
  if (radio.available()) {
    radio.read(&dataReceived, sizeof(dataReceived));
    newData = true;
  }
}
//________________________________________________________________________________

//________________________________________________________________________________show_Data()
// Subroutine for printing the received data to the serial monitor (serial communication).
void show_Data() {
  if (newData == true) {
    Serial.print("Data received : ");
    Serial.println(dataReceived);
    newData = false;
  }
}

Transmitter:

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

// Defines CE and CSN PINs.
#define CE_PIN  9
#define CSN_PIN 10

// Address through which two modules communicate.
const byte Pipe_Address[6] = "00001";

// Variable for the data sending timer.
unsigned long previousMillis = 0;
unsigned long sendIntervalMillis = 1000; // Interval of sending data (1000 ms = 1 second).

// Variables to hold the data to be sent.
// The maximum data length that can be transmitted by the nRF24L01 module is 32 bytes.
char dataToSend[32] = "";

byte count = 0;

// Create an RF24 object as a radio, while also setting the CE and CSN PINs.
RF24 radio(CE_PIN, CSN_PIN); // CE, CSN

//________________________________________________________________________________VOID SETUP()
void setup() {
  // put your setup code here, to run once:
  
  Serial.begin(115200);
  Serial.println();
  delay(2000);

  Serial.println("This is the Sender.");

  // initialize the radio object.
  radio.begin();

  // set the Power Amplifier level.
  // Use "RF24_PA_MIN" or "RF24_PA_LOW" if the distance between nRF24L01 modules is close to each other.
  // Use "RF24_PA_HIGH" or "RF24_PA_MAX" if the distance between nRF24L01 modules is far from each other.
  // For more details, see here : https://github.com/nRF24/RF24/blob/master/RF24.h#L26C1-L26C1
  radio.setPALevel(RF24_PA_LOW);
  
  // Set the transmission datarate.
  radio.setDataRate(RF24_250KBPS); // (RF24_250KBPS|RF24_1MBPS|RF24_2MBPS).

  // Set the number and delay of retries upon failed submit.
  radio.setRetries(5,5); // setRetries(delay,count).

  // Set the nRF24L01 module as the sender.
  radio.stopListening();

  // Set the address to send data to the receiver. The receiver must use the same address.
  radio.openWritingPipe(Pipe_Address);

  // Prepare data to be sent.
  sprintf(dataToSend, "Message %d",  count);
}
//________________________________________________________________________________

//________________________________________________________________________________VOID LOOP()
void loop() {
  // put your main code here, to run repeatedly:
  
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= sendIntervalMillis) {
    previousMillis = currentMillis;
    
    // Calls the send() subroutine.
    send_Data();
  }
}
//________________________________________________________________________________

//________________________________________________________________________________send_Data()
// Subroutine for sending data.
void send_Data() { 
  bool rslt;

  // 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
  rslt = radio.write(&dataToSend, sizeof(dataToSend));

  Serial.print("Data Sent : ");
  Serial.print(dataToSend);
  if (rslt) {
    Serial.println(" | Acknowledge received");
    update_Message();
  }
  else {
    Serial.println(" | Failed to send data !");
  }
}
//________________________________________________________________________________

//________________________________________________________________________________update_Message()
void update_Message() {
  count++;
  if (count > 9) count = 0;

  sprintf(dataToSend, "Message %d",  count);
}

Another close one, Receiver:

//Receiver

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

RF24 radio(9,8); //CE, CSN
const byte address[10] = "ADDRESS01";

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

void loop() {
  if(radio.available()) {
    char txt[11] = "";
    radio.read(&txt, sizeof(txt));
    Serial.println(txt);
  }
  else {
    Serial.println("No Data");
  }
}

Transmitter:

//Transmitter

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

RF24 radio(9,8); //CE,CSN
const byte address[10] = "ADDRESS01";

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

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

My wiring is the same as what everyone uses.

Hello jpfreels

I have been following the topic of using this type of wireless module and the associated software functions for some time now.

For wireless projects, I recommend using the HC12 module.

What are the advantages:

  1. no external functions from a library are needed.
  2. the development of a communication protocol is in your hands
  3. the necessary development steps can be programmed and tested without using the wireless module
  4. the radio module can be easily configured for the project requirements
  5. both transmitter and receiver are contained in one radio module.

hth

Have a nice day and enjoy coding in C++.

Mr. Paul,

I very much appreciate the speedy and comprehensive reply! I will absolutely look into utilizing the HC12 module when I have time in a few weeks. However, I am on a much shorter deadline than when I could acquire one. I basically have until tomorrow afternoon to have my Arduino's communicating as I need the data by tomorrow evening...

Today is the Tomorrow you worried about Yesterday. Without an annotated schematic I can only take a guess and that is nothing but a time burner for both of us. This sounds like a class project. What did you try, post links.

This is a long term project, not one with 24 hour deadline. Too late for the latter.

By the way, the nRF24L01 became obsolete years ago, and there are plenty of modern replacements that require far less effort to use.

Or, just dump Serial.prints to the Sparkfun OpenLog SD card and play the data back on your PC.

These are the links to some of the tutorials and below is the schematic of what I'm using.

It is one I have been working on for months but have just hit a snag with the communication which is not the main project but a necessary factor. I will probably purchase the SD car you mentioned but it will not arrive until Monday and I had planned to start the neural network then. which I need to finish by next Friday.

Gil's Crispy Critter Rules, they apply to processor hardware:
Rule #1. A Power Supply the Arduino is NOT!
Rule #2. Never Connect Anything Inductive to an Arduino!
Rule #3 Don't connecting or disconnecting wires with power on.
Rule #4 Do not apply power to any pin unless you know what you are doing.
LaryD's Corollary's
Coro #1 when first starting out, add a 220R resistor in series with both Input and Output pins.
Coro #2 buy a DMM (Digital Multi-meter) to measure voltages, currents and resistance. Violating these rules tends to make crispy critters out of Arduinos.
Hint: It is best to keep the wires under 25cm/10" for good performance.
Use a separate power supply for the radio, The way it is shown is some times maybe.

Any chance you can preprogram the boat?
I'd be rushing to the hobby RC shop first thing if I was out of options, you could get that up and running in an hour or two

The shop nearest to me is 45 minutes away, and I have called each time to make sure they have what I need. Either I am terrible at explaining things or they just don't hear me as they do not have what I need when I go. But, I was able to fix the code I was running and will post it when all is said and done for others who have the same issue.

1 Like

Sweet, must be a relief to make some headway on your snag.

It was a huge relief!

1 Like

Following a tutorial by Ralph Bacon on his YouTube channel:

Modified to nearly fit my needs; the Receiver code is as follows:

//Receiver

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

RF24 radio(7, 8);

byte addresses[][6] = {"1Node", "2Node"};

void setup() {
  Serial.begin(115200);
  Serial.println("Receiver");

  radio.begin();
  radio.setPALevel(RF24_PA_MIN);
  radio.setDataRate(RF24_2MBPS);
  radio.setChannel(124);

  //radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1, addresses[1]);
  
  radio.startListening();
}

void loop() {
  float data[7];

  if ( radio.available()) {
    while (radio.available()) {
    radio.read( &data, sizeof(data));
    }
    Serial.print(data[0]);
    Serial.print(",");
    Serial.print(data[1]);
    Serial.print(",");
    Serial.println(data[2]);
  }
}

The Transmitter code:

//Transmitter

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

float theta = 0;
float phi = 1;
float psi = 2;

RF24 radio(7, 8);

byte addresses[][6] = {"1Node", "2Node"};

void setup() {
  Serial.begin(115200);
  Serial.println("Transmitter");

  radio.begin();
  radio.setPALevel(RF24_PA_MIN);
  radio.setDataRate(RF24_2MBPS);
  radio.setChannel(124);

  radio.openWritingPipe(addresses[1]);
  //radio.openReadingPipe(1, addresses[0]);
}

void loop() {
  float data[3] = {theta,phi,psi};

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

  Serial.print("Sent: ");
  Serial.print(data[0]);
  Serial.print(",");
  Serial.print(data[1]);
  Serial.print(",");
  Serial.println(data[2]);

  delay(100);
}

The tutorial has the viewer send random integers while I have modified it to send arrays of data. I was unable to get the transceivers to acknowledge sends and receives but I didn't need it for my purposed.

I am unsure why, but if you tack on an else{} clause after if(radio.available... the program defaults to else{}. This tells me that either I misunderstand what the true false parameters of radio.available are or something is wrong within my RF24.h library. Either way, removing the else{} clause makes it work.

Aside from that, I found that the maximum one dimensional array size that can be sent is 8.

Also, contrary to what I have been told, I only got about 20-30m of range when PA Level was set to RF24_PA_MAX instead of the promised 'couple kilometers'. Different parameters and data-packs absolutely affect the range, but that's what you'll get if your needs are similar to mine.

1 Like

nRF24L01 Tutorial

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