Can we guarantee RF chat bewteen Arduinos?

I have a couple of Arduinos set up with nRF24L01 RF boards as shown. They do talk but there are a disturbing number of missed packets, both out and in. About 3% at 10 m going up to about 10-12% at 20 m.

Another thing my experimenting has shown up is that missed packets are much more likely to occur if I am moving the slave station. Why would the system be sensitive to one of the stations moving (within range)?

Given that the boards (usually) reconnect after a string of misses, do you just strip out any timeout functionality and just keep hammering away at the transmission until you succeed? Is there any more elegant solution to the provision of communication reliability expected when you are running a machine? I know there is an high-power version of the nRF24L01. Is there anything else I can do?


160828-Arduino with Capacitor.jpg

That does seem like a large dropout for such a small distance...

You can set the baud rate lower. This can increase range at expense of...well...baudrate.


That capactior needs to be as close to the module as possible. Ideally soldered to the + and - pins ON the module.

Wire length also introduces noise from RF emissions. Think about shortening all wires and moving that cap closer.

A separate 3.3V supply is also a good requirement to have.

Image from Original Post so we don’t have to download it. See this Image Guide

160828-Arduino with Capacitor.jpg


My Unos work fine with that sort of connectio arrangement and without any capacitor. However I have found it necessary to use a capacitor on a breadboard version.

My suspicion is that the problem has nothing to do with the capacitor.

However it may be due to loose connections - when you move the Arduinos around maybe there are brief moments with loss of power or signal for the nRF24s

My breadboard nRF24s worked at about 110m while I was walking with the Tx in my hand.

As usual, post the programs you are using.


Networking theory for "guaranteed" transmissions is like Alice in Wonderland's rabbit hole.

A sends a message to B. B responds "I got it". So A knows that the transmission was received and passes the checks at the other end. But if A doesn't receive that message, it can try to send it again.

If B did actually get it but the "got it" message was the one which was lost, B now has two copies of the first message. How does it know that they are the same message and not two commands?

So A has to flag the second message as a retransmission. Then B has to respond to say "I got the retransmission".

What if that gets lost? You can go forever.

There are systems that do this for unreliable data links. Copy an existing one instead of making up your own ideas. There are so many little things that can go wrong, much like cryptography. Use the system designed by the guy with a PhD.

Networking theory for "guaranteed" transmissions is like Alice in Wonderland's rabbit hole..

I agree. But I suspect the OP has some simple problem that when eliminated will provide sufficient reliability without any of the complexities for which a PhD would be needed.

One thought that should have crossed my mind earlier is that the OP is unwittingly using a channel that is subject to external interference. I think the RF24 library defaults to channel 76. It would be worth trying a different channel.


Thanks to all those folks who responded.

Firstly, the code I used for the test is a modified version of TMRh20’s ‘Getting Started’. You will not that I have lowered the Baud Rate to 9600, and changed the channel to 108.

* Getting Started example sketch for nRF24L01+ radios
* This is a very basic example of how to send data from one node to another
* Updated: Dec 2014 by TMRh20
* Modified: October 2106 by Rick 

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

/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/
bool radioNumber = 0;
int txNumber = 0;
int txFailures = 0;
int rxFailures = 0;

/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8);

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

// Used to control whether this node is sending or receiving
bool role = 0;

void setup() {
  Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));

  // Set the PA Level low to prevent power supply related issues since this is a
 // getting_started sketch, and the likelihood of close proximity of the devices. 
 // The options are MIN, LOW, HIGH and MAX.  RF24_PA_MAX is default.

  // Added some code to increase range of TX/RX
  radio.setDataRate(RF24_250KBPS);  // Fast enough ... better range
  radio.setChannel(108);  // Above most WiFi channels
  // Open a writing and reading pipe on each radio, with opposite addresses
  // Start the radio listening for data

