Simultaneous servo and esc control with NRF24l01 over two servos

Hello, I am currently working on a project that requires me to communicate two analog signals from a joystick (X and Y) that control either an electronic speed controller or a servo. I have done this successfully over a wired connection on a single board, with the code shown below:

// Hardwired Hovercraft Program Version
#include <Servo.h>
Servo ESC; // creates servo object to control the ESC
Servo servo; // creates servo object to control servo
int JoysX;  // value from the analog pin 0
int JoysY;  // value from the analog pin 1
void setup() {
  // Attach the ESC on pin 9
  ESC.attach(6,1000,2000); // (pin, min pulse width, max pulse width in microseconds to arm ESC) 
  servo.attach(5);
}
void loop() {
  JoysX = analogRead(A0);   // reads the value of the potentiometer (value between 0 and 1023)
  JoysX = map(JoysX, 0, 1023, 0, 180);   // scales it to use it with the servo library (value between 0 and 180)
  ESC.write(JoysX);    // Sends the signal to the ESC  
  JoysY = analogRead(A1);   // reads the value of the potentiometer (value between 0 and 1023)
  JoysY = map(JoysY, 0, 1023, 0, 180);   // scales it to use it with the servo library (value between 0 and 180)
  servo.write(JoysY);    // Sends the signal to the Servo
}

Although this works, what I am attempting to complete is to have two Arduino boards, one a transmitter, and one a receiver, over two nrf24l01 modules, where the transmitter can communicate two analog signals at once to the receiver. I have attempted to program this myself, although it is proving quite difficult. The code for both the transmitter and receiver is shown below:

TX CODE:


#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); // 00001
  radio.setPALevel(RF24_PA_MIN);
}

void loop() {
  radio.stopListening();
  int JoysValueX = analogRead(A0);
  int angleValueX = map(JoysValueX, 0, 1023, 0, 180);
  radio.write(&angleValueX, sizeof(angleValueX));
  int JoysValueY = analogRead(A1);
  int angleValueY = map(JoysValueY, 0, 1023, 0, 180);
  radio.write(&angleValueY, sizeof(angleValueY));

}

RX CODE:

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

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

Servo SteeringSystem;
Servo ESC;

void setup() {
  SteeringSystem.attach(5);
  ESC.attach(6);
  radio.begin();
  radio.openReadingPipe(1, address); // 00001
  radio.setPALevel(RF24_PA_MIN);
}

void loop() {
  delay(5);
  radio.startListening();
  if ( radio.available()) {
    while (radio.available()) {
      int angleVX = 0;
      int angleVY = 0;
      radio.read(&angleVX, sizeof(angleVX));
      SteeringSystem.write(angleVX);
      radio.read(&angleVY, sizeof(angleVY));
      ESC.write(angleVY);
    }
  }
}

I don't know if communicating two analog signals at once through an nrf24l01 module is possible or plausible, so if anyone can help me out, it would be much appreciated.

This might be of use. It's the repository for a combat robot I built.
https://github.com/IceChes/Flash_Memory

1 Like

Put your two values into a "struct" and transmit the struct.

Project #2 of the following has an example where the struct contains two ints (could be your two analogReads), a float, and a char message. The transmitter sends that entire package to the receiver...

Arrays also work but structs are more intuitive.

1 Like

Here is example code that sends 2 LDRs (LIght Dependent Resistor) data in a struct and receives the struct to display the LDR values. The code uses some methods from the Robin2's simple rf24 tutorial.

sender:


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


const byte CE_PIN = 9;
const byte CSN_PIN = 10;

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


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

struct LdrValues
{
  int ldr_1;
  int ldr_2; 
}ldrValues;

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

const byte LDR1 = A0;
const byte LDR2 = A1;

void setup()
{

   Serial.begin(115200);
   Serial.println("SimpleTx Starting");
   pinMode(LDR1, INPUT_PULLUP);
   pinMode(LDR2, INPUT_PULLUP);
   
   radio.begin();
   radio.setChannel(76);  //76 library default
   //RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
   radio.setPALevel(RF24_PA_HIGH);
   radio.setDataRate( RF24_250KBPS );
   radio.setRetries(3, 5); // delay, count
   radio.openWritingPipe(slaveAddress);
}

