add faisafe to rx with nrf24l01

Hello,i have make this rx for small rc car.It work well.Now i need to add a failsafe that stop the motor if the nrf24l01 lost signal with tx.Can you help me to add it?I don't know how i can implement it on rx.I enclose the code.Thanks for you help!Ivan

//Ricevitore 2.4ghz per automodello proporzionale.Autore:Ivan Pepe-(Giugno 2016)-Versione 1
//Aggiunto potenziometro digitale 64 step;
//H-bridge -avanti 100%-indietro 60%
//Aggiunta uscita accensione fari anteriori.
//Aggiunte luci Freno;
//Aggiunte luci Fari;
//Aggiungere reverse servo???
//Collegamenti del modulo RF24L01 ad Arduino:
// 1 - GND
// 2 - VCC 3.3V !!! NOT 5V
// 3 - CE to Arduino pin 9
// 4 - CSN to Arduino pin 10
// 5 - SCK to Arduino pin 13
// 6 - MOSI to Arduino pin 11
// 7 - MISO to Arduino pin 12
// 8 - UNUSED

#include <HCMotor.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>

int r; int y; int n;
Servo servo;
/* Pins used to drive the motors */
#define MOTOR_PINA 5
#define MOTOR_PINB 6
#define DEADZONE 20
#define POT_REV_MIN 0
#define POT_REV_MAX (250 - DEADZONE)
#define POT_FWD_MIN (251 + DEADZONE)
#define POT_FWD_MAX 510

#define LuciFreno 4

//FARI
#define LED 3          // Led collegato al pin digitale 3
int val = 0;           // Si userà val per conservare lo stato del pin di input
int vecchio_val = 0;   //Si userà vecchio_val per conservare lo stato del pin di input al passo precedente
int stato = 0;         //Ricorda lo stato in cui si trova il led,stato =0 led spento,stato =1 led acceso;


#define CE_PIN   9
#define CSN_PIN 10
/* Create an instance of the library */
HCMotor HCMotor;

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


RF24 radio(CE_PIN, CSN_PIN);

int joystick[3];

void setup(void)
{
  /* Initialise the library */
  HCMotor.Init();
  HCMotor.attach(0, DCMOTOR_H_BRIDGE, MOTOR_PINA, MOTOR_PINB);
  HCMotor.DutyCycle(0, 100);
  Serial.begin(9600);
  delay (1000);
  Serial.println("Nrf24L01 Receiver Starting");
  radio.begin();
  radio.setChannel(80);
  radio.setDataRate(RF24_2MBPS);
  //radio.setDataRate(RF24_1MBPS);
  //radio.setDataRate(RF24_250KBPS);
  // optionally, increase the delay between retries & # of retries
  radio.setRetries(12, 12);
  // optionally, reduce the payload size.  seems to
  // improve reliability
  radio.setPayloadSize(5);
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1, pipes[0]);
  radio.startListening();

  servo.attach(2);
  pinMode(3, OUTPUT);
  pinMode(LuciFreno, OUTPUT);
}

void receiveOrder()

