RISOLTO nrf24: conferma ricezione pacchetto sul ricevitore.

Ciao a tutti,
sto facendo un progetto che mi sta facendo tribolare ...

Arduino A legge un encoder e lo trasmette ad Arduino B che ha un display
e fin qui tutto ok.

Quando pero B perde il segnale mi visualizza l'ultimo valore letto, cosa che non mi va bene.
Vorrei fare in modo che mi dia un messaggio tipo "connection error" e credo che vada gestito con l'ack payload.

Il problema è che da quanto capisco l'ack mi segnala sul trasmettitore quindi A se B ha ricevuto il pacchetto (ed in tal modo sono riuscito ad implementarlo ma no mi serve a niente).

Ma a me serve che il ricevitore, quindi B mi scriva se ha letto correttamente il pacchetto inviato da A.

Quindi riassumento A ---> B dato, B ---> A ack , A --> B la ricezione dell'ack, B autorizza A a mandare il prossimo pacchetto.
E' corretto?

Sto diventando matto ...

Grazie!

Prova a mostrare il codice

Al momento non avrei cosa mostrare: ho una coppia di codici che trasmettono il dato senza ack e funzionano perfettamente ma come detto sopra quando vado fuori range il visualizzato resta l'ultimo ricevuto,
e una coppia di codici che trasmettono un dato inserito damonitor seriale con ack che ho trovato come esempio per tentare di capirci qualcosa.

Il problema è che mi sfugge se c'è un modo logico per fare le cose in maniera piu semplice di quanto ho scritto sopra ovvero con praticamente 4 trasmissioni per dato.

Se lo ritieni utile posso cmq postare i codici.
Grazie.

Allego codice TX_ACK:
inserendo nello standard monitor un valore lo spedice e verifica se è andato tutto a buon fine.

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

// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);

// Topology
const uint64_t add1 = 0xf0f0f0f0e1LL;      
char msg[20];
char Ack[20];

boolean transmissionState;
static unsigned long previousSuccessfulTransmission;

void setup(){

  Serial.begin(115200);
  printf_begin();
  radio.begin();
  radio.enableAckPayload();               // Allow optional ack payloads
  radio.setPALevel(RF24_PA_MIN);
  radio.openWritingPipe(add1);       // Both radios listen on the same pipes by default, and switch when writing
  radio.printDetails();              // Dump the configuration of the rf unit for debugging
}

void loop() {


}
void serialEvent()
{
Serial.readBytesUntil('\n',msg,sizeof(msg));
 if(radio.write(msg,sizeof(msg)))
  {
   Serial.println(msg);
   if(radio.isAckPayloadAvailable())
    {
     radio.read(Ack,sizeof(Ack));
     Serial.print("Received an Ack: ");
     Serial.println(Ack);
     previousSuccessfulTransmission = millis();
    }
  }
 if (millis() - previousSuccessfulTransmission > 1000) 
  {
   transmissionState = false;
   memset(msg, 0, sizeof(msg)); // clear the payload array, if transmission error
   Serial.println("Data transmission error, check receiver!");
  }
    else
     {
      transmissionState = true;
      Serial.println("Data successfully transmitted");
     }
}

Questo è il codice dell'RX ACK che non fa altro che ricevere e mandare su monitor quanto ricevuto.

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

// Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);

// Topology
const uint64_t add1 = 0xf0f0f0f0e1LL;      
char msg[20];

void setup(){

  Serial.begin(115200);
  printf_begin();
  // Setup and configure rf radio

  radio.begin();
  radio.enableAckPayload();               // Allow optional ack payloads
  radio.setPALevel(RF24_PA_MIN);
  radio.openReadingPipe(1,add1);
  radio.startListening();                 // Start listening
  radio.printDetails();                   // Dump the configuration of the rf unit for debugging
}

void loop() {
 if(radio.available())
  {
   radio.read(msg,sizeof(msg));
   radio.writeAckPayload(1,"received",15);
   Serial.println(msg);
  }
 }

Esattamente come in trasmissione segnali errore dopo 1 secondo senza ack

In ricezione segnali errore dopo 1 secondo senza dati

Altrimenti apri la libreria e nella parte dove da ack gli fai anche stampare ok o no ok

Comunque ho l'impressione che gli nrf24 siano inutilmente complicati

Salvorhardin:
Esattamente come in trasmissione segnali errore dopo 1 secondo senza ack

In ricezione segnali errore dopo 1 secondo senza dati

Altrimenti apri la libreria e nella parte dove da ack gli fai anche stampare ok o no ok

