nRF24L01 serial like synchronous bi-directional communication

Hi,

does someone have a good example of a protocol implementation which simulates a syncronous bi-direction communication (like a serial communication via COM or bluetooth) using nRF24L01 devices?
In the end I want to simply dump a message to the other device, not caring about the current state of RX or TX. If the device is currently in sending mode, the message should get queued and send later.

Otherwise I'll start based on the very good existing libraries and develop it myself.

Any tip on where how to start is welcome.

Thanks
Robert

I started working on my own solution. Not all the features I requested in my initial post are in. But for my project it does the job. I'll extend it as needed by the project.
It is based on the getting started sketch.

What you can do with it:

  • One sketch for both arduinos/nodes.

  • Submitted messages get "injected" into the variable used for buffering the serial communication. So your sketch works with serial input the same way as with messages received via the NRF.

  • Submit T:xxx\n via serial to one arduino will submit a message (xxx) to the other one. (can trigger any function which can also be triggered by serial com)

  • Submit S:xxx\n via serial to one arduino will submit a message (xxx) to the other one and have him output the message via Serial.print.

  • Submit R\n via serial to one arduinowill perform a throughput test.

  • Submit T:R\n via serial to one arduino will request the other arduino to perform a throughput test.

  • Submit T:P\n via serial to one arduino will request the other arduino to perform send back "Pong".

Every input on improvements is welcome. If someone finds ways to reduce the size of the compiled sketch I would be glad too.

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

RF24 radio(9,10);
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = {0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

//for Serial input
String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

//NRF Packages
byte SendPackage[32];
byte ReceivePackage[32];
boolean sending=0;

void setup(void)
{
  //
  // Print preamble
  //

  Serial.begin(115200);
  radio.begin();
  // optionally, increase the delay between retries & # of retries
  radio.setRetries(15,15);
  radio.setPayloadSize(32);
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.startListening();
  //radio.printDetails();
}

void loop(void)
{
  //check for NRF received
  NRFreceive();
  //check for Serial received (or filled by NRF)
  Serialreceive();  
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read(); 
    inputString += inChar;
    if (inChar == '\n') {
      stringComplete = true;
    } 
  }
}

byte NRFsend(String NRFPack = ""){
  NRFPack.getBytes(SendPackage, 32);
  radio.stopListening();
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  bool ok = radio.write(SendPackage,sizeof(SendPackage));
  if (!ok) Serial.println("NRFerror");
  radio.startListening();
  unsigned long started_waiting_at = millis();
  bool timeout = false;
  while ( ! radio.available() && ! timeout )
    if (millis() - started_waiting_at > 200 )
      timeout = true;
  if ( timeout )
  {
    Serial.println("NRFerror");
  }
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
}

void NRFreceive(){
  if ( radio.available() )
  {
    //byte ReceivePackage[32];
    bool done = false;
    while (!done)
    {
      done = radio.read( &ReceivePackage, sizeof(ReceivePackage) );
      delay(5);
    }
    radio.stopListening();
    inputString = ((char *)ReceivePackage);
    stringComplete = true;
    radio.write( "1", 1 );
    radio.startListening();
  }
}

void Serialreceive(){
  if (stringComplete) {
    if (inputString.startsWith("T:")) {
      NRFsend(inputString.substring(2));
    }
    if (inputString.startsWith("S:")) {
      Serial.print(inputString.substring(2));
    }

    //    ####  TEST FUNCTIONS ###
    if (inputString == "P\n") {
      Serial.println("Pong");  
      NRFsend("S:Pong\n");   
    }
    if (inputString == "R\n"){
      double starttest = millis();
      int x = 1;
      while ((millis()-starttest) < 1000){
        NRFsend("11111111111111111111111111111111");
        x++;
      }
      Serial.print("Packet test 1000 millis: ");
      Serial.println(x);
      NRFsend("S:Remote Test: Packet test ");
      NRFsend("S:1000 millis: ");
      NRFsend("S:" + String(x) + "\n");
    }
    //    ####  TEST FUNCTIONS - END ###

    inputString = "";
    stringComplete = false;
  }
}

Hey robvoi,

I'm looking for a protocol for send/recieve messages over Bluetooth. Atm I'm using Serial.read()/write(bytearray,lengt) to get/post messages and my scetch is working well but sometimes some bytes are twisted, different or just missing.

Does your scetch work with Bluetooth?
Or do you know any protocol which would solve my problem?

Hi,

what I wrote is actually no protocol and it's only based on the nRF24L01 library someone else wrote. No, it doesn't work for bluetooth.
All it does is covered by the bluetooth protocol anyway.

It is actually a bit strange that you get bytes twisted as they get send serially. Maybe it is a resend issue on Bluetooth level.

What you can do is to send each byte converted as a string instead of the bytes alone. You add meta information like a serial number to the byte. The receiver can then sort the bytes by the serial number until the message is completely submitted (which is signaled by a byte you specify – e.g. 10).

I always used simple Serial.print to submit a String. Never had the problems you described.

Regards,
Robert

The meta Information is a good idea and I'm already working on it, but I've still got the feeling there is much simpler solution out there :grin:.