void loop() {
/****************** Ping Out Role ***************************/  
  if (role == 1)  
    radio.stopListening();  // First, stop listening so we can talk.
    // added code to see message sequence
    txNumber ++;
    Serial.print("Transmission number ");
    Serial.print(": ");
    Serial.println(F("Now sending"));

    unsigned long start_time = micros();  // Take the time, and send it.  This will block until complete
     if (!radio.write( &start_time, sizeof(unsigned long) ))
       // count Tx failures
       txFailures ++;
       Serial.print("Transmission failure count = ");
       Serial.print(' ');   
    radio.startListening(); // Now, continue listening
    unsigned long started_waiting_at = micros();  // Set up a timeout period, get the current microseconds
    boolean timeout = false;  // Set up a variable to indicate if a response was received or not
    while ( ! radio.available() )
    { // While nothing is received
      if (micros() - started_waiting_at > 200000 )
      { // If waited longer than 200ms, indicate timeout and exit while loop

        // added code to count Rx failures
        rxFailures ++;
        Serial.print("Reception failure count = ");
          timeout = true;
    if ( timeout )
    { // Describe the results
        Serial.println(F(" Failed, response timed out."));
        unsigned long got_time; // Grab the response, compare, and send to debugging spew &got_time, sizeof(unsigned long) );
        unsigned long end_time = micros();
        // Spew it
        Serial.print(F("Sent "));
        Serial.print(F(", Got response "));
        Serial.print(F(", Round-trip delay "));
        Serial.println(F(" microseconds"));
    } // end if ( timeout ) .. else

    // Try again 1s later
  }  // end if (role == 1)

/****************** Pong Back Role ***************************/

  if ( role == 0 )
    unsigned long got_time; // Variable for the received timestamp
    if( radio.available())

      while (radio.available())
      { // While there is data ready &got_time, sizeof(unsigned long) ); // Get the payload
      radio.stopListening();  // First, stop listening so we can talk   
      radio.write( &got_time, sizeof(unsigned long) );  // Send the final one back.      
      radio.startListening(); // Now, resume listening so we catch the next packets.     
      Serial.print(F("Sent response "));
 }  // end if ( role == 0 )

/****************** Change Roles via Serial Commands ***************************/

  if ( Serial.available() )
    char c = toupper(;
    if ( c == 'T' && role == 0 )
      Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
      role = 1; // Become the primary transmitter (ping out)
      if ( c == 'R' && role == 1 )
        Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));      
        role = 0; // Become the primary receiver (pong back)
      } // end else ... if
    } // end if ( c == 'T' && role == 0 ) ... else ...
  } // end if ( Serial.available() )
} // end Loop

Robin2 suggested the problem might be loose connections. I put a ‘C’ bend in each leg of the capacitor (which I use as the pin) so that I have a definite push to insert the pin in the socket. That did help, but not enough.

I have attached some of the printout for a test at 20 m. You can see I have a total failure rate of some 11%, and in this case all of them are transmission errors.

MorganS mentioned that there …are systems … and that I should … copy one …. That brings up the question, "From where?. How would I search for something like that?

Thanks again all

You may try to set your Tx Power to low , you may using fake nRF24L01+'s

	radio.setPALevel(RF24_PA_LOW);  // RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX

I did try that BillHo, but at 20 m I couldn't connect at all.

I'm not familiar with that radio, but I notice from a picture that the units have built-in strip antennas. Have you taken care to make sure there is no shielding in your case that would affect the antennas?

Incidentally, for better range use lower frequencies. The 433 Mhz. radios (my favorite -- the RFM22B) give very good range.

Network transmission systems have names. TCP/IP is one. MODBUS is another. I can't think of one off the top of my head which will do exactly what you asked for but I am sure that following a few Wikipedia links will find them for you.

Incidentally, for better range use lower frequencies. The 433 Mhz. radios (my favorite -- the RFM22B) give very good range.

Hi jrdoner

My newbie status trips me up again. :sob: I know nothing of 433 MHz or RFM22B. What Arduino channel would that be?

Dealing with things backwards ...
433 Mhz requires a different wireless module. The nRF24 should be perfectly good for 10m or 20m and much more.

When I referred to loose connections I did not mean ONLY for the capacitor - you need to check ALL the connections.

If channel 108 is the only one you have tried then try some other channels.

I have posted a new Simple nRF24 Tutorial with some very basic demo programs that don't depend on input from the Serial Monitor. They may be worth trying. Unlike the TMRh20 examples, there are separate Tx and Rx programs.


Thanks ribin2, I'll work through those.