Ed eccoci di nuovo a parlare di ZigBee!
Come ogni buon ‘serial’, e visto che è passato un po’ di tempo, iniziamo con un veloce riassunto delle puntate precedenti.
- Parte uno: abbiamo introdotto i moduli XBee, adattandoli ad una breadboard standard, collegandoli ad Arduino e completando la configurazione di base;
- Parte due: abbiamo fatto conoscenza con i comandi AT ed i moduli hanno iniziato a parlarsi tra loro.
- Parte tre: abbiamo assegnato un ruolo attivo ad Arduino, pilotando un LED via ZigBee (l’equivalente elettronico del classico ‘Hello World”).
Finora, in tutti gli esempi, abbiamo utilizzato i moduli XBee esclusivamente come ‘ponti’ per trasmettere bit da un Arduino all’altro (in pratica una comunicazione RS232 wireless), limitandoci a sfruttare il protocollo ZigBee per configurare gli indirizzi di partenza e di destinazione dei messaggi ma senza approfondire le reali potenzialità dei moduli stessi: in questo capitolo scopriremo che c’è molto di più e che un modulo XBee può essere impiegato direttamente come ‘sensor board’, può essere configurato (e ri-configurato) remotamente, può essere messo a nanna e risvegliato secondo necessità….
La cosa si fa interessante
Nella prima parte, parlando della configurazione dei moduli con X-CTU, abbiamo visto che esistono diversi firmware utilizzabili per i diversi tipi di modulo (coordinator, router, end device) e per ciascuno di questi sono disponibili due varianti: AT e API. Finora abbiamo utilizzato AT, ma cosa cambia tra i due? La differenza fondamentale non risiede nella modalità di comunicazione RF tra due moduli, che rimane la stessa, ma nella comunicazione tra il modulo e l’applicazione o il device che lo utilizza (Arduino, nel nostro caso):
– Modalità AT (modalità ‘trasparente’): le informazioni da trasmettere sono serializzate e passate al modulo attraverso il pin DIN e da questo trasmesse al modulo di destinazione, che, a sua volta, le comunicherà agli utilizzatori attraverso il pin DOUT: Il modulo non interviene in alcun modo sul contenuto ma si comporta come una seriale (RS232).
– Modalità API: la comunicazione tra modulo ed utilizzatore, basata dal punto di vista dell’elettronica sempre sui pin DIN e DOUT, avviene attraverso un’interfaccia strutturata (API sta per Application Programming Interface): non vengono più accettati dati serializzati ‘grezzi’ ma solo ‘frame’, ovvero sequenze di byte aventi struttura e composizione definita. I frame possono contenere sia informazioni di routing (indirizzi di partenza e destinazione, richieste di conferma trasmissione, ecc..), sia eventuali comandi (richieste di trasmissione, comandi di configurazione), sia dati veri e propri (payload), come potrebbero essere letture di sensori o altro.
La modalità API diventa utile quando, per esempio:
- è necessario trasmettere pacchetti verso molte destinazioni differenti: dal momento che le informazioni di routing possono essere inserite in ciascun frame non è più necessario riconfigurare il modulo per cambiare il destinatario;
- è necessario ricevere la conferma della spedizione: può essere richiesta all’interno del frame e verrà gestita direttamente dai moduli XBee evitando di dover ricorrere all’implementazione di un protocollo a livello di utilizzatore (l’utilizzatore si dovrà solo preoccupare di decidere come agire nel caso di errori);
- il modulo deve ricevere letture da sensori collegati ad altri moduli remoti;
- il modulo riceve trasmissioni da più mittenti: i frame contengono gli indirizzi di partenza e questo consente all’utilizzatore di identificare e di gestire dati provenienti da fonti diverse.
In una stessa rete possono coesistere moduli API e moduli AT in quanto, come detto, la comunicazione RF tra moduli non varia.
Frames: cosa c’è dentro?
Tutto molto interessante, ma in pratica come è fatto un frame? Dipende dallo scopo della comunicazione, ma la struttura di base è costituita da una parte fissa ed una parte che varia con il tipo di frame utilizzato. La figura seguente illustra il concetto:
Il delimitatore (1 byte) indica l’inizio del frame ed assume il valore fisso di 0x7E. I due byte successivi indicano la lunghezza del frame in byte della sola parte variabile, escludendo quindi i primi 3 byte e l’ultimo (checksum). L’ultimo byte, il checksum, è un byte di controllo il cui algoritmo di calcolo è il seguente (tutti i valori numerici sono esadecimale):
1. si sommano tutti i byte della parte variabile (esclusi quindi il delimitatore e i 2 byte relativi alla lunghezza;
2. si sottraggono da 0xFF gli ultimi 8 bit del valore calcolato al passo precedente. Il risultato è il checksum da inserire nel frame come ultimo byte.
Esempio: supponiamo di avere un frame così costituito: 7E 00 0A 01 01 50 01 00 48 65 6C 6C 6F e di volerne calcolare il checksum da aggiungere in fondo. I primi tre byte sono rispettivamente delimitatore e lunghezza, e vanno quindi esclusi dal calcolo: sommando i rimanenti si ottiene 247 (ricordandoci sempre che stiamo lavorando in esadecimale). Prendiamo il valore rappresentato dagli ultimi 8 bit, ovvero 47: sottraendolo da FF si ottiene B8, che è il valore da assegnare all’ultimo byte. I frame completo è quindi 7E 00 0A 01 01 50 01 00 48 65 6C B8. Tutti i calcoli si possono fare facilmente utilizzando una calcolatrice scientifica che possa operare con numeri in base 16 (la calcolatrice di Windows, per esempio). Digi mette a disposizione qui un’applicazione scaricabile per costruire frame per eventuali test.
Fin qui per la parte fissa. Ed in quella variabile, che c’è dentro? Dipende, ovviamente, dal tipo di frame. I moduli XBee supportano circa una ventina di frame diversi, individuati da un codice univoco (frame type) che è trasmesso come quarto byte (dopo delimitatore e lunghezza) all’interno del frame stesso:
La descrizione di tutti i tipi di frame supportati sarebbe piuttosto lunga ed in ogni caso è reperibile con facilità all’interno della documentazione di prodotto reperibile sul siti di Digi. Faremo solo qualche esempio, in modo da rendere più chiare le spiegazioni ‘teoriche’ e da avere disponibili gli strumenti necessari per far funzionare le applicazioni di prova di cui parleremo nella prossima parte.
Esempio 1: richiesta di esecuzione di un comando AT in locale
Il frame è molto semplice ed è utilizzato per eseguire un comando AT sul modulo locale (non c’è trasmissione verso altri moduli).
Il frame type è 0x08 e la struttura del frame è indicata nella tabella seguente:
Nell’esempio il comando AT è NJ senza parametri (i byte 5 e 6 contengono la codifica ASCII dei caratteri ‘N’ e ‘J’ rispettivamente): il modulo restituirà il Node Join Time impostato.
La sequenza di byte da trasmettere al modulo sarà quindi: 7E 00 04 08 01 4E 4A 0D .
Esempio 2: richiesta di trasmissione
Il frame è utilizzato per richiedere al modulo la trasmissione di una serie di byte verso un modulo remoto. E’ quello che avveniva negli esempi fatti nelle scorse puntate utilizzando i moduli in modalità AT, con la differenza che, utilizzando la modalità API, siamo in grado di specificare il destinatario all’atto della trasmissione, senza necessità di riconfigurazione del modulo stesso.
Il frame type è 0x10 e la struttura completa è descritta nella tabellina sotto.
La sequenza completa sarà quindi: 07 00 16 10 00 01 13 A2 00 40 0A 01 27 FF FE 00 00 54 78 44 61 74 61 30 41 13 .
Esempio 2: ricezione di campionamento I/O
In questo caso sarà il modulo a comunicare all’utilizzatore di aver ricevuto dei dati di campionamento provenienti da un sensore (o da una serie di sensori) remoto. Ciascun modulo XBee possiede una serie di ingressi / uscite sia analogici che digitali ai quali possono essere collegati sensori o comunque input di vario tipo. Il modulo di acquisizione (tipicamente un end device od un router) può essere configurato per leggere con una frequenza prestabilita gli input connessi ed inviare i dati acquisiti ad un modulo ricevente, il quale comunicherà all’utilizzatore quanto ricevuto all’interno di uno specifico frame con frame type 0x92.
Di seguito la tabellina con i dettagli:
La sequenza completa sarà quindi: 7E 00 14 92 00 13 A2 00 40 52 2B AA FF FE 01 01 00 1C 02 00 14 02 25 F5 . Vedremo più in dettaglio questo frame e la relativa gestione da parte di Arduino nella prossima parte, dove faremo un po’ di prove pratiche e realizzeremo qualcosa di (forse) utile.
complimenti per questi articoli 🙂
Mi sto interessando anche io a ZigBee per la mia tesi e vorrei provare anche qualcosa a casa con Arduino..prenderò taaaanto spunto da questi tuoi post 🙂
P.S. attendo gli altri….:) ce ne saranno,vero?:)
Ciao, grazie dell’interesse. Sicuramente scriverò qualche altro approfondimento, ho già il materiale ‘grezzo’, devo solo trovare il tempo di organizzare il tutto!
Senti ma…tesi su cosa, se posso chiedere?
Tesi sull’ottimizzazione di una rete zigbee che opera in una casa domotica 🙂
Pingback: Arduino, ZigBee e le infinite possibilità (5) | The Monday Morning Tech Newsletter
Ciao,so che la guida è un po’ vecchia ma da poco sto utilizzando due moduli xbee ed ho un problema relativo alla comunicazione api.
I due moduli sono Xbee serie 2 XB24-Z7SIT-004, uno connesso ad un arduino UNO con caricato uno sketch vuoto,mentre l’altro collegato a una Raspberry PI che monta Raspbian.
In modalità AT tutto funziona,invio comandi,comunico tra i due moduli da terminale ecc. ma quando setto i firmware su API mode e cerco di inviare ad esempio la stringa “7E 00 04 08 01 4E 4A 0D” del node join date non ricevo alcuna risposta da nessuno dei due moduli e non capisco perchè
Ciao, vediamo se riesco a darti qualche suggerimento….è un po’ che non gioco con queste cosette, ma penso di non essermi dimenticato i punti fondamentali. Stai usando il frametype 08, che corrisponde alla richiesta di esecuzione di un comando AT in locale: non ci sarà nessuna interazione con altri moduli remoti. Il comando che stai inviando è ‘NJ’ (4E 4A in hex), ovvero Node Join Time, e dovresti ricevere in risposta un frame type 88, contenente il node join time in secondi, espresso in esadecimale (il default dovrebbe essere 0, ovvero node join time illimitato). Lo stesso frame dovrebbe anche dirti se è tutto OK oppure se c’è stato un errore di qualche tipo (comando non valido, parametro non valido, errore di trasmissione,…) nel byte 7.
MA: se il checksum non è corretto, il pacchetto è scartato in modo silente, senza alcuna risposta da parte del modulo stesso: sei sicuro che ‘0D’ sia giusto?
In base a quello che leggo qui dovrebbe essere ‘5E’…
Ti ringrazio della risposta,ho provato anche a cambiare il checksum ma non ricevo nulla come prima. Ho provato anche ad inviare altri frame con questo ad esempio 7E 00 04 08 52 49 44 18 e 7E 00 04 08 52 4E 44 13 ma niente,come se fosse sordo :/