Do you know any settings which have to be set so a shield could work the way it should?

I use the ITEAD BT Shield v2.2, based on the Bluetooth HC-05 modem transceiver.

No idea why it doesn't work. So I can't offer a solution.

You can try to lower the baud rate and see if the stability is better.
Also check the AT commands available for the module. Especially things like buffering and retransmitting.

Robert

robvoi:
I started working on my own solution. Not all the features I requested in my initial post are in. But for my project it does the job. I'll extend it as needed by the project.
It is based on the getting started sketch.

What you can do with it:

  • One sketch for both arduinos/nodes.

  • Submitted messages get "injected" into the variable used for buffering the serial communication. So your sketch works with serial input the same way as with messages received via the NRF.

  • Submit T:xxx\n via serial to one arduino will submit a message (xxx) to the other one. (can trigger any function which can also be triggered by serial com)

  • Submit S:xxx\n via serial to one arduino will submit a message (xxx) to the other one and have him output the message via Serial.print.

  • Submit R\n via serial to one arduinowill perform a throughput test.

  • Submit T:R\n via serial to one arduino will request the other arduino to perform a throughput test.

  • Submit T:P\n via serial to one arduino will request the other arduino to perform send back "Pong".

Every input on improvements is welcome. If someone finds ways to reduce the size of the compiled sketch I would be glad too.

This is good stuff man... just what I'm looking for... :slight_smile: :slight_smile:

I got the RF24 lib working fine with the GettingStarted examples and got very good range of out my wireless modules from inhaos.com ( they are 100% compatible with nRF24L01 modules )...

When I copy, compile & upload yr sketch on both my Arduino UNO with the correct SPI pins, nothing happened on the Serial Monitor... even the radio.printDetails() did not print out on the Serial monitor...

Any idea where should I start troubleshooting this ?

I've read the nRF24L01 datasheets and tested a few other Nordic RF24L01 libraries and found this RF24 libraries from maniacbug ( http://maniacbug.github.com/RF24/index.html ) one of the best lib for these low cost RF modules...

Hi,

I would start here: http://arduino.cc/forum/index.php/topic,54795.0.html
With this you can find out if your module is connected correctly and working.

Go near a WIFI wouter and you should get some output. The output should look like in the example. When I first tried it I got 'W' stated in all fields of all chanels.
I don't remember though what the problem was. One NRF worked, the other didn't.

One you got this running you can start with the ping examples of the NRF library.

Regards,
Robert

Oh, I accidentally found the issue..

In the Serial Monitor besides the speed/baud, there are options for :-

  • No line ending
  • Newline
  • Carriage Return
  • Both NL & CR..

For yr sketch to work, it need to be at Newline since your codes are looking for \n at the end of the serial input...

Well, I got R & P working, the T is still not working yet.... getting there....

:slight_smile: That was easy then.
I hope my code works, if there is a problem, just let me know.

Robert

I found out why the T: was not working ( or not displaying text on the other side )

I notice the data was sent over to the receiving end but was NOT displayed on the serial monitor...

Just to make the instruction much more clearly :-

To send a text to the other side to be displayed by serial monitor, you will need to type in :-

"T:S:print this text"

so that the other side will see :-

"S:print this text"

... and the if statement matching "S:" will sent it to the Serial.print function displaying

"print this text"

That's how it was meant :slight_smile:
With this you can send instaructions to both involved arduinos. In addition you can use them as wireless serial adapter.

Yes.. I found that out after reading yr codes... :slight_smile:

Can you share some examples/ideas on how u use this ?

Do u define yr own packet/frames with headers to read/write to the pins to/from the remote nodes ?

Do u add fields like simple addressing to address different nodes in a broadcast environment ?

Stanley

I mainly used it to steer a robot. I used one Arduino on the PC, and one on the robot.
The one on the PC acted as controller for the NRF. At the same time I can unhook the controller on the PC and can use physical control (joystick, buttons) to control the robot.

The communication was manly based on predefined message patterns. Like D:100 is: go forward 100cm. For the manual/physical control it's then a simple F: to go forward until the stop message arrives.

Hello,
I've tried this sketch on 2 Arduino with NRF but I lose most of my packets.
If I try to send 20 times the same packet, I receive it in the best case 1 time in 80% of the tests and 0 time in the other 20%.
I never receive all of my packets.
I don't understand why ...

You may have sender and receiver too close together. Try to have at least one meter between them.

hi all,

Is it poossible to do bi-directional communication with Arduino due boards using nRF24L01+?

thank you.

Hi,robvoi...I have seen your code u have posted for 2 way communication whereby u combine the code together for both transmit and receive... So , are u uploading the same code to two different arduino ? Is it possible to seperate the code into two parts one for each arduino?

See this chat program example :-

Details docs in the codes itself... one code for both functions ...

https://github.com/stanleyseow/RF24/tree/master/examples/nRF24_Serial_Chat

See this chat program example :-

Details docs in the codes itself... one code for both functions ...

https://github.com/stanleyseow/RF24/tree/master/examples/nRF24_Serial_Chat

I think my project can combine both together. Can u guide me through my project? I have posted already related to two way wireless communication.