Nella
precedente
pagina ho presentato un sistema di ricetrasmettitori che permette di
chiamare una persona che è troppo distante dal chiamante per sentirlo.
L'esigenza di progettare un simile sistema è stata dettata dal mio
lavoro di portinaio; spesso sono in giro per le palazzine per le
pulizie o per inserire la posta nelle cassette postali ed essendo
le palazzine piuttosto distanti dal cancello d'ingresso del
comprensorio delle volte non sentivo chi mi chiamava a voce. Il vecchio
sistema, presentato in
questa pagina, soddisfaceva la mia
esigenza di essere chiamato ovunque mi trovassi...ma non del tutto,
infatti nei piani più bassi delle palazzine il segnale non
arrivava
e anche se il sistema era (ed è) stato progettato per
"memorizzare" una chiamata che risultasse effettiva solo quando il
ricevitore fosse entrato nella zona di campo ho voluto rendere più
efficiente il sistema perché sarebbe stato un problema nel caso fossi
rimasto nei piani bassi per
diverso tempo con un condomine loquace. In tal caso il chiamante
avrebbe potuto perdere la pazienza creando delle volte danni a
beni
di proprietà (corrieri che avrebbero potuto lasciare il pacco in
strada, postini che avrebbero potuto lanciare la busta della
posta oltre il cancello incuranti che quelle
buste, delle volte, contengono anche piccoli pacchi delicati oltre
che materiale cartaceo...).
Per risolvere questo problema ho
progettato un ulteriore
RTX (che ho chiamato
RTX ponte) con la funzione
di ponte radio da interporre tra
l'RTX fisso e quello mobile. Questo
RTX ponte non è fisso come i ponti dei
cellulari o come i ponti radio
in genere ma va sempre posizionato giornalmente in ogni zona di
interesse coperta dal campo. In particolare lo metto nell'androne
della palazzina che devo pulire di turno e lo sposto
nelle
altre palazzine nei giorni a seguire, l'importante è che esso va sempre posizionato nella zona di campo creato dal
RTX fisso per avere la sicurezza del collegamento. In questo modo il campo
risulta essere presente anche nei piani più bassi. Vedi figure
sotto.
Nel
disegno superiore è rappresentato il vecchio sistema, si nota che il
campo prodotto dall'
RTX fisso (cerchio nero) non raggiunge i piani più
bassi della palazzina essendo assente anche in alcune zone del
piano -1, mentre nel disegno inferiore è rappresentato il nuovo sistema
dove si nota che sia l'
RTX ponte che quello mobile (al piano -2) sono
immersi in un campo forte, il primo in quello prodotto dall'
RTX fisso (cerchio nero)
ed il secondo in quello prodotto dall'
RTX ponte (cerchio rosso). Le
frecce indicano il percorso del collegamento.
L'RTX
fisso, come fa intendere la parola, lo sistemo fuori il cancello del
comprensorio attaccandolo con delle calamite al contenitore in metallo del citofono (che funge anche da piano
di massa per l'antenna).
.
L'RTX ponte (anch'esso si potrebbe definire
fisso ma non facciamo confusione e chiamiamolo "ponte") lo attacco (sempre con delle calamite) alla
ringhiera (che funge da piano di massa per l'antenna) delle scale nella palazzina di turno, vedi foto sotto.
L'
RTX mobile lo tengo attaccato alla cintura e lo porto sempre con me, vedi foto sotto.
Consiglio
di usare un'antenna esterna magnetica sia per l'RTX fisso
che l'RTX ponte per aumentare l'efficienza della comunicazione sia
in trasmissione che in ricezione.
DESCRIZIONE QUALITATIVA DEL FUNZIONAMENTO DEL SISTEMA
Alla
pressione del pulsante l'RTX fisso invia un messaggio sia all'RTX
mobile che all'RTX ponte
(prima al RTX ponte e poi al RTX mobile) indefinitamente
fintanto che uno dei due apparecchi non risponde con l'invio un segnale
di
riconoscimento (ACK), alla ricezione dell'ACK suona un buzzer
e si illumina un led per 500 mS sul RTX fisso per segnalare al
chiamante che la chiamata è stata ricevuta. Per circa 10 S il tasto dell'RTX fisso viene escluso per evitare che il chiamante (impaziente) lo premi troppe volte quando uno degli altri due RTX ha gia' risposto, ad esempio il mobile seguiterebbe a suonare, questo continuo inviare
messaggi potrebbe andare in conflitto con quelli che invia l'RTX ponte al
mobile, tutto ciò potrebbe causare malfunzionamenti del sistema che si
potrebbe bloccare. In questo tempo di esclusione del tasto lampeggia anche il led del RTX fisso. Se sia
che l'RTX ponte
che l'RTX mobile si
trovano in zona coperta dal campo risponde prima l'RTX ponte dato che
ha la
priorità di risposta e vengono
automaticamente interrotti ulteriori invii di messaggi all'RTX mobile. L'RTX ponte risponde allora all'RTX fisso, subito dopo si
illumina il suo led per 1 S e
commuta in TX per inviare a sua volta un messaggio all'RTX mobile
indefinitamente fintanto che esso non risponde. Quando l'RTX mobile risponde al ponte inviandogli un ACK, suona il suo buzzer e si illumina il suo led per due volte mentre sul RTX ponte si illumina il led per 500 mS.
Se il ponte è spento (perché non sono a fare le pulizie delle
palazzine) alla chiamata dall'RTX fisso risponde
il mobile, allora si illumina il suo led e suona il suo buzzer per una
volta per 1 S, in questo modo si discrimina la chiamata; led illuminato
e
suono per una volta significa che la chiamata è stata spedita dal RTX
fisso, led illuminato e suono per due volte significa che la chiamata è stata spedita dal RTX ponte. Ai fini della utilità questa discriminazione non serve a nulla (o suona una volta o suona due volte in ogni caso capisco che qualcuno mi cerca), però mi piaceva ci fosse.
SOFTWARE RTX FISSO
#include<SPI.h>
#include<nRF24L01.h>
#include<RF24.h>
int msg[1] = {};
int i;
bool flag_0 = false;
bool flag_1 = false;
RF24 radio(9,10);
const uint64_t pipe[] = {0xF0F0F0F0E1,0xF0F0F0F0E0};
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.setDataRate(RF24_250KBPS);
radio.stopListening();
}
void loop()
{
if(digitalRead(2) == 0)
{
while(!flag_0 && !flag_1)
{
msg[0] = 1;
radio.openWritingPipe(pipe[1]);
delay(10);
flag_1 = radio.write(msg,sizeof(msg));
if(flag_1 == 0)
{
msg[0] = 0;
radio.openWritingPipe(pipe[0]);
delay(10);
flag_0 = radio.write(msg,sizeof(msg));
}
}
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
while(digitalRead(2) == 0);
for(i = 0 ; i<= 10 ; i++)
{
digitalWrite(3, HIGH);
delay(500);
digitalWrite(3, LOW);
delay(500);
}
flag_0 = false;
flag_1 = false;
}
}
#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 o al ponte, per il momento è
vuoto, sarà caricato con un valore per discriminare la chiamata
effettuata o dal RTX fisso o dal RTX ponte verso l'RTX mobile.
bool flag_0 = false;
bool flag_1 = false;
Due variabili di tipo bool che serviranno per l'istruzione "while".
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, 0xF0F0F0F0E0};
Questi
sono gli l'indirizzi, il primo appartiene all'RTX mobile ed il secondo all'RTX ponte,
nel momento dell'utilizzo essi devono essere uguali a quello del RTX
fisso, 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).
radio.enableDynamicPayloads();
Questa funzione trasmette solo i byte necessari, se 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 viene premuto viene eseguito il corpo della "if".
while(!flag_0 && !flag_1)
{
msg[0] = 1;
radio.openWritingPipe(pipe[1]);
delay(10);
flag_1 = radio.write(msg,sizeof(msg));
if(flag_1 == 0)
{
msg[0] = 0;
radio.openWritingPipe(pipe[0]);
delay(10);
flag_0 = radio.write(msg,sizeof(msg));
}
Il
corpo dell'istruzione "while" viene eseguito fintanto che i contenuti
nei registri "flag_0" e "flag_1" sono a valore "false" (come impostato
nella dichiarazione delle due variabili all'inizio). Nel corpo della "while"
la prima istruzione che si trova carica nella variabile "msg" il
valore uno (che farà capire al RTX mobile che è stato chiamato dall'RTX ponte e non dall'RTX fisso), subito dopo si trova l'istruzione radio.openWritingPipe(pipe[1]); che imposta l'indirizzo "0xF0F0F0F0E0" appartenente al RTX ponte dopo un ritardo di 10 mS (che serve al modulo per stabilizzarsi al nuovo indirizzo) tramite flag_0 = radio.write(msg,sizeof(msg));
l'RTX fisso invia il valore contenuto nella variabile "msg" al ponte (che a sua volta spedirà al mobile). Quando l'RTX ponte risponde la funzione restituisce il
valore "true" che viene memorizzato nella variabile "flag_1",
questo avrà due conseguenze, la prima è che alla prossima interazione
del "while" il programma uscirà dal ciclo, la seconda è che non farà
eseguire le istruzioni nel corpo della "if" successiva inibendo l'invio
del messaggio all'RTX mobile. Se
invece l'RTX ponte è spento e quindi non risponde, la
funzione di invio messaggio restituisce un valore "false" che viene
memorizzato nella solita variabile "flag_1", il corpo della
"if" successiva viene allora esguito. La prima istruzione presente in esso carica il
valore zero nella variabile "msg", questo valore sarà inviato all'RXT
mobile in modo che capirà che è stato chiamato dal RTX fisso e non dal RTX ponte. Subito dopo si trova l'istruzione radio.openWritingPipe(pipe[0]); che imposta l'indirizzo "0xF0F0F0F0E1" appartenente all'RTX mobile e dopo un ritardo di 10 mS (che serve al modulo per stabilizzarsi al nuovo indirizzo) tramite flag_0 = radio.write(msg,sizeof(msg)); l'RTX fisso invia il valore contenuto nella variabile "msg" all'RTX mobile.
Se quest'ultimo risponde la funzione restituisce il valore "true"
che viene memorizzato nella variabile "flag_0", questo
stato, alla prossima interazione del "while", farà uscire il programma dal ciclo "while".
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
Quando
il ciclo "while" si interrompe, perché o l'RTX mobile o l'RTX ponte
risponde, il led lampeggia e il buzzer suona per 500 mS segnalando al
chiamante che la chiamata è stata ricevuta.
while(digitalRead(2) == 0);
Questa istruzione ferma
il programma fintanto che il tasto è premuto.
for(i = 0 ; i<= 10 ; i++)
{
digitalWrite(3, HIGH);
delay(500);
digitalWrite(3, LOW);
delay(500);
}
Questa
for ripete l'interazione per 5 volte, quindi per 10 S, il led lampeggia
ed è inibito il tasto per i motivi dei quali ho parlato all'inizio.
flag_0 = false;
flag_1 = false;
Reimposta le due variabili al valore "false" per il prossimo ciclo di "while"
SOFTWARE RTX PONTE
#include<SPI.h>#include<nRF24L01.h>#include<RF24.h>const uint64_t pipe[] = {0xF0F0F0F0E0, 0xF0F0F0F0E1};RF24 radio(9,10); int msg[1] = {}; void setup(){ pinMode(2, OUTPUT); 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(msg,sizeof(msg)); digitalWrite(2, HIGH); delay(1000); digitalWrite(2, LOW); radio.openWritingPipe(pipe[1]); radio.stopListening(); delay(100); while(!radio.write(msg,sizeof(msg))); digitalWrite(2, HIGH); delay(500); digitalWrite(2, LOW); radio.openReadingPipe(1,pipe[0]); radio.startListening(); delay(100); }}NOTA:
Tutte le istruzioni fino al "void loop" identiche a quelle usate nel TRX fisso non le spiegherò di nuovo. pinMode(2, OUTPUT); Predispone il pin 2 come uscita, al pin è collegato il led.
if(radio.available()) { radio.read(msg,sizeof(msg)); digitalWrite(2, HIGH); delay(1000); digitalWrite(2, LOW); radio.openWritingPipe(pipe[1]); radio.stopListening(); delay(100); while(!radio.write(msg,sizeof(msg))); digitalWrite(2, HIGH); delay(500); digitalWrite(2, LOW); radio.openReadingPipe(1,pipe[0]); radio.startListening(); delay(100); }In
"void loop" viene continuamente eseguita una "if" fintanto che l'RTX
ponte non riceve un messaggio dall'RTX fisso, quando questo accade la
funzione radio.available() restituisce un "true" e il corpo della "if" viene eseguito. La funzione radio.read(msg,sizeof(msg)); legge
il messaggio ricevuto e lo salva nella variabile "msg" (il valore
ricevuto è sempre 1). Le tre istruzioni seguenti fanno
accendere il
led per 1S. La funzione radio.openWritingPipe(pipe[1]); apre per la scrittura l'indirizzo 0xF0F0F0F0E1 appartenente all'RTX mobile, la funzione radio.stopListening(); commuta l'RTX ponte
in TX e dopo un ritardo di 100 mS (necessario per dare il tempo al
modulo si assestarsi alle nuove condizioni) viene eseguita la
funzione while(!radio.write(msg,sizeof(msg))), il ciclo while invia il messaggio all'RTX mobile tramite la funzione radio.write(msg,sizeof(msg) e fintanto che essa non restituisce un "true" (ovvero fintanto che l'RTX mobile non risponde), il ciclo verrà ripetuto indefinitamente.
Quando l'RXT mobile risponde con un ACK il ciclo "while" si interrompe e il programma salta alle istruzioni successive. Le tre istruzioni successive fanno lampeggiare per 500 mS il led per indicare che l'RTX ponte ha ricevuto risposta dal mobile. La funzione radio.openReadingPipe(1,pipe[0]); apre per la lettura l'indirizzo 0xF0F0F0F0E0 appartenente all'RTX ponte e la funzione radio.startListening(); lo commuta in RX, dopo un leggero ritardo di 100 mS (sempre per assestare i cambiamenti nel modulo), l'RTX ponte torna all'ascolto.
SOFTWARE RTX MOBILE
#include<SPI.h>#include<nRF24L01.h>#include<RF24.h>const uint64_t pipe[1] = {0xF0F0F0F0E1};RF24 radio(9,10); int rec[1] = {0};void setup(){ pinMode(2, OUTPUT); pinMode(4, OUTPUT); 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)); delay(100); if(rec[0] == 0) { digitalWrite(2, HIGH); digitalWrite(4, HIGH); delay(1000); digitalWrite(2, LOW); digitalWrite(4, LOW); } else { digitalWrite(2, HIGH); digitalWrite(4, HIGH); delay(500); digitalWrite(2, LOW); digitalWrite(4, LOW); delay(500); digitalWrite(2, HIGH); digitalWrite(4, HIGH); delay(500); digitalWrite(2, LOW); digitalWrite(4, LOW); } }}NOTA:
Tutte le istruzioni fino al "void loop" identiche a quelle usate nel TRX fisso non le spiegherò di nuovo.
if(radio.available()) { radio.read(rec,sizeof(rec)); delay(100); if(rec[0] == 0) { digitalWrite(2, HIGH); digitalWrite(4, HIGH); delay(1000); digitalWrite(2, LOW); digitalWrite(4, LOW); }
In "void loop" viene continuamente eseguita
una "if" fintanto che l'RTX mobile non riceve un messaggio o dall'RTX
fisso o dall'RTX ponte, quando questo accade la funzione radio.available() restituisce in "true" e il corpo della "if" viene eseguito. La funzione radio.read(rec,sizeof(rec)); legge
il messaggio ricevuto e lo salva nella variabile "rec" (il valore
contenuto può essere sia uno che zero). Dopo un ritardo di
100 mS (serve per dare il tempo all'RTX
di eseguire tutte le funzioni necessarie per scrivere il dato nella
variabile) il programma trova una "if", se la variabile "rec" contiene
uno zero (chiamata dal RTX fisso) viene eseguito il corpo della "if". Le tre istruzioni seguenti fanno illuminare il led e suonare il buzzer per 1 S.
Se nella variabile "rec" è presente un uno viene eseguito il corpo della "else".
else { digitalWrite(2, HIGH); digitalWrite(4, HIGH); delay(500); digitalWrite(2, LOW); digitalWrite(4, LOW); delay(500); digitalWrite(2, HIGH); digitalWrite(4, HIGH); delay(500); digitalWrite(2, LOW); digitalWrite(4, LOW); } }Questo significa che la chiamata è partita dal RTX ponte, Il led si illumina e il buzzer suona per 500 mS per due volte. Dopo l'RTX mobile
torna ad ascoltare.COLLEGAMENTI
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.Qui tutti i programmi.Fabio