void loop()
{
   currentMillis = millis();
   if (currentMillis - prevMillis >= txIntervalMillis)
   {
      send();
      Serial.print("LDR 1 = ");
      Serial.print(ldrValues.ldr_1);
      Serial.print("    LDR 2 = ");
      Serial.println(ldrValues.ldr_2);
      prevMillis = millis();
   }
}

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

void send()
{
   ldrValues.ldr_1 = analogRead(LDR1);
   ldrValues.ldr_2 = analogRead(LDR2);
   radio.write( &ldrValues, sizeof(ldrValues) );
}

receiver



// SimpleRx - the slave or the receiver

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

const byte CE_PIN = 9;
const byte CSN_PIN = 10;

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

RF24 radio(CE_PIN, CSN_PIN);

struct LdrValues
{
   int ldr_1;
   int ldr_2;
} ldrValues;

bool newData = false;

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

void setup()
{

   Serial.begin(115200);

   Serial.println("SimpleRx Starting");

   radio.begin();
   radio.setChannel(76);  //76 library default
   //RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
   radio.setPALevel(RF24_PA_HIGH);
   radio.setDataRate( RF24_250KBPS );
   radio.openReadingPipe(1, thisSlaveAddress);
   radio.startListening();
}

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

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

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

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

void showData()
{
   if (newData == true)
   {
      Serial.print("Data received >> ");
      Serial.print("LDR 1 = ");
      Serial.print(ldrValues.ldr_1);
      Serial.print("    LDR 2 = ");
      Serial.println(ldrValues.ldr_2);
      newData = false;
   }
}
1 Like

After the reapplication of this code, the ESC on pin 6 does arm after I send the '0' value from the X axis potentiometer, however, I cannot control either one of the Servo objects, and the ESC is stuck on its maximum setting. I didn't use pin A2 for analog, so I felt as though I didn't need it, but I need to understand why it is there, so I can see whether or not to put it to use. The code used is shown below:

Transmitter:

//Inspired largely by IceChes

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
int num[1]; //Configure packet to send
int X;
int Y;

RF24 radio(9, 10); // CE, CSN of RF 

const byte address[6] = "00001"; //Channel one

void setup() {
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MAX); //All of the power
  radio.stopListening();
}

void loop() {
  X = analogRead(A0);
  Y = analogRead(A1);
  num[0] = X;
  num[1] = Y;
  radio.write(&num, sizeof(num)); //SEND IT
}

Reciever:

//Inspired largely by IceChes

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

RF24 radio(9, 10); // CE, CSN of the RF 

Servo ESC; //Attach ESC as a servo
Servo SteeringSystem; //Attach Steering System as a servo

int num[32];

const byte address[6] = "00001"; //Channel 1
int ESCWrite;
int SSWrite;
int potRead;
int xDir = 90;       // inital direction for esc later
int yDir = 90;      // initial direction for servo later  
void setup() {
  Serial.begin(9600);
  ESC.attach(6, 1000, 2000); //Timings for ESC
  SteeringSystem.attach(5);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MAX); //Amplify it
  radio.startListening();
}

void loop() {
  if (radio.available()) {
    radio.read(&num, sizeof(num)); //Get packet and assign values
    Serial.println(num[0]);
    Serial.println(num[1]);
    ESCWrite = map(num[0], 0, 1024, 0, 180); //Map ESC to full power
    ESC.write(ESCWrite);
    SSWrite = map(num[1], 0, 1024, 0, 180); //Map Servo to full power
    SteeringSystem.write(SSWrite);
    XRead();
    YRead();
  }
}

