Go Down

Topic: Weird things happens with nRF24L01+ when network.write() returns fail (Read 183 times) previous topic - next topic

adamzxtan

I'm working on a sensor project that requires two way communication between the master and slave. The network consist of 1 master, and 6 slave devices (01, 02, 03, 04, 05, 014). The master node is just a display panel with some LEDs on it, while the sensor has IR sensor and a LED ring on it. At the start of the program, one of the sensor's LED ring will lights up and the person will need to go disable LED by waving on it. The sensor will send another message back to master to signify the action is complete. Then the master will randomly send another dummy message to other sensor node, and the LED ring on other sensor will light up when received message.

So far, I've been able to get the sensor network to work nicely, but it keeps on having a random "glitch" in my system.

The glitch is whenever the master device fails to send a dummy message to the desired sensor node, the sensor that was failed to send to the first time, will receive the signal from the master when the master sends a dummy message to other node.

Ex: Master(00) fail send to Node(014), then randomize to send dummy message to Node(04). When Master successfully send message to Node(04), Node (014) lights up at the same time with Node (04)

This problem happens very randomly, and I'm really puzzled with the cause of it. It feels like the FIFO is filled with an ACK package from the first failed send, and the initial failed sent ACK package is sent out on the next attempt to send message to other node. I even tried inserting radio.flush_tx() whenever the network.write() return fail, but it doesn't seem to work. I'm not sure if I'm right, its just a hunch anyway.

As for the nRF24 hardware, I've done the initial RF24 examples code checking with it. The hardware didn't had any issue with the RF24 examples, so I'm sure I'm using genuine nRF24L01+ chip, with PA/LNA.

To help everyone better understand my situation, here's the code for the master:
Code: [Select]
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <RF24Network.h>
#include <RF24Network_config.h>

#define MASTER_NODE 00
//#define SERIAL_DEBUG

RF24 radio(7, 8); //start nrf24l01+ with CE = 7, CS = 8
RF24Network network(radio); //create RF24Network using radio

const uint16_t node_addr_list[] = {01, 02, 03, 04, 05, 014}; //create a list of child node, in OCT format
uint8_t ledPin[] = {9, 10, 4, A0, 5, A1};  //pins for led indicators on display panel
int totalLightCount = 0;
bool isReturnMessageReceived = false;

void setup() {
  //Initializing the led pins
  for (int i = 0; i < 6; i++) {
    pinMode(ledPin[i], OUTPUT); //setup for the led pins on the display panel
    digitalWrite(ledPin[i], LOW); //make sure all led are switched off
  }

  //Initialize the RF24Network for the master node
  SPI.begin();
  radio.begin();  // Bring up the RF network
  radio.setPALevel(RF24_PA_MAX);
  radio.setDataRate(RF24_1MBPS);
  network.begin(/*channel*/ 100, /*node address*/ MASTER_NODE );

  randomSeed(analogRead(A6));   //make sure when system restarts will generate different random number
}

void loop() {
  while (totalLightCount < 20) {
    //Program starts here
    network.update();
    byte n = random(6);        // generate a random number between 0 to 5
    unsigned long time = 1000;
    RF24NetworkHeader header_t(node_addr_list[n], /*Msg type*/ 'N');  //prepare the message header to be sent to a child node
    bool ok = network.write(header_t, &time, sizeof(time));  //send the timing to the child node

    //This is a redundancy routine to brute force sending signal in case the first sending attempt returns fail
    //It is to prevent double-light issue due to sending fail from master node
    int counter = 0;
    while (ok != true && counter < 2) {
      ok = network.write(header_t, &time, sizeof(time));
      counter++;
    }

    if (ok) {
      digitalWrite(ledPin[n], HIGH); //switch on respective light

      // Wait to get return signal from the respective slave node
      while (isReturnMessageReceived != true) {
        network.update();

        if (network.available()) {
          unsigned long r;
          RF24NetworkHeader header_r;
          network.read(header_r, &r, sizeof(r));
          if (header_r.from_node == node_addr_list[n]) {
            isReturnMessageReceived = true;
          }
        }
      }
      //once condition in the while loop is fulfilled
      isReturnMessageReceived = false;    //Reset the message flag for the next loop
      digitalWrite(ledPin[n], LOW);  //switch off respective led light

      totalLightCount++;    //increase total light count
      delay(time); //edit delay time to change the blinking frequency
    }
    else {
      radio.flush_tx();   //empty the transmit buffer
      radio.flush_rx();
    }
  }
}//END OF PROGRAM


And here's the code for the sensor node:
Code: [Select]
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <RF24Network.h>
#include <RF24Network_config.h>

#define PIN_DETECT 2  //IR Receiver pin

RF24 radio(7, 8); // nRF24L01(+) radio attached, with CE = pin 7, CS = pin 8

RF24Network network(radio);      // Network uses that radio
const int node_addr_list[] = {01, 02, 03, 04, 05, 014}; //create a list of child node, in OCT format
int ledLight = 10;

// Address of this child node, change this to select from the node address list matrix
const int this_node = 0;    //change this whie loading the program for each node according to numbers

void setup() {
  pinMode(PIN_DETECT, INPUT);   //for IR sensor detection
  pinMode(ledLight, OUTPUT);

  SPI.begin();
  radio.begin();
  radio.setPALevel(RF24_PA_MAX);
  radio.setDataRate(RF24_1MBPS);
  network.begin(/*channel*/ 100, /*node address*/ node_addr_list[this_node]);

  //flash the LED to signal the device is ready
  digitalWrite(ledLight, HIGH);
  delay(1000);
  digitalWrite(ledLight, LOW);
  delay(1000);
}

void loop() {
  network.update(); // Check the network regularly

  while (network.available()) {     // Is there anything ready for us?
    //Serial.println("Received packet!");
    RF24NetworkHeader header;        // If so, grab it and print it out
    network.peek(header);

    switch (header.type) {
      case 'N':
        handle_N(header);
        break;
    }
  }
}//END OF PROGRAM


/********************************************************************************************************
   Handles Mode 2: Sprinting mode message
 ********************************************************************************************************/
void handle_N(RF24NetworkHeader& header) {
  unsigned long timeOut;   //the timing message received is from host's user raw timing input in "s"
  network.read(header, &timeOut, sizeof(timeOut));  //load the timing into payload variable

  digitalWrite(ledLight, HIGH); //switch on the lights
  unsigned long startTime = millis();
  unsigned long elapsedTime = 0;

  //wait for user input to trigger the sensor or wait for master message to escape the loop
  while (elapsedTime <= timeOut) {
    network.update();
    elapsedTime = millis() - startTime;

    if (digitalRead(PIN_DETECT) == LOW) {
      digitalWrite(ledLight, LOW);  //switch off led when detected user input
    }
  }
  digitalWrite(ledLight, LOW);  //switch off led when time out

  //send signal back to master to signify action complete
  RF24NetworkHeader header_master(00);   //send back msg for acknowledgement
  bool ok = network.write(header_master, &timeOut, sizeof(timeOut));

  //If sending signal back to master fails, repeat transmission until success or reaching counter limit
  int counter = 0;
  while (ok != true && counter < 15) {
    ok = network.write(header_master, &timeOut, sizeof(timeOut));
    counter++;
    delayMicroseconds(50);
  }
}


So after reading through such a long story and code, anyone has any idea what I'm missing here?

Robin2

I have never used the Network library with an nRF24 and if you really need it then I cannot help.

If all of the slaves are within range of the master then you probably do not need it.

...R
Simple nRF24L01+ Tutorial
Two or three hours spent thinking and reading documentation solves most programming problems.

adamzxtan

Hi Robin,

Thanks for your reply. Can the RF24 library create a star network with 2 way communication? I haven't really deep dive on that yet, been using RF24Network since the beginning of the project.

One thing that puzzles me a lot on the RF24 library is the pipe and address setting, which is why i chose to use RF24Network considering it has been handle by the library. Guess right now I really have to try and understand it.

Robin2

One thing that puzzles me a lot on the RF24 library is the pipe and address setting,
The idea of pipes can be a bit confusing. Think of them as 6 shelves onto which the mail for different residents in an apartment block can be placed. All the letters come through the same mail slot (the radio receiver listening on Channel N) and when they fall on the floor someone picks them up, looks at the name of the recipient (the address the message was sent to) and puts them on the correct shelf (the pipe that has been assigned the same address as the message) or shreds them if they are for a recipient who lives in another block (i.e. if they are for an address that is not assigned to any of the pipes on this nRF24)


If all the slaves are within range of the master then IMHO the simplest thing is for the master to call each slave in turn. There is no need for more than 1 pipe (no matter how many slaves). Each slave has its own address. This assumes the slaves are listening all the time.

My Tutorial includes an example for a master and 2 slaves that can easily be extended to a larger number of slaves.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

adamzxtan

Hmm, I think I will have to study your tutorial first for 1 master, multi slaves on same pipe. That concept is really new to me, considering in my application situation, all slaves is within the range of master. I'll get back to you on this :)

BTW, will there be an upper limit for the number of slaves on the same pipe? Seems abit unreal for me for one to assume that there can be like 1000 slaves connected to only 1 master using just 1 pipe.

Robin2

Hmm, I think I will have to study your tutorial first for 1 master, multi slaves on same pipe. That concept is really new to me, considering in my application situation, all slaves is within the range of master. I'll get back to you on this :)

BTW, will there be an upper limit for the number of slaves on the same pipe? Seems abit unreal for me for one to assume that there can be like 1000 slaves connected to only 1 master using just 1 pipe.
I don't really understand how you find that strange - I doubt that you imagine that all 1000 messages can be stored in the nRF24 until the Arduino feels like reading them. The messages are each read as they are received.

The limit will be the time taken to poll NN slaves and deal with the responses within the required time frame. The time to communicate with a slave will be much the same no matter how many pipes you use.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Whandall

For a couple of modules polling can make sense but not for a big number of clients,
or for clients that want to sleep most of the time.

Clients can reach an always listening 'master' with ACK on a single pipe, without being polled.
(Ack payload only makes sense on that pipe if all clients expect the same data format obviously.)

The nodes don't fire blindly destroying ongoing traffic,
they wait for idle on the medium before starting to send.

Shure, if two (ore more) modules wait for the same idle there can be a collision,
but there is an internal multiple retry functionality and the software could retry after that fails.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

Go Up