NRF24Network communication protocol

I am crashing my head on the wall to find a solution. I know it must be silly but I 'm stuck.

I am trying to implement a solution for communication integrity between several nodes and a base using the NRF24Network library and two Arduino nanos with nRF24 modules. My programs are pretty simple:

  • The base listens for incoming packets
  • The #A node sends packets to the base, inluding a random number that it’s my first step to confirm data
  • The base catches the packet with the data, reads them and…
  • The base sends back the confirmation number to the node #A
  • The node #A receives the packet with the confirmation number and checks its correctness

All steps are perfectly working except that the node #A gets the confirmation number but displays the previous one.

  • The temp, humi etc. data in the structure are variables I am planning to use next, so they are initialised and never updated for now.

node A#

//
//
// hypernet node A 1.1
//
//

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

//////////////////////////////////////
// Create the structures for data
//////////////////////////////////////
struct data_to_send{
  unsigned node;
  unsigned temp;
  unsigned humi;
  unsigned light;
  unsigned gas;
  unsigned door;
  unsigned hkey;
  unsigned test;
};

struct data_received{
  unsigned hkey = 0;
};

//////////////////////////////////////
// Setup nRF24L01+ module
//////////////////////////////////////
RF24 radio(8,7);
RF24Network rf24Net(radio);
const uint64_t this_node =  01; // node A
const uint64_t other_node = 00; // base

//////////////////////////////////////
// setup
//////////////////////////////////////
void setup(void){

  // Initialize interfaces
  printf_begin();
  Serial.begin(9600);
  Serial.print(F("Starting interfaces..."));
  SPI.begin();
  radio.begin();
  Serial.print(F("complete]\n"));
  rf24Net.begin(90, this_node);
  radio.setDataRate(RF24_250KBPS);
  radio.printDetails();
}

//////////////////////////////////////
// loop
//////////////////////////////////////
void loop(void)
{
  data_to_send payload;
  payload.node  = 1;
  payload.temp  = 22;
  payload.humi  = 33;
  payload.light = 44;
  payload.gas   = 55;
  payload.door  = 66;
  payload.hkey  = random(1000, 9999);
  payload.test  = 112;

  // starts counting
  unsigned long elapsed = 0;
  unsigned long start = millis();
  Serial.println(payload.hkey);

  // sends packet
  rf24Net.update();
  RF24NetworkHeader header(other_node);
  bool ok = rf24Net.write( header, &payload, sizeof(payload) );
  if (ok) {
    unsigned long finish = millis();
    elapsed = finish - start;
    Serial.println("ok.");
    Serial.print(elapsed);
    Serial.print("ms\n");
    rf24Net.update();

    while ( rf24Net.available() )
    {
      Serial.println("Received packet");
      RF24NetworkHeader header2;
      //rf24Net.peek(header2);
      data_received confirm;
      rf24Net.read(header2, &confirm, sizeof(confirm));
      Serial.println(confirm.hkey);
      Serial.println("------------------------------");
      delay(2000);
    }
  }
  else {
    Serial.println("failed.");
  }

  Serial.println("Sending data to base every 2 sec.");
  //radio.startListening();
  delay(2000);
}

base

//
//
// hypernet base A 1.1
//
//

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

//////////////////////////////////////
// Create the structures for data
//////////////////////////////////////
struct data_received{
  unsigned node;
  unsigned temp;
  unsigned humi;
  unsigned light;
  unsigned gas;
  unsigned door;
  unsigned hkey;
  unsigned test;
};

struct data_to_send {
  unsigned hkey = 0;
}confirm;

//////////////////////////////////////
// Setup nRF24L01+ module
//////////////////////////////////////
RF24 radio(7,8);
RF24Network rf24Net(radio);
const uint64_t this_node  = 00; // base
const uint64_t other_node = 01; // node A

//////////////////////////////////////
// setup
//////////////////////////////////////
void setup(void) {

  // Initialize interfaces
  printf_begin();
  Serial.begin(9600);
  Serial.print(F("Starting interfaces..."));
  SPI.begin();
  radio.begin();
  Serial.print(F("complete]\n"));
  rf24Net.begin(90, this_node);
  radio.setDataRate(RF24_250KBPS);
  radio.printDetails();
}

//////////////////////////////////////
// loop
//////////////////////////////////////
void loop() {
  // main layer loop
  rf24Net.update();

  // listen for incoming clients
  while ( rf24Net.available() )
    {
      RF24NetworkHeader header;
      confirm.hkey = 0;

      // read the next available header
      //rf24Net.peek(header);

      // print NRF24 header data
      String rf24header = "\n[header info => id: "
                        + String(header.id) + " type: "
                        + header.type + " from_node: "
                        + header.from_node +"]";
      Serial.println(rf24header);

      // read data
      data_received payload;
      rf24Net.read( header, &payload, sizeof(payload) );

      // Print data received
      String dataPrint = "[NODE: "  + String(payload.node) +" ]=>  "
                       + "[temp: "  + String(payload.temp) + "*C] "
                       + "[humi: "  + String((float)payload.humi,2) + "%] "
                       + "[light: " + String((float)payload.light,2) + "%] "
                       + "[gas: "   + String(payload.gas) + "%] "
                       + "[door: "  + String(payload.door) + "] "
                       + "[hkey: "  + String(payload.hkey) + "] "
                       + "[test: "  + String(payload.test) + "] ";
      Serial.println(dataPrint);

      // send back data to confirm integrity
      confirm.hkey = payload.hkey;
      Serial.println("...");
      RF24NetworkHeader header2(header.from_node);
      delay(100);
      bool sent_back = rf24Net.write( header2, &confirm, sizeof(confirm));

      if (sent_back == true){
        Serial.print(confirm.hkey);
        Serial.print(F(" - Confirmed back \n"));
        delay(2000);
      }
      else{
        Serial.print(F("Not confirmed"));
        delay(2000);
      }
      rf24Net.update();
    }

    // give it time to receive the data
    delay(100);
    Serial.println("Listening for nodes..");

}