la prima parte ok,
non capisco cosa intendi per aprire la libreria.
Sono agli inizi e di programmazione ne capisco decisamente poco.

Ho usato gli nrf24 perchè li ho a casa per un progetto di un telecomando per un'auto RC che sto copiando (progetto bello e pronto di un ragazzo svizzero).

Ci sono alternative a tuo avviso più semplici?

Grazie!

Salvorhardin:
Comunque ho l'impressione che gli nrf24 siano inutilmente complicati

... impressione pienamente condivisa, specie per le applicazioni in cui vengono normalmente usati in questo forum ... ::slight_smile:

Guglielmo

Buongiorno,
grazie al vostro consiglio sono uscito dal loop :slight_smile:
Ho finalmente il sitema che funziona come volevo io, dandomi un messaggio quando la trasmissione si interrompe.

Ora procederò con il resto del codice.
Vi allego i nuovi listati.

Codice Trasmettitore

/*
Encoder: legge i dati dall'encoder e li trasmette grezzi (numero di step) al ricevitore il quale 
li convertirà in angolo da visualizzare sul display.
* modulo nrf24
* CE   9
* SCN  10
* mosi 11
* miso 12
* sck  13
* pulsante 1 4
* pulsante 2 5
* pulsante 3 6
* pulsante 4 7
* 
*/
#include <RF24.h>                                                                              
#include <nRF24L01.h>
#include <SPI.h>
#include "printf.h"

#define DEBUG  //if not commented out, serial.print is active!

/* encoder*/
#define encoderPin1  3
#define encoderPin2  2
#define risoluzioneEncoder  0.05 /* INSERIRE QUI VALORE ENCODER uguale anche nel programma COTO 360/7200=0.05, se usiamo in quadratura va 360/28800
* http://www.sciamannalucio.it/arduino-encoder-conta-impulsi-giri-motore/
*  tecnicamente adesso la risoluzione si ottiene con 360/7200 perchè (vedi sezione encoder) usiamo un solo fronte per il conteggio e non 4 */
volatile int lastEncoded = 0;
volatile long encoderValue = 0;
float Angolo = 0;
long lastencoderValue = 0;
 
int lastMSB = 0;
int lastLSB = 0;
/* endocder */

/*Variabili network */
RF24 radio(9, 10);               // nRF24L01 (CE,CSN)
const uint64_t add1 = 0xf0f0f0f0e1LL;      
char msg[20];
char Ack[20];
boolean transmissionState;
static unsigned long previousSuccessfulTransmission;
/*Variabili network */





void setup() {

/* Setup network */  
  radio.begin();
  radio.enableAckPayload();               // Allow optional ack payloads
  radio.setPALevel(RF24_PA_MAX);
  radio.openWritingPipe(add1);       // Both radios listen on the same pipes by default, and switch when writing
/* Setup network */       
 
/* Debug*/
#ifdef DEBUG
  Serial.begin (115200);
  printf_begin();
  radio.printDetails();
#endif  
 /*Debug*/
 
/* encoder*/ 
  pinMode(encoderPin1, INPUT_PULLUP);
  pinMode(encoderPin2, INPUT_PULLUP);
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);
/* encoder*/ 
  
}




void loop() {


  
   Angolo = encoderValue*risoluzioneEncoder;
   if(radio.write(&encoderValue,sizeof(encoderValue)))
  {
   #ifdef DEBUG
   Serial.println(encoderValue);
   #endif
   if(radio.isAckPayloadAvailable())
    {
     radio.read(Ack,sizeof(Ack));
     #ifdef DEBUG
     Serial.print("Received an Ack: ");
     Serial.println(Ack);
     #endif
     previousSuccessfulTransmission = millis();
    }
  }
   if (millis() - previousSuccessfulTransmission > 1500) 
    {
     transmissionState = false;
     #ifdef DEBUG
     Serial.println("Data transmission error, check receiver!");
     #endif
    }
    else
    {
     transmissionState = true;
     #ifdef DEBUG
     Serial.println("Data successfully transmitted");
     #endif
    }
 
}






/* routine encoder, non toccare!*/
void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit
 
  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value
 
  if(sum == 0b1101 /*|| sum == 0b0100 || sum == 0b0010 || sum == 0b1011*/) encoderValue ++; // modificato per non lavorare in quadratura
  if(sum == 0b1110 /*|| sum == 0b0111 || sum == 0b0001 || sum == 0b1000*/) encoderValue --; // modificato per non lavorare in quadratura
 
  lastEncoded = encoded; //store this value for next time
}

/* routine encoder, non toccare!*/

codice Ricevitore:

/*
Ricevitore per Encoder: riceve un segnale grezzo dall'encoder (numero di step) e lo converte in un angolo 
da visualizzare sul display .

* modulo nrf24
* CE   9
* SCN  10
* mosi 11
* miso 12
* sck  13
* pulsante 1 2
* pulsante 2 3
* pulsante 3 4
* pulsante 4 5
* 
*/
#include <RF24.h>
#include <nRF24L01.h>
#include <SPI.h>
#include <LiquidCrystal_I2C.h>
#include "printf.h"

#define risoluzioneEncoder  0.05 // INSERIRE QUI VALORE ENCODER uguale anche ne programma kren 360/7200=0.05 ma adesso va 360/2850

#define DEBUG  //if not commented out, serial.print is active!

/* variabile display*/
LiquidCrystal_I2C lcd(0x27,16,2); 
/* variabile display*/

/*variabile network */
RF24 radio(9,10);               // nRF24L01 (CE,CSN)
const uint64_t add1 = 0xf0f0f0f0e1LL;      
char msg[20];
boolean transmissionState;
static unsigned long previousSuccessfulTransmission;
/*variabile network */

/* conversione Angolo */
float Angolo;
long encoderValue;
/* conversione Angolo */

/*Variabili Pulsanti */
int pulsante_1 = 0;
int pulsante_2 = 0;
int pulsante_3 = 0;
int pulsante_4 = 0;
/*Variabili Pulsanti */



void setup() {
   
  
/* Setup network */  
  radio.begin();
  radio.enableAckPayload();               // Allow optional ack payloads
  radio.setPALevel(RF24_PA_MAX);
  radio.openReadingPipe(1,add1);
  radio.startListening();                 // Start listening
/* Setup network */  

/* parte display i2c */
  lcd.init();                      // initialize the lcd 
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Crankshaft");
  lcd.setCursor(0,1);
  lcd.print("Wireless reader");
  delay(200);
/* parte display i2c */

/* Debug*/
  #ifdef DEBUG
  Serial.begin(115200);
  printf_begin();
  radio.printDetails();   
  #endif
/* Debug*/ 
}

void loop() {

   if(radio.available())
  {
   radio.read(&encoderValue,sizeof(encoderValue));
   radio.writeAckPayload(1,"received",15);
   previousSuccessfulTransmission = millis();
  }
    if (millis() - previousSuccessfulTransmission > 1000) 
     {
       transmissionState = false;
       #ifdef DEBUG
       Serial.println("Data transmission error, check Transmitter!");
       #endif
       lcd.clear();
       lcd.setCursor(0,0);
       lcd.println("NO CONNECTION    ");
       lcd.setCursor(0,1);
       lcd.println("Check Encoder   ");
       delay(200);
     }
    else
     {
       transmissionState = true;
       #ifdef DEBUG
       Serial.println("Data successfully received");
       Serial.println(encoderValue);
       #endif
       Angolo = encoderValue*risoluzioneEncoder;
       lcd.clear();
       lcd.setCursor(4,0);
       lcd.print("Angolo:");
       lcd.setCursor(4,1);
       lcd.print(Angolo);
       lcd.setCursor(10,1);
       lcd.print("Gradi");  
       delay(200);
     }
}

Tanto per curiosità quali sarebbero secondo voi le alternative a questo modulo?
Quantomeno per imparare qualcosa di nuovo :slight_smile:

Tdmax:
Tanto per curiosità quali sarebbero secondo voi le alternative a questo modulo?

Dato che non mi sembra tu stia lavorando su una rete "mesh", ma piuttosto su una trasmissione punto-punto, probabilmente sarebbero stati più che sufficienti dei semplici HC-12 o dei buoni moduli radio a 433/868 (NON quelle "monnezze" cinesi da 1.5US$ o meno, ma moduli seri, come ad esempio quelli che produce QUESTA ditta Italiana).

Guglielmo

Quindi non pratica hai usato un timeout
Bene,
Concordo con Guglielmo : moduli hc12 a volontà

Ma perché tutti usano nrf24? Costano di meno?

Standardoil:
Ma perché tutti usano nrf24? Costano di meno?

... magari i "cloni" clinesi, perché gli nRF24l01 originali costano un bel po ... solo il CHIP, una BREADBOARD.

Credo comunque dipenda dalla motitudine di esempi che si trovano in giro (il 70% NON funzionanti come si deve).

Guglielmo

Come dice mio 'cuggino' : monnezzanet

No scherzo, non mio cugino, ma mio fratello