void XRead() { 
  if (num[0] > 600) {             // if data is greater than 600
  xDir = 0;                       // dir is 0 
  ESC.write(xDir);             // TURN
  }
  else if (num[0] < 400) {         // more if data for x axis, (steering)
  xDir = 90;                       // 90 is straight 
  ESC.write(xDir);               // no turn 
  }
  else {                          // if data 0 is equal to 0. servo turns left
  xDir = 180;                    // see unit circle
  ESC.write(xDir);               // TURN  
 }
}
void YRead() {
  if (num[1] > 600) {             // if data is greater than 600
  yDir = 0;                       // dir is 0 
  SteeringSystem.write(yDir);             // TURN
  }
  else if (num[1] < 400) {         // more if data for x axis, (steering)
  yDir = 90;                       // 90 is straight 
  SteeringSystem.write(yDir);               // no turn 
  }
  else {                          // if data 0 is equal to 0. servo turns left
  yDir = 180;                    // see unit circle
  SteeringSystem.write(yDir);    // TURN  
  }
 }

num[1] is an array with only 1element. You are trying to use 2 (num[0] and num[1]).

Steve

1 Like

So you are sending data. Great!

Arrays are kind of weird, and there's one small problem. Spot the difference.
Transmitter:

//Inspired largely by IceChes

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
int num[2]; //Configure packet to send
int X;
int Y;

RF24 radio(9, 10); // CE, CSN of RF 

const byte address[6] = "00001"; //Channel one

void setup() {
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MAX); //All of the power
  radio.stopListening();
}

void loop() {
  X = analogRead(A0);
  Y = analogRead(A1);
  num[0] = X;
  num[1] = Y;
  radio.write(&num, sizeof(num)); //SEND IT
}

Receiver:

//Inspired largely by IceChes

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

RF24 radio(9, 10); // CE, CSN of the RF 

Servo ESC; //Attach ESC as a servo
Servo SteeringSystem; //Attach Steering System as a servo

int num[32];

const byte address[6] = "00001"; //Channel 1
int ESCWrite;
int SSWrite;
int potRead;
int xDir = 90;       // inital direction for esc later
int yDir = 90;      // initial direction for servo later  
void setup() {
  Serial.begin(9600);
  ESC.attach(6, 1000, 2000); //Timings for ESC
  SteeringSystem.attach(5);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MAX); //Amplify it
  radio.startListening();
}

void loop() {
  if (radio.available()) {
    radio.read(&num, sizeof(num)); //Get packet and assign values
    Serial.println(num[0]);
    Serial.println(num[1]);
    ESCWrite = map(num[0], 0, 1024, 0, 180); //Map ESC to full power
    ESC.write(ESCWrite);
    SSWrite = map(num[1], 0, 1024, 0, 180); //Map Servo to full power
    SteeringSystem.write(SSWrite);
    XRead();
    YRead();
  }
}

void XRead() { 
  if (num[0] > 600) {             // if data is greater than 600
  xDir = 0;                       // dir is 0 
  ESC.write(xDir);             // TURN
  }
  else if (num[0] < 400) {         // more if data for x axis, (steering)
  xDir = 90;                       // 90 is straight 
  ESC.write(xDir);               // no turn 
  }
  else {                          // if data 0 is equal to 0. servo turns left
  xDir = 180;                    // see unit circle
  ESC.write(xDir);               // TURN  
 }
}
void YRead() {
  if (num[1] > 600) {             // if data is greater than 600
  yDir = 0;                       // dir is 0 
  SteeringSystem.write(yDir);             // TURN
  }
  else if (num[1] < 400) {         // more if data for x axis, (steering)
  yDir = 90;                       // 90 is straight 
  SteeringSystem.write(yDir);               // no turn 
  }
  else {                          // if data 0 is equal to 0. servo turns left
  yDir = 180;                    // see unit circle
  SteeringSystem.write(yDir);    // TURN  
  }
 }

EDIT - Disclaimer: This may not fix 100% of your problems. Without being able to test, I don't know.

1 Like

It works! After using the change given, it had still not been communicating with the other, but a simple switch for the nRF24l01+pa+lna module (The more powerful one with the antenna) from 3.3v to 5v made it work smoothly. It is almost instant feedback, and I could not be happier. Thanks for your help!

1 Like

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