NRF2401 Multiple pip (How to monitor if one is missing)

Hi Group,

Remember in your answers that I only start coding in general and play with Arduino
since this summer so I am new at this but with your help I will get better :slight_smile:

Project

I have two NRF2401 acting as transmitter. They both have an ultrasonic sensor and a flow sensor. Each transmitter will monitor the water lever of a water tank and the input flow that fill that tank.

Each NRF2401 is sending is data to the same NRF2401 acting as a receiver, each of them using a different pip.

All this is working for now, the receiver is receiving each pip and print the values on an LCD 16X4.

The first transmitter has the sensors installed but the second transmitter is sending fixed values
until I'm ready with the general concept.

For now and for the test purpose, sending the data from two TX to One RX is ok.

Monitoring The Signal

I need to find a way to monitor if I'm receiving the signal from the first, the second or both transmitters.
So if I loose the signal from on eof them or both, my LCD screen will become blank or print Lost signal.

The way the code is done, I can see the following on the serial monitor of the receiver

Data on pip = 1 Got data size=12 data = folowing by my value
Data on pip = 2 Got data size=12 data = folowing by my value
Data on pip = 1 Got data size=12 data = folowing by my value
Data on pip = 2 Got data size=12 data = folowing by my value
Data on pip = 1 Got data size=12 data = folowing by my value
Data on pip = 2 Got data size=12 data = folowing by my value

and so on..

Maybe

If there is a way to recognize from which TX the signal is coming from tell me how so I can
create an (if) condition with it.

BUT

It it's impossible to monitor the different signal, maybe I can create a condition to see (pip =1) and or (pip=2).

I did that but since I'm receiving (pip =1) then ( pip =2) one after the other, it's making
my LCD flashing all the time and it's not nice.

I told myself that maybe I can create a boolean value to store true in the boolean pip1 when pip = 1 and then store true in pip2 when pip =2. I need to keep that value for 3 secondes so if within that 3 seconds, the pip = 1 and pip =2 are still sending, it will keep the true condition in both boolean pip1 and pip2. So i just have to create a condition to see if pip1 and or pip2 is or are true. it will prevent the conditon to change at each transmission and so keep my LCD to flash all the time.

I really don't know if I'm on the right direction to reach my goal by I wanted to tell you what I tried so you can help me better.

See my code

//the NRF2401 code section is from sew-dude Post on july 2016 on the Arduino forum 

//Multiple Pip receiver

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

#include "LCD.h"
#include "LiquidCrystal_I2C.h"

#define lenght 16.0
double percent=100;
unsigned char b;
unsigned int peace;

unsigned long previousMillis = 0;
const long interval = 3000;

boolean pip1 = false;
boolean pip2 = false;


//****************************************Initialize for Receiver

RF24 radio (8, 10);
#define PLOAD_WIDTH  32  // 32 unsigned chars TX payload
byte pip;
byte pload_width_now;
byte newdata;
unsigned char rx_buf[PLOAD_WIDTH]= {0};

struct dataStruct1{
float p1;
float t1;
float s1; 
}transmitter1_data;

struct dataStruct2{
float p1;
float t1;
float s1; 
}transmitter2_data;

unsigned char ADDRESS2[1]= {0xb2};  
unsigned char ADDRESS3[1]= {0xb3};  
unsigned char ADDRESS4[1]= {0xb4};  
unsigned char ADDRESS5[1]= {0xb5};  

unsigned char ADDRESS1[5]  = 
{
   0xb1,0x43,0x88,0x99,0x45
}; // Define a static TX address

unsigned char ADDRESS0[5]  = 
{
  0xb0,0x43,0x88,0x99,0x45
}; // Define a static TX address

//****************************************END Receiver

LiquidCrystal_I2C lcd_3(0x23,2,1,0,4,5,6,7);

void setup(){

 //****************************************Setup Receiver
   radio.begin();
   printf_begin();
   Serial.begin(115200);
   radio.setDataRate(RF24_250KBPS);
   radio.enableDynamicPayloads();
   radio.openWritingPipe(ADDRESS0);
   radio.openReadingPipe(0,ADDRESS0);
   radio.openReadingPipe(1,ADDRESS1);
   radio.openReadingPipe(2,ADDRESS2);
   radio.openReadingPipe(3,ADDRESS3);
   radio.openReadingPipe(4,ADDRESS4);
   radio.openReadingPipe(5,ADDRESS5);

   radio.startListening();
   radio.printDetails();

//****************************************END Setup Receiver

   lcd_3.begin (16,4); // 16 x 4 LCD module
   lcd_3.setBacklightPin(3,POSITIVE);
   lcd_3.setBacklight(HIGH);


}

//**************************************** void Receiver

void Receiver_1(){

 if ( radio.available(&pip) ){

      // Fetch the payload, and see if this was the last one.
      pload_width_now = radio.getDynamicPayloadSize();

      // If a corrupt dynamic payload is received, it will be flushed
      if(!pload_width_now){   
      }
      else
      {
       
      radio.read( rx_buf, pload_width_now );

      newdata=1;

      Serial.print(F("Data on pip= "));
      Serial.print(pip);
      Serial.print(F(" Got data size="));
      Serial.print(pload_width_now);
      Serial.print(F(" data="));
      for(byte i=0; i<pload_width_now; i++)
      {
      Serial.print(" ");
      Serial.print(rx_buf[i]); // print rx_buf
      }
      Serial.print(" ");
      }
    }
   
if(newdata==1){
   newdata=0;

if(pip==1&&pload_width_now==sizeof(transmitter1_data)){
  
    memcpy(&transmitter1_data, rx_buf, sizeof(transmitter1_data)); 
          
    Serial.print(" Distance, Percent, Flow ");
    Serial.print(transmitter1_data.p1);
    Serial.print(" , ");
    Serial.print(transmitter1_data.t1);
    Serial.print(" , ");
    Serial.print(transmitter1_data.s1);    
             
        lcd_3.setCursor(0,0);
        lcd_3.print(transmitter1_data.p1, 0);
        lcd_3.print(F("cm "));

        lcd_3.setCursor(6,0);
        lcd_3.print(percent, 0);
        lcd_3.print(F("% "));

        lcd_3.setCursor(11,0);
        lcd_3.print(transmitter1_data.s1, 0);
        lcd_3.print(F("l/m "));
      
   }
   
if(pip==2&&pload_width_now==sizeof(transmitter2_data)){
  
    memcpy(&transmitter2_data, rx_buf, sizeof(transmitter2_data)); 
          
    Serial.print(" Distance, Percent, Flow ");
    Serial.print(transmitter2_data.p1);
    Serial.print(" , ");
    Serial.print(transmitter2_data.t1);
    Serial.print(" , ");
    Serial.print(transmitter2_data.s1);

       lcd_3.setCursor(0,2);
       lcd_3.print(transmitter2_data.p1, 0);
       lcd_3.print(F("cm "));

       lcd_3.setCursor(6,2);
       lcd_3.print(transmitter2_data.t1, 0);
       lcd_3.print(F("% "));

       lcd_3.setCursor(11,2);
       lcd_3.print(transmitter2_data.s1, 0);
       lcd_3.print(F("l/m "));
       }
       Serial.println("");
  }
}

//********************************************That's the section I'm talking about

void LostRfSignal(){

unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= interval){ //interval = 3000 millis

    if (pip == 1){
      pip1 = true; // true for pip1 should stay in memory for 3000 millis
    }else{
      pip1 = false;
    }

    if (pip == 2){
      pip2 = true; // true for pip2 should stay in memory for 3000 millis
    }else { 
      pip2 = false;    
    }
    previousMillis = currentMillis;
    } 
    
      //during the 3000 Millis, the next two (IF) should have the time to
      //see if pip1 and/or pip2 are true or false
    
      if(pip1 == true){ //do nothing
        
      }else{ // it will erase the line 0 and 1 on LCD
        
        lcd_3.setCursor(0, 0);  
        lcd_3.print(F("                "));
        lcd_3.setCursor(0, 1);
        lcd_3.print(F("                "));
      }
    
      if(pip2 == true){ //do nothing
  
      }else{  // it will erase the line 2 and 3 on LCD
        lcd_3.setCursor(0, 2);  
        lcd_3.print(F("                "));
        lcd_3.setCursor(0, 3);
        lcd_3.print(F("                "));
      } 

} //********************************************END of the section I'm talking about



void loop(){
  
  Receiver_1();
  LostRfSignal();
  ProgressBar_1();

  delay(100);

}

You have not posted the code from the transmiitters but it looks like each transmitter sends its data to a different address on the receiver. The receiver will put the message into the pipe associated with that address. So if you take data from a particular pipe you will know which receiver it came from.

An additional strategy (but probably not necessary) is to include in each message the ID (a number like 1, 2 or 3 or a letter like A, B or C) that identifies the sender.

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)

...R
Simple nRF24L01+ Tutorial

Hi Robin 2,

I know where the data is coming from and it works. The receiver is printing
the data from each pip to the right line on my LCD, noo problem with that.

The problem is that I want to monitor if one of the transmitter stop transmitting.

hddforensic:
The problem is that I want to monitor if one of the transmitter stop transmitting.

Keeping timestamps of the last receptions and comparing their distance to the current time to some limit seems pretty obvious.

Hi Whandall,

How can I do that ? Because I have no clue.

If you don't have time maybe you can point to an example so I can work on it.

Thanks

unsigned long lastPacket[6];

//....

  if (radio.available(&pip)){
    lastPacket[pip] = millis();

//...

  if (millis() - lastPacket[1] >= 5000) {
    Serial.println(F("5 seconds no message on pipe 1"));

//...

Hi Whandall,

Sorry for now I don't know enough Arduino to use your example.

I will look for lost signal with NRF24L01 on the net.

Programming is not collecting and copying code.

Learn at least some C++, there are millions of tutorials out there.

hddforensic:
Sorry for now I don't know enough Arduino to use your example.

It would be difficult to make his example any simpler.

Record the time when a message is received then regularly check how much time has elapsed since the previous message with something like

for (n = 0; n < numSlaves; n++) {
  if (millis() - lastPacket[n] >= maxIntervalMillis) {
      Serial.print("No message from slave ");
      Serial.println(n);
  }
}

...R

Hi Whandall,

I'm not programming I'm learning.

Collecting and copying code to create project is a good way to learn for me.

Last June I needed a five minutes timer to autoshutoff of a motor.

I took a capacitor, a transistor and a resistor to make it and it work fine.

One Month after I decided to buy my first Arduino and last week I modified
a library in order to install two ultrasonic sensors on the same arduino.

A few project later I know that I still have a lot to learn and I will.

Asking questions, trying codes, modifying them to fit my needs and apply all
that to real project, this is the way I do it.

Tutorials are very goods but at the beginning I don't even know what to
look for.

Anyway all this to say, don't worry I'm not pretending that I'm a programmer :slight_smile:
but I'm working on it.

Hi Robin 2,

I don't understand yet where to take numSlaves and lastPacket
and I will read about [n] because I don't know what append when you
put a value between [ ] but I will work on your example and find out.

This afternoon I tried something. Every time the NRF2401 receive
data from pip1 and then pip2 I can use that. I decide to count the
pip and send the value to compare after if the value increase or not.

I probably took the highway for something that could be done more simple
but it is working.

This section is increasing every time I received pip 1.
I put a limit of 100 because I didn't want the code to count
forever.

  if (pip==1) {
     D++;
     Serial.print("Pip_1 = "); //print for debug
     Serial.println(D);        //print for debug
     if (D==100){
     D = 0;
     }
     }

The next section is waiting 5 seconds and then check if the value increase at least
of 1. if it't not, it print spaces on my LCD to erase the line where the data is written
for that pip.

     currentD = D;

unsigned long currentMillis_1 = millis();

if (currentMillis_1 - previousMillis_1 >= interval_1){ //interval_1 = 5000 millis
     
if (currentD - previousD <= 1) {
      previousD = 0;
      lcd_3.setCursor(0, 0);
      lcd_3.print(F("               "));
      
      D = 0;
      }

      previousD = currentD;
     
      previousMillis_1 = currentMillis_1;
}
}

It's working nice and I can see if I loose signal from pip 1, pip 2 or both.

The only thing weird is when I loose both signal, the last pip I loose will
continue counting until 100 even if the pip is not there anymore but when it
reach 100, the condition is reach and i can see that I lost the signal of that pip.

I will probably find another way but for now I need to go further with other section
of this project and I will make the correction after I finish with the hardware.

But I promise you that I will see how to use your example.

hddforensic:
I don't understand yet where to take numSlaves and lastPacket

The idea is that you create a variable that holds the number of slaves and an array that holds the millis() values for when the last packet (the most recent packet) was received from each slave.

...R

Hi Robin2

I understand the logic first time I saw the example but I just don't know how to make
it in code (syntax etc etc) So that's why I will start from what you said and read more
about it and find how.

For now it's working the way I did it and since I'm limited in the time, I will continue
the project with the harware and builting the housing for it because I need to install
this in a month and I'm working on it only part time.

The project is to monitor the flow of water that fills the tank and also the level of the
water inside two tanks in a kid shelter in Haiti. I'm taking care of that place since
2014.