NRF24l01 lagging with servo

Hi, I am working on a project that requires servo control through radio and was having a bit of trouble. As soon an I plug in my servo into my Arduino Nano, the output for the receiver slows down significantly. Before plugging in the servo, the serial output came in multiple times a second but with the servo plugged in and servo.write() being added to the code, the output comes about once every 2 seconds. I have both my Receiver and Transmitter code attached below. I do not think it is a wiring problem as I have tested the servo and NRF module separately and they work just fine. I would love to know what is going on.

Final_Receiver.ino (849 Bytes)

Final_Transmitter.ino (1.36 KB)

More members will see your code if posted properly. Read the how to use this forum-please read sticky to see how to properly post code. Remove useless white space and format the code with the IDE autoformat tool (crtl-t or Tools, Auto Format) before posting code.

You are sending data awfully fast. How fast do you really need to send data? How fast can the servo respond?

I have 2 Unos set up with rf24 radios and tried your code on them. I had to change the CE and CSN pins to match my setup. I also changed the sending code to send hard coded test values and included a timer to slow the data sending down. Code seems to work fine for me. I get values at the expected rate (10Hz).

Are your servos powered by an external supply?

Modified send code:

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

RF24 radio(9, 10); // CE, CSN     // Radio Setup
const byte address[6] = "00001";

int ThrustPin = 2;    // select the input pin for the potentiometer
int PitchPin = 3;
int YawPin = 4;
int ThrustVal, PitchVal, YawVal, intValues = 0;
String Thrust, Pitch, Yaw, values;



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

   radio.begin();                    // Radio setup
   radio.openWritingPipe(address);
   radio.setPALevel(RF24_PA_MIN);    // Change for flight
   radio.stopListening();
}

void loop()
{
   static unsigned long timer = 0;
   unsigned long interval = 100;
   if (millis() - timer >= interval)
   {
      timer = millis();
      ThrustVal = analogRead(ThrustPin);            // Read Pot Values
      PitchVal = analogRead(PitchPin);
      YawVal = analogRead(YawPin);

      ThrustVal = map(ThrustVal, 0, 430, 1000, 2000);     // Convert Pot values to 1000-2000

      if (PitchVal >= 569)
         PitchVal = map(PitchVal, 569, 1023, 1500, 2000);
      else
         PitchVal = map(PitchVal, 0, 569, 1000, 1500);

      if (YawVal >= 505)
         YawVal = map(YawVal, 505, 1023, 1500, 2000);
      else
         YawVal = map(YawVal, 0, 505, 1000, 1500);

      int int_array[3];                                 // Put pot values into an array
      int_array[0] = 1500; //map(ThrustVal,1000,2000,0,180);
      int_array[1] = 1000; //map(PitchVal,1000,2000,0,180);
      int_array[2] = 2000; //map(YawVal,1000,2000,0,180);

      radio.write(&int_array, sizeof(int_array));         //send radio signal
   }
}

Receive code:

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

ServoTimer2 servoElevator;

int Thrust, Pitch, Yaw;



RF24 radio(9, 10); // CE, CSN
const byte address[6] = "00001";
void setup()
{
   radio.begin();                    //Radio Setup
   radio.openReadingPipe(0, address);
   radio.setPALevel(RF24_PA_MIN);
   radio.startListening();

   Serial.begin(9600);
   servoElevator.attach(3);        //Servo Setup
}

void loop()
{

   if (radio.available())
   {
      int int_array[3];
      radio.read(&int_array, sizeof(int_array));

      Thrust = int_array[0];
      //Pitch = int_array[1];
      //Yaw = int_array[2];

      Serial.println(Thrust);
      servoElevator.write(Thrust); //
   }
}

Sorry for the error in the way I sent the code as I am quite new to this.

I need my servos to send in values quick enough to control an RC Foamboard Airplane so I am not quite sure about the exact speed of data transmission. We can assume it to be fairly quick with at least more than one set of data being sent every second.

My servos are not powered externally. I have tried that but it resulted in very sporadic servo movements. I have also tried powering the entire system through an external battery but the servos didn't and as I do not have access to the serial monitor, in that case, I have no idea what happened in that run.

Thanks for the help.

The 5V regulator on a Nano is nowhere powerful enough to power one loaded servo, period. When the servo is powered the stall current draws the supply voltage down and the processor may reset and/or the radio will not receive properly. So multiple servos is a definite no go. They must be powered by an external source that has the current capability to supply the total stall current of all the servos. There is no shortcut to that. The stall current should be listed in the servo data sheet. You can assume 1A per small servo. Larger servos will pull considerably more.

My servos are not powered externally. I have tried that but it resulted in very sporadic servo movements. I have also tried powering the entire system through an external battery but the servos didn't

That is a common symptom of under-powered servos and a supply that can not keep up.

A spec for servos is the amount of slew versus time at a particular supply voltage. Many are in the range of 60 degrees in 200ms at 6V. I would try 20 to 50 updates per second (50ms to 20ms intervals). The servo signal is updated every 20ms so more often than that is a waste, I think.

My external power supply is a LiPo battery connected to an ESC that regulates the voltage to 5V. I have also checked this with a voltmeter. My setup is connecting the power pins to the power pins of the ESC while connecting the servo data wire to the Arduino digital pin.

I tried this and it did fix the lagging problem in the serial monitor; however, my servo was not moving at all. I even tried running a simple servo testing code that basically moves the servo back and forth yet with no success. I reran the servo test code with the Arduino powering the servo and it worked perfectly fine. I even double-checked the voltage output of the ESC and it was still 5V.

I have the Towerpro SG90 servo.

Post a diagram and clear photos of your wiring. Also your test code with a detailed explanation of what the code does and how that differs from what you want.

The closer that I can duplicate your setup I can more easily troubleshoot it on my hardware.

I have a picture below of my set-up. It is kind of a mess but most of the clutter comes from the NRF wiring and I can confirm that all of those are correct. I also checked if the servo pin actually goes to pin 3 as it does.

The basic test code is pasted below

#include <Servo.h>

Servo servoElevator;

void setup() {
  servoElevator.attach(3);      // Sets up servo to pin 3
  servoElevator.write(180);
  delay(1000);
}

void loop() {
  // put your main code here, to run repeatedly
  servoElevator.write(0);                   // Sets servo to position 0 degrees
  delay(1000);
  
  servoElevator.write(180);                 // Sets servo to position 180 degrees
  delay(1000);
}

My current problem is the fact that the servo is not even working with an external power source but ultimately I need the servo to change according to the values received through the NRF module

Connect Arduino, radio, servo and ESC grounds all together.

Do you know how much current that the ESC can supply to the 5V output?

How to post images so we don't have to download them and everyone can see them.
How to post an image.
Another page on posting images.

My current problem is the fact that the servo is not even working with an external power source but ultimately I need the servo to change according to the values received through the NRF module.

We will get there. I have done this before.

Alright. Attaching all ground pins to a common ground allowed the servo to move with the test code.

There is also no lag in the serial output for the receiver code either. But, the servo does not move with any movement in the remote/transmitter end.

Here is the reciver code again.

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

ServoTimer2 servoElevator;

int Thrust, Pitch, Yaw;



RF24 radio(7, 8); // CE, CSN
const byte address[6] = "00001";
void setup() {
  radio.begin();                    //Radio Setup
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MIN);
  radio.startListening();
  
  Serial.begin(9600);
  
  servoElevator.attach(3);        //Servo Setup
  
  
}
void loop() {

  if (radio.available()) {
      
                               
      int int_array[3];
      radio.read(&int_array, sizeof(int_array));
      
      Thrust = int_array[0]; 
      //Pitch = int_array[1];
      //Yaw = int_array[2]; 
              
      Serial.println(Thrust);
      servoElevator.write(Thrust); //
      
      
  }
  
  
}

The serial monitor on the receiver end definitely prints the correct values but it isn't writing on to the servo.

OK, I modified the codes a bit and tested. Servos move and seem responsive at 10Hz. Go faster if you want. I start slow to see what is happening better then speed up. I connected a joystick to A0 and A1 for input for the sender and made the maps simpler. One thing that I think was messing you up is that ServoTimer2 expects microseconds (1000 - 2000) and you were sending 0 to 180 after the maps so the ServosTimer2 instances never saw a valid number. Note again that I change CE and CSN to fit my setup. Change them back for yours.

Sender:

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

RF24 radio(9, 10); // CE, CSN     // Radio Setup
const byte address[6] = "00001";

const byte  ThrustPin = A0;    // select the input pin for the potentiometer
const byte PitchPin = A1;  // **** should use the A designator on analog inputs
const byte YawPin = A2;
int ThrustVal, PitchVal, YawVal, intValues = 0;

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

   radio.begin();                    // Radio setup
   radio.openWritingPipe(address);
   radio.setPALevel(RF24_PA_MIN);    // Change for flight
   radio.stopListening();
}

void loop()
{
   static unsigned long timer = 0;
   unsigned long interval = 100;
   if (millis() - timer >= interval)
   {
      timer = millis();
      ThrustVal = analogRead(ThrustPin);            // Read Pot Values
      PitchVal = analogRead(PitchPin);
      YawVal = analogRead(YawPin);

      /* ThrustVal = map(ThrustVal, 0, 430, 1000, 2000);     // Convert Pot values to 1000-2000

         if (PitchVal >= 569)
         PitchVal = map(PitchVal, 569, 1023, 1500, 2000);
         else
         PitchVal = map(PitchVal, 0, 569, 1000, 1500);

         if (YawVal >= 505)
         YawVal = map(YawVal, 505, 1023, 1500, 2000);
         else
         YawVal = map(YawVal, 0, 505, 1000, 1500);*/

      int int_array[3];                                 // Put pot values into an array
      int_array[0] = map(ThrustVal, 0, 1023, 1000, 2000);
      int_array[1] = map(PitchVal, 0, 1023, 1000, 2000);
      int_array[2] = map(YawVal, 0, 1023, 1000, 2000);
      for (int n = 0; n < 3; n++)
      {
         Serial.println(int_array[n]);
      }
      radio.write(&int_array, sizeof(int_array));         //send radio signal
   }
}

Receiver:

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

ServoTimer2 servoElevator;
ServoTimer2 servoPitch;

int Thrust, Pitch, Yaw;



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

void setup()
{
   radio.begin();                    //Radio Setup
   radio.openReadingPipe(0, address);
   radio.setPALevel(RF24_PA_MIN);
   radio.startListening();

   Serial.begin(9600);
   servoElevator.attach(3);        //Servo Setup
   servoPitch.attach(4);
}

void loop()
{

   if (radio.available())
   {
      int int_array[3];
      radio.read(&int_array, sizeof(int_array));

      Thrust = int_array[0];
      Pitch = int_array[1];
      //Yaw = int_array[2];

      Serial.print("Thrust  ");
      Serial.println(Thrust);
      Serial.print("Pitch  ");
      Serial.println(Pitch);

      servoElevator.write(Thrust); //
      servoPitch.write(Pitch);
   }
}

Oh my god thank you so much for the help. I finally got it to work perfectly!

Yay!!!