{
  if ( radio.available() )
  {
   bool done = false;
   // while (!done)
    {

      // Fetch the payload, and see if this was the last one.
      //radio.read( &message, sizeof(unsigned long) );
      // Fetch the payload, and see if this was the last one.
      radio.read( joystick, sizeof(joystick) );
     

      servo.write(joystick[0]);
      Serial.print("X = ");
      Serial.print(joystick[0]);
      int Speed, Pot;
      Pot = joystick[1];
      /* Is the pot in the reverse position ? */
      if (Pot >= POT_REV_MIN && Pot <= POT_REV_MAX)
      {
        HCMotor.Direction(0, REVERSE);
        Speed = map(Pot, POT_REV_MIN, POT_REV_MAX, 60, 10);

        /* Is the pot in the forward position ? */
      } else if (Pot >= POT_FWD_MIN && Pot <= POT_FWD_MAX)
      {
        HCMotor.Direction(0, FORWARD);
        Speed = map(Pot, POT_FWD_MIN, POT_FWD_MAX, 0, 100);

        /* Is the pot in the dead zone ? */
      } else
      {
        Speed = 0;
      }

      /* Set the on time of the duty cycle to match the position of the pot. */
      HCMotor.OnTime(0, Speed);

      if   ((Pot >= 170) && (Pot <= 245) )
      {
        digitalWrite(LuciFreno, HIGH);

      }
      else
      {
        digitalWrite(LuciFreno, LOW);

      }

      Serial.print("    Y = ");
      Serial.print(joystick[1]);

      Serial.print("    z = ");
      Serial.println(joystick[2]);

      val = joystick[2]; //legge il valore del pulsante sul joystick2
      //controlla se è accaduto qualcosa
      if ((val == HIGH) && (vecchio_val == LOW)) {
        stato = 1 - stato;
        delay(15); //attesa di 15 millisendi
      }

      vecchio_val = val; //ricordiamo il valore precedente di val

      if (stato == 1) {
        digitalWrite(3, HIGH); //accende il led
      }
      else {
        digitalWrite(3, LOW);//spegne il led
      }
         // First, stop listening so we can talk   
  radio.stopListening();

    // Send the final one back.
   radio.write( joystick, sizeof(joystick) );

  //Now, resume listening so we catch the next packets
   radio.startListening();
       }
     }
      
        else
  {
    Serial.println("No radio available");
    delay(50);
  }
}
  void loop(void)
{
  receiveOrder();
}

stop the motor if the nrf24l01 lost signal with tx

Is your Tx always talking to Rx even when there is nothing to say?

Every time you receive a message set a variable - for example lastReceivedMillis =millis()

Then in every iteration of loop() check if (millis() - lastReceivedMillis >= maxWaitMillis)

...R

Robin - that is my question indeed. If the Tx is not supposed to send a heartbeat then it's difficult to set the timeout in a meaningful way

J-M-L:
Robin - that is my question indeed. If the Tx is not supposed to send a heartbeat then it's difficult to set the timeout in a meaningful way

Yes, a regular message from the Tx was implicit in my Reply #2 and I should have made that clear. In my own model train project a message is sent every 100 millisecs even if it has the same data as the previous message.

...R

Good morning.I enclose also the code for tx.

//Telecomando 2.4ghz per modellismo.
//Collegamenti del modulo RF24L01 ad Arduino:
// 1 - GND
// 2 - VCC 3.3V !!! NOT 5V
// 3 - CE to Arduino pin 9
// 4 - CSN to Arduino pin 10
// 5 - SCK to Arduino pin 13
// 6 - MOSI to Arduino pin 11
// 7 - MISO to Arduino pin 12
// 8 - UNUSED


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

//Telemetria
// Led Pins
int red = 7;
int green = 6;

// Print battery voltage
// with Voltage Divider R1=22k R2=10k
#define Bled_pin 8

#define CE_PIN  9
#define CSN_PIN 10
#define JOYSTICK_X A1
#define JOYSTICK_Y A0
#define JOYSTICK_Z A2
int y;
int x;
int z;

// this is not the channel address, but the transmitter address
//const uint64_t pipe = 0xE8E8F0F0E1LL;

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

RF24 radio(CE_PIN, CSN_PIN);

int joystick[3];

void setup (void)
{
  pinMode(Bled_pin, OUTPUT);
  digitalWrite(Bled_pin, LOW);
  Serial.begin(9600);
  radio.begin();
  radio.setChannel(80);
  radio.setDataRate(RF24_2MBPS);
  //radio.setDataRate(RF24_1MBPS);
  //radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_MAX);
  // optionally, increase the delay between retries & # of retries
  radio.setRetries(12, 12);
  // optionally, reduce the payload size.  seems to
  // improve reliability
  radio.setPayloadSize(5);
  //radio.openWritingPipe(pipe);
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1, pipes[1]);

  radio.startListening();

  // Configure the LED
  pinMode(green, OUTPUT);
  pinMode(red, OUTPUT);
  digitalWrite(green, LOW);
  digitalWrite(red, LOW);

}