Please shed a little light !

Looks like only a couple minor things:

a: Node A is not waiting for a response, so the response will only get picked up on the next send
b: With RF24Network, delays are bad, always try to use timers/millis() instead. The code below keeps network.available() outside of the sending code, so any received payloads are picked up, regardless of whether a packet was sent immediatly prior.

Old Process

  1. network update()
  2. send payload
  3. If payload sent, check immediately, only once for a received payload
  4. Wait 2 seconds (during this time, the payload is received by the radio)
  5. network.update() (loads previously requested payload into user cache)

New Process:

  1. network.update() ( Load payloads into user cache, routing, etc )
  2. Only send if 2seconds has passed since last send
  3. Check for received payloads, goto 1
//
//
// hypernet node A 1.1
//
//

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

//////////////////////////////////////
// Create the structures for data
//////////////////////////////////////
struct data_to_send {
  unsigned node;
  unsigned temp;
  unsigned humi;
  unsigned light;
  unsigned gas;
  unsigned door;
  unsigned hkey;
  unsigned test;
};

struct data_received {
  unsigned hkey = 0;
};

//////////////////////////////////////
// Setup nRF24L01+ module
//////////////////////////////////////
RF24 radio(8,7);
RF24Network rf24Net(radio);
const uint64_t this_node =  01; // node A
const uint64_t other_node = 00; // base

//////////////////////////////////////
// setup
//////////////////////////////////////
void setup(void) {

  // Initialize interfaces
  printf_begin();
  Serial.begin(9600);
  Serial.print(F("Starting interfaces..."));
  SPI.begin();
  radio.begin();
  Serial.print(F("complete]\n"));
  rf24Net.begin(90, this_node);
  radio.setDataRate(RF24_250KBPS);
  radio.printDetails();
}

//////////////////////////////////////
// loop
//////////////////////////////////////
uint32_t txTimer = 0;

void loop(void)
{

  rf24Net.update();

  if (millis() - txTimer > 2000) {
    data_to_send payload;
    payload.node  = 1;
    payload.temp  = 22;
    payload.humi  = 33;
    payload.light = 44;
    payload.gas   = 55;
    payload.door  = 66;
    payload.hkey  = random(1000, 9999);
    payload.test  = 112;

    // starts counting
    unsigned long elapsed = 0;
    unsigned long start = millis();
    Serial.println(payload.hkey);

    // sends packet

    RF24NetworkHeader header(other_node);

    Serial.println("Sending data to base every 2 sec.");
    txTimer = millis();
    bool ok = rf24Net.write( header, &payload, sizeof(payload) );
    if (ok) {
      unsigned long finish = millis();
      elapsed = finish - start;
      Serial.println("ok.");
      Serial.print(elapsed);
      Serial.print("ms\n");
      rf24Net.update();
    }
    else {
      Serial.println("failed.");
    }
  }

  while ( rf24Net.available() )
  {
    Serial.println("Received packet");
    RF24NetworkHeader header2;
    //rf24Net.peek(header2);
    data_received confirm;
    rf24Net.read(header2, &confirm, sizeof(confirm));
    Serial.println(confirm.hkey);
    Serial.println("------------------------------");
    delay(2000);
  }

}

Thanks for the reply and your useful fork of NRF24 library !

Do you think that the base has to do anything with this ? Also, do you believe .peek() is necessary for any of them ? I didn't witness any change after removing it.

hyp3rkyd:
Do you think that the base has to do anything with this ?

Not really, but replacing/removing delays will improve things.

hyp3rkyd:
Also, do you believe .peek() is necessary for any of them ? I didn't witness any change after removing it.

.peek() has specific uses. It returns the msg size and next available header. See network.peek

In my case, don't we need the next available header?

That depends on your definition of the word 'need'. :smiling_imp:

.peek() functions generally all perform similar functions. See http://arduino.cc/en/Serial/Peek

Do you need the header or the size before calling network.read()? If not then no, else yes.

Thanks for the solution, it worked OK! I just got home from work and uploaded - everything looks fine.

I can't say I understand it 100% but I'll go through the code once again and find out why this worked.

Where do you think it's sane to powerDown and powerUp ?

Just about anywhere.

Hi,

I find your project very interesting! I haven't understood how to use the modules sending and receiving feedback at the same device and your sketches helped me now. I'm wondering if you have maybe a newer version with some changes you maybe made (deleting delay, powerdown..) ?

Anyway, thanks a lot :slight_smile: