CERCA PERSONA CON nRF24L01+



Quando si fa un particolare lavoro delle volte può essere necessario essere rintracciabili ma quando, per motivi personali, non si vuole fornire il proprio numero telefonico, che fare? Ci sono due possibilità; o il chiamante alza la voce sperando che il chiamato sia nelle immediate vicinanze o utilizzare un ricetrasmettitore. Quest'ultimo potrebbe essere costituito da una semplice coppia di portatili con i quali si potrebbe  instaurare un dialogo tra il chiamato ed il chiamante, delle volte, però,  tale possibilità non serve, nel mio caso, ad esempio, per il  lavoro che faccio (portiere condominiale) non occorre comunicare vocalmente con chi mi chiama ma serve recarmi sul posto per aprire semplicemente un cancello (ad esempio al postino o al corriere) dopo avere visto di persona chi è dall'altra parte. D'altronde non potrei usare i portatili data la sconvenienza di lasciarli  fuori del condominio a vista di tutti...anche di male intenzionati che  potrebbero farci un pensierino. Quindi  servirebbe qualcosa che non dia all'occhio stimolando appetiti illegali. Questo qualcosa dovrebbe essere dotato di un pulsante, di un led e di un buzzer, il tutto racchiuso in una scatoletta non eccessivamente attraente (ho usato una canalina 40 X 25). Sarebbe anche il caso di poter rendere questa scatoletta staccabile dal posto dove si trova per portarla in guardiola una volta finito il lavoro per poi riattaccarla la mattina successiva quando riinizia il lavoro (ad essa ho attaccato una calamita per tale scopo).


Il sistema è composto da un RTX fisso (fuori dal cancello) e un RTX mobile attaccato alla mia cintura.  I due apparecchi funzionano sia come TX che come RX cambiando il modo di funzionamento automaticamente in fase di comunicazione, infatti quando si preme il tasto sull'RTX fisso  quest'ultimo va in trasmissione (TX) inviando una messaggio (più altri dati del tipo, indirizzo, bit di controllo, etc, etc...) all'RTX mobile, subito dopo avere trasmesso questi dati  commuta automaticamente in RX e aspetta il  segnale di riconoscimento (ACK) dall'RTX mobile che a riposo è sempre in fase di ascolto (RX), appena l'RTX mobile riceve il messaggio fa una serie di controlli su di esso (sull'integrità dei dati, indirizzo, etc, etc...), se tutto va bene commuta in TX e invia all'RTX fisso il suddetto segnale di riconoscimento (ACK), subito dopo ritorna  in RX.
Come ho scritto prima questa commutazione avviene in maniera automatica grazie ai protocolli interni al nRF24L01, non occorre quindi che inseriamo nel programma istruzioni per far commutare i due moduli una volta in RX e poi in TX all'occorrenza, si potrebbe fare ma sarebbe un inutile spreco di tempo (e di energia della batteria). Cominciamo ora ad analizzare il software dell'RTX fisso.



PROGRAMMA RTX  FISSO
#include<SPI.h>
#include<nRF24L01.h>
#include<RF24.h>
int msg[1] = {}; 
RF24 radio(9,10);
const uint64_t pipe[1] = {0xF0F0F0F0E1};
void setup()
{
  pinMode(2, INPUT_PULLUP);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  radio.begin();
  digitalWrite(3, HIGH);
  delay(500);           
  digitalWrite(3, LOW); 
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.openWritingPipe(pipe[0]);
  radio.setDataRate(RF24_250KBPS);                           
  radio.stopListening();
 }
void loop()
{
  if(digitalRead(2) == 0)
  { 
    while(!radio.write(msg,sizeof(msg)));
    digitalWrite(3, HIGH);  
    digitalWrite(4, HIGH);
    delay(500);                
    digitalWrite(3, LOW); 
    digitalWrite(4, LOW);      
  }
}

#include<SPI.h>

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

Le tre librerie che servono per il corretto funzionamento.

int msg[1] = {}; 

Questo è un array di tipo int, viene usato dall'RTX fisso per inviare un  messaggio  al mobile, attenzione, non occorre che l'array contenga un valore, l'importante è che l'RTX fisso invii qualcosa per far fare qualche altra cosa all'RTX mobile, può essere, quindi,  anche vuoto (in questo programma ovviamente).


RF24 radio(9,10);

Con questa istruzione si crea l'oggetto "radio" e si assegnano i pin CE e CSS del modulo nRF24L01 ai pin di arduino nano ( nel mio caso CE = pin 9, CSS pin  10).



const uint64_t pipe[1] = {0xF0F0F0F0E1};

Questo è l'indirizzo, esso deve essere lo stesso sia per RTX fisso che  per quello mobile, possono essere usati , valori interi,  esadecimali e caratteri, l'importante che non siano più di 5 byte. Attenzione non usare valori che diano in binario serie di "uni" o di "zeri" continui (11111111 o 00000000)  perché il ricevitore potrebbe interpretarli come noise. Non devono essere neanche del tipo "01010101"...perché il ricevitore potrebbe interpretarli come un proseguimento del preambolo (una serie di "serie" ed "uno" alternati che servono per sincronizzare i dati). Per questo motivo sono stati usati gli esadecimali F0 (11110000).


pinMode(2, INPUT_PULLUP);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);

Predispone  il pin 2 come ingresso con PULLUP (tasto)
Predispone il pin 3 come uscita (LED)
Predispone il pin 4 come uscita (BUZZER)


radio.begin();
Attivazione  modulo nRF24L01


digitalWrite(3, HIGH);
delay(500);           
digitalWrite(3, LOW); 

Queste tre istruzioni servono per far lampeggiare il LED per 500mS e per dare una pausa tra radio.begin();  e le successive istruzioni


radio.enableAckPayload();

Questa istruzione abilita  il riconoscimento automatico (ACK), ne ho scritto all'inizio.


radio.enableDynamicPayloads();

Questa funzione trasmette solo i byte necessarise non fosse presente questa funzione il TX trasmetterebbe 32 byte fissi indipendentemente da quelli presenti nell'array. Funzione utile per abbreviare i tempi di trasmissione dati.


radio.openWritingPipe(pipe[0]);

Usa l'indirizzo precedentemente scritto nell'array pipe[]  per la trasmissione.


radio.setDataRate(RF24_250KBPS);

Velocità dei dati (baud rate), più è bassa e maggiore è la sensibilità del ricevitore (e quindi maggiore è la distanza di collegamento raggiungibile). l'ho impostata al minimo.


radio.stopListening();

Predispone il modulo nRF24L01 per trasmettere


if(digitalRead(2) == 0)

Se il tasto è premuto viene eseguito il corpo della "if".


while(!radio.write(msg,sizeof(msg)));

L'istruzione radio.write(msg,sizeof(msg)) invia il dato contenuto nell'array msg[]  all'RTX mobile, l'RTX fisso si pone poi in RX e aspetta l'ACK, quando lo riceve la funzione  restituisce un TRUE e il programma esce da "while" e salta all'istruzione successiva.
Se l'RTX mobile è fuori campo l'RTX fisso seguita a inviare il dato tramite la "while" in attesa del riconoscimento. In questo modo l'RTX mobile non perderà mai una chiamata anche quando è fuori campo, semmai la riceverà in ritardo (quando tornerà ad essere raggiungibile).


digitalWrite(3, HIGH);  
digitalWrite(4, HIGH);
delay(500);                 
digitalWrite(3, LOW); 
digitalWrite(4, LOW);  

Illumina il LED e attiva il BUZZER per 500 mS per indicare al chiamante che la chiamata è stata ricevuta dall'RTX mobile.


PROGRAMMA RTX  MOBILE



#include<SPI.h>
#include<nRF24L01.h>
#include<RF24.h>
const uint64_t pipe[1] = {0xF0F0F0F0E1};
RF24 radio(9,10); // radio(pin CE, pin CSN)
int rec[1] = {};
void setup()
{
  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, INPUT_PULLUP);
  radio.begin();
  digitalWrite(2, HIGH);
  delay(500);           
  digitalWrite(2, LOW); 
  radio.enableAckPayload();
  radio.enableDynamicPayloads();
  radio.openReadingPipe(1,pipe[0]);
  radio.setDataRate(RF24_250KBPS);                                 
  radio.startListening();
}
void loop()
{
  if(radio.available())
 {
    radio.read(rec,sizeof(rec));
    digitalWrite(2, HIGH);
    digitalWrite(4, HIGH);
    delay(1000);          
    digitalWrite(2, LOW);
    digitalWrite(4, LOW);
  }
}

Questa volta spiegherò solo le istruzioni che differiscono da quelle per il RTX fisso.


pinMode(2, OUTPUT);
pinMode(4, OUTPUT);

Predispone il pin 2 come uscita (LED)
Predispone il pin 4 come uscita (BUZZER)


radio.openReadingPipe(1,pipe[0]);

Usa l'indirizzo precedentemente scritto nell'array pipe[]  per la ricezione.


radio.startListening();

Predispone il modulo nRF24L01 per ricevere.


if(radio.available())

Se arriva una dato viene eseguito il corpo della "if".


radio.read(rec,sizeof(rec));

Legge il dato e lo memorizza nell'array rec[], anche se in questo programma il dato non contiene nulla occorre sempre chiamare questa funzione per svuotare il registro FIFO del nRF24L01, se non la si chiamasse il programma eseguirebbe il corpo della "if" indefinitamente.


digitalWrite(2, HIGH);
digitalWrite(4, HIGH);
delay(1000);          
digitalWrite(2, LOW);
digitalWrite(4, LOW);

Si illumina il led ed emette un suono per 1S, sufficiente per avvertire che qualcuno ha chiamato.


    COLLEGAMENTI



NOTE CONCLUSIVE
Questo sistema di comunicazione è molto affidabile grazie al protocollo interno dell'nRF24L01 che gestisce l'intero processo di trasmissione, di ricezione del dato e relativo riconoscimento.  Questa gestione automatica elimina tutti quei processi necessari per effettuare le stesse operazioni con il programma, questo alleggerisce il lavoro del programmatore ma soprattutto diminuisce la corrente media consumata dal sistema.
Per consumare ulteriormente di meno consiglio di togliere il LED "on" sito sulla scheda arduino, esso, stando internamente al contenitore, non è visibile e quindi non serve se non a consumare energia.

Sempre in tema di energia consiglio di usare un accumulatore a 9V ricaricabile tramite  USB di capacità 1000 mAH, la carica dura tantissimo. Fate un buco quadrato sul contenitore che userete per accedere  facilmente al connettore della batteria senza togliere il coperchio. Stessa cosa vale per il connettore di Arduino per la programmazione.


I due condensatori da 10 uF debbono essere saldati il più vicino possibile ai pad di ingresso della tensione VIN di Arduino e della tensione a 3.3 V del modulo nRF24L01 (nel disegno sono posti distanti dai suddetti pad solo per questioni di leggibilità dello schema). Questi condensatori eliminano disturbi creati sull'alimentazioni dalle emissioni elettromagnetiche, sono molto importanti, senza di essi questi segnali immessi sull'alimentazione possono resettare arduino o al limite abbassare la potenza di trasmissione. Tra le altre cose andando avanti con l'utilizzo dei due RTX si è evidenziato un fenomeno anomalo sulla durata  degli accumulatori da 9V che ho pensato fosse dovuto a un difetto della ricarica o a un malfunzionamento degli accumulatori. A tempi più o meno regolari gli accumulatori o duravano tre giorni o una sola mattinata alternandosi tra loro in questa strana manifestazione. Poi ho messo il condensatore sui pad della VIN di Arduino e il fenomeno è scomparso, in media ora durano tre giorni. Ipotizzo che quei disturbi sulla alimentazione siano i responsabili di tale comportamento strano.

La distanza massima raggiungibile dipende fortemente  dai vari ostacoli che si interpongono tra i due RTX (in particolare se sono conduttivi;  tubi, cavi elettrici, cancelli di metallo), ho fatto delle prove sia in ambiente chiuso che in campo libero. Per ambiente chiuso intendo una casa, un garage, insomma un posto dove vi siano molti muri, cavi e altri oggetti metallici. In particolare ho posto l'RTX fisso al 5^ piano del mio condominio e sono sceso con l'RTX mobile per vedere fin dove riceveva il segnale. Il mobile è riuscito a ricevere fino al 2 piano, essendo ogni piano alto 3 metri circa, in totale la massima distanza raggiunta è stata pari a 12 metri. Poi ho fatto delle prove in garage, ho posto l'RTX fisso  in cantina e sono uscito con il mobile. Gli ostacoli tra i due RTX erano: un muro e una porta metallica, in questa esperienza la massima distanza raggiunta  è stata di 20 metri.
Per le prove in campo aperto sono andato al parco e ho scelto un posto dove non vi era nulla tra i due RTX (neppure alberi), cioè, i due RTX erano a vista, la distanza massima raggiungibile è stata di 700 metri (misurata con GPS).

Se volete aumentare notevolmente queste distanze dovete usare una antenna esterna per l'RTX fisso. Quella che ho usato io è bibanda (2.4 GHz, 5.8 GHz) a base magnetica di quelle che si usano per la videosorveglianza. Dalla foto si notano le due bobine facenti parte delle trappole per l'accordo alle due frequenze.


L'antenna suddetta  risuona a 1/2 onda, con questa antenna si possono usare piani di massa estesi e la si può posizionare in punti  alti (la vendono con tre metri di filo) rendendo il collegamento più efficiente rispetto a quello che si ottiene con lo stilo che forniscono con il modulo nRF24L01 (dove l'altro braccio del dipolo è costituito dal solo piano di massa delle schede).

Usando questa antenna i risultati sono i seguenti.
Nel condominio l'RTX è arrivato a ricevere fino al piano -1 (18 metri).
In garage l'RTX è arrivato a ricevere fino a 45 metri.
Nel parco l'RTX è arrivato a ricevere fino a 1 km circa.

Per questo modulo è stata creata una libreria con molte funzioni, qui  troverete la spiegazione per ognuna di esse..
Qui i due programmi TX_RF_24_11 (RTX fisso), RX_RF_24_11 (RTX mobile).
Ciao
Fabio
HOME