void sendOrder()
{
  {
  printVolts(); }

  x = analogRead(JOYSTICK_X);
  x = map(x , 0, 1023, 30, 150);
  joystick[0] = x;
  Serial.print("    ");
  Serial.print(x);

  y = analogRead(JOYSTICK_Y);
  y = map(y , 0, 1023, 0, 255 * 2);
  joystick[1] = y;
  Serial.print("    ");
  Serial.print(y);

  z = digitalRead(JOYSTICK_Z);
  joystick[2] = z;
  Serial.print("    ");
  Serial.print(z);

  // First, stop listening so we can talk.
  radio.stopListening();

  // Take the time, and send it.  This will block until complete
  radio.write( &joystick, sizeof(joystick) );//  radio.write (joystick, sizeof(joystick) );

  // Now, continue listening
  radio.startListening();

  // Wait here until we get a response, or timeout (10ms)
  unsigned long started_waiting_at = millis();
  bool timeout = false;
  while ( ! radio.available() && ! timeout )
    if (millis() - started_waiting_at > 35 )
      timeout = true;

  // Describe the results
  if ( timeout )
  {
    // At this point the ACK did not arrived so the red LED has to be on
    digitalWrite(green, LOW);
    digitalWrite(red, HIGH);
  }
  else
  {
    // Grab the response, compare, and send to debugging spew
    unsigned long response;
    radio.read( &response, sizeof(unsigned long) );

    // At this point the ACK did arrived so the green LED has to be on
    digitalWrite(green, HIGH);
    digitalWrite(red, LOW);
  }

}
void printVolts()
{
  int sensorValue = analogRead(A3); //read the A3 pin value
  float voltage = sensorValue * (2.3 / 1023.00) * 2; //convert the value to a true voltage.//2.3
  if (voltage < 4.5 ) //set the voltage considered low battery here//4.2
  {
    digitalWrite(Bled_pin, HIGH);
  }

}
void loop(void)
{
  sendOrder();

}

OK so you do send 6 bytes very often, so the proposal from Robin will work for you.

Basically if you don't get something for - say 0.2 second - then you definitely have something wrong happening.

There is an interrupt system also available on many NRF24 but this seems to not work too well. So the time-out is probably the easiest way to do what you want.

Hello I have make the change but the failsafe don't work.Can you help me on solve the problem?Thanks

//Ricevitore 2.4ghz per automodello proporzionale.Autore:Ivan Pepe-(Giugno 2016)-Versione 1
//Aggiunto potenziometro digitale 64 step;
//H-bridge -avanti 100%-indietro 60%
//Aggiunta uscita accensione fari anteriori.
//Aggiunte luci Freno;
//Aggiunte luci Fari;
//Aggiungere reverse servo???
//Collegamenti del modulo RF24L01 ad Arduino:
// 1 - GND
// 2 - VCC 3.3V !!! NOT 5V
// 3 - CE to Arduino pin 9
// 4 - CSN to Arduino pin 10
// 5 - SCK to Arduino pin 13
// 6 - MOSI to Arduino pin 11
// 7 - MISO to Arduino pin 12
// 8 - UNUSED

#include <HCMotor.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>

int r; int y; int n;
Servo servo;
/* Pins used to drive the motors */
#define MOTOR_PINA 5
#define MOTOR_PINB 6
#define DEADZONE 20
#define POT_REV_MIN 0
#define POT_REV_MAX (250 - DEADZONE)
#define POT_FWD_MIN (251 + DEADZONE)
#define POT_FWD_MAX 510

#define LuciFreno 4

//FARI
#define LED 3          // Led collegato al pin digitale 3
int val = 0;           // Si userà val per conservare lo stato del pin di input
int vecchio_val = 0;   //Si userà vecchio_val per conservare lo stato del pin di input al passo precedente
int stato = 0;         //Ricorda lo stato in cui si trova il led,stato =0 led spento,stato =1 led acceso;


#define CE_PIN   9
#define CSN_PIN 10
/* Create an instance of the library */
HCMotor HCMotor;

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


RF24 radio(CE_PIN, CSN_PIN);

int joystick[3];

void setup(void)
{
  /* Initialise the library */
  HCMotor.Init();
  HCMotor.attach(0, DCMOTOR_H_BRIDGE, MOTOR_PINA, MOTOR_PINB);
  HCMotor.DutyCycle(0, 100);
  Serial.begin(9600);
  delay (1000);
  Serial.println("Nrf24L01 Receiver Starting");
  radio.begin();
  radio.setChannel(80);
  radio.setDataRate(RF24_2MBPS);
  //radio.setDataRate(RF24_1MBPS);
  //radio.setDataRate(RF24_250KBPS);
  // optionally, increase the delay between retries & # of retries
  radio.setRetries(12, 12);
  // optionally, reduce the payload size.  seems to
  // improve reliability
  radio.setPayloadSize(5);
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1, pipes[0]);
  radio.startListening();

  servo.attach(2);
  pinMode(3, OUTPUT);
  pinMode(LuciFreno, OUTPUT);
}


void receiveOrder()
{
  static unsigned long lastRecvTime = 0;
  if ( radio.available() )
  {
    bool done = false;
    // while (!done)


    // Fetch the payload, and see if this was the last one.
    //radio.read( &message, sizeof(unsigned long) );
    // Fetch the payload, and see if this was the last one.
    radio.read( joystick, sizeof(joystick) );
    lastRecvTime = millis();
    if (millis() - lastRecvTime > 500) { // bring all servos to their middle position, if no RC signal is received for 0.5s!

      joystick[0] = 250;//FAILSAFE motor stop
      joystick[1] = 510; //  (Steering for car)
      //joystick[2] = 0;

      receiveOrder();
    }

    servo.write(joystick[0]);
    Serial.print("X = ");
    Serial.print(joystick[0]);

    //Motore Bidirezionale!

    int Speed, Pot;
    Pot = joystick[1];
    /* Is the pot in the reverse position ? */
    if (Pot >= POT_REV_MIN && Pot <= POT_REV_MAX)
    {
      HCMotor.Direction(0, REVERSE);
      Speed = map(Pot, POT_REV_MIN, POT_REV_MAX, 60, 10);

      /* Is the pot in the forward position ? */
    } else if (Pot >= POT_FWD_MIN && Pot <= POT_FWD_MAX)
    {
      HCMotor.Direction(0, FORWARD);
      Speed = map(Pot, POT_FWD_MIN, POT_FWD_MAX, 0, 100);

      /* Is the pot in the dead zone ? */
    } else
    {
      Speed = 0;
    }

    /* Set the on time of the duty cycle to match the position of the pot. */
    HCMotor.OnTime(0, Speed);

    //Luci Freno

    if   ((Pot >= 170) && (Pot <= 245))
    {
      digitalWrite(LuciFreno, HIGH);
    }
    else if ((Pot >= 170) && (Pot <= 0))
    {
      digitalWrite(LuciFreno, LOW);
    }
    else

    {
      digitalWrite(LuciFreno, LOW);
    }

    Serial.print("    Y = ");
    Serial.print(joystick[1]);

    Serial.print("    z = ");
    Serial.println(joystick[2]);

    val = joystick[2]; //legge il valore del pulsante sul joystick2
    //controlla se è accaduto qualcosa
    if ((val == HIGH) && (vecchio_val == LOW)) {
      stato = 1 - stato;
      delay(15); //attesa di 15 millisendi
    }

    vecchio_val = val; //ricordiamo il valore precedente di val

    if (stato == 1) {
      digitalWrite(3, HIGH); //accende il led
    }
    else {
      digitalWrite(3, LOW);//spegne il led
    }
    // First, stop listening so we can talk
    radio.stopListening();

    // Send the final one back.
    radio.write( joystick, sizeof(joystick) );

    //Now, resume listening so we catch the next packets
    radio.startListening();
  }

}

void loop(void)
{
  receiveOrder();
}
    if (millis() - lastRecvTime > 500)

should be outside the main if ( radio.available() ) {}

because if you have not received anything that's when you really need to test for the time out

Ok thanks.I test the code and let you know if it works!Thanks for your time!

Your receiveOrder should globaly look like this

void receiveOrder()
{
  static unsigned long lastRecvTime = 0;
  if ( radio.available() )   {
      // deal with incoming info and set lastRecvTime to mills() at the end
  }
  else if (millis() - lastRecvTime > 500UL) { 
      // deal with timeout 
  }
}

you might have a condition at the very start of the program where your Tx is not started before your Rx and so Rx will see the timeout. You'll need to handle that case, but if the only thing you do in the timeout section is park the motors somewhere safe then you are all OK, the next Tx will get things back in order

I have make the change and the failsafe work perfect now!Thanks

congratulation!!!!