Realizza una comunicazione LoRa P2P

Il protocollo LoRa, come vedremo nei prossimi tutorial, è lo standard fisico di trasmissione che caratterizza il protocollo IoT LoRaWan, tuttavia, può anche essere utilizzato per realizzare facilmente una comunicazione punto-punto (detta anche Pear to Pear P2P) tra due dispositivi.

In questo tutorial introdurremo la scheda Arduino MKR WAN 1310, la board della famiglia MKR dotata di connettività LoRa e ti faremo vedere come realizzare una comunicazione P2P che utilizzi la trasmissione radio LoRa.

Solitamente questa scheda viene venduta in bundle con una antenna a dipolo, indispensabile per un uso sul campo della scheda.

Arduino MKR 1310 + Antenna a dipolo


Lo sketch utilizzato per il ruolo di “Alice” è riportato nel riquadro che segue.

#include <SPI.h>
#include <LoRa.h>

// parametrizzo l'indirizzo locale e quello di destinazione
String mioNome = "Alice";
byte mioIndirizzo = 0xAA;  
byte indirizzoDestinatario = 0xBB;

void setup() {
  // inizializzo la comunicazione seriale
  // attend'apert del tenale seriale
  // e stampo il messaggio di benvenuto
  Serial.begin(9600);
  while(!Serial);
  Serial.println("Benvenuto nel Servizio di Chat via LoRa!");

  // inizializzo il modem LoRa
  // se viene restituito un errore fermo il programma
  if (!LoRa.begin(868E6)) {
    Serial.println("Errore nell'avvio del modem!");
    while (true);
  }
  // pausa per lasciar stabilizzare il modem
  delay(1000);
}

void loop() {

  if (Serial.available()) {
    String messaggio = Serial.readString();
  

    if (messaggio.length() > 0) {
      Serial.println(mioNome + ": " + messaggio); //visualizzato sul serial monitor

      // Trasmissione pacchetto LoRa
      LoRa.beginPacket();
      LoRa.write(indirizzoDestinatario);              
      LoRa.write(mioIndirizzo);
      LoRa.print(mioNome +": " + messaggio); //inviato sul canale LoRa
      LoRa.endPacket();
   }
  }
  // Verifico se è arrivato un messaggio per me
  riceviMessaggio(LoRa.parsePacket());

}

void riceviMessaggio(int packetSize) {
  if (packetSize == 0) return;          // se non ci sono messaggi termina la funzione
  
  // Leggo i primi due byte del pacchetto ricevuto
  int destinatario = LoRa.read();
  int mittente = LoRa.read();

  // inizializzo a stringa vuota la stringa che conterrà il msg ricevuto
  String msgRicevuto = "";

  // leggo il contenuto del buffer di ricezione
  // questa operazione deve essere sempre fatta
  // per svuotare il buffer
  while (LoRa.available()) {
    msgRicevuto += (char)LoRa.read();
  }

  // Verifico se il pacchetto ricevuto è destinato a me
  if ((destinatario != mioIndirizzo) || (mittente != indirizzoDestinatario)) {
    // Serial.println("Questo messaggio non è per me.");
    // il messaggio non è per me quindi termino la funzione
    return;                             
  }
  // stampo sul terminale il messaggio ricevuto
  Serial.print(msgRicevuto);

  // stampo sul terminale il valore RSSI del pacchetto ricevuto
  Serial.print(" || RSSI: ");
  Serial.println(LoRa.packetRssi());
  Serial.println();
}

Come ha visto nel video, questo sketch Arduino implementa un semplice sistema di chat utilizzando il protocollo di comunicazione LoRa.

Riportiamo per tua comodità la descrizione dettagliata delle sue funzionalità:

1. Area globale
  • Inclusione delle librerie: Lo sketch include le librerie SPI.h e LoRa.h necessarie per la comunicazione LoRa.
  • Definizione dei parametri: Vengono definiti il nome locale mioNome (Alice), l’indirizzo locale mioIndirizzo (0xAA), e l’indirizzo del destinatario indirizzoDestinatario (0xBB).
2. Funzione setup()
  • Inizializzazione della comunicazione seriale: La comunicazione seriale viene avviata con Serial.begin(9600), e il programma attende finché la connessione seriale non è pronta.
  • Messaggio di benvenuto: Viene stampato un messaggio di benvenuto sul terminale seriale: “Benvenuto nel Servizio di Chat via LoRa!“.
  • Inizializzazione del modem LoRa: Viene avviato il modem LoRa sulla frequenza 868 MHz con LoRa.begin(868E6). Se l’inizializzazione fallisce, viene stampato un messaggio di errore e il programma si blocca in un ciclo infinito.
  • Pausa di stabilizzazione: Viene introdotto un ritardo di 1000 ms per permettere al modem di stabilizzarsi.
3. Funzione loop()
  • Lettura dalla seriale: Se ci sono dati disponibili sulla seriale, questi vengono letti e memorizzati in una stringa messaggio.
  • Trasmissione del messaggio via LoRa: Se la lunghezza del messaggio è maggiore di zero, viene:
  • Stampato il messaggio sul terminale seriale.
  • Preparato il pacchetto LoRa con LoRa.beginPacket().
  • Scritti gli indirizzi del destinatario e del mittente nel pacchetto.
  • Aggiunto il contenuto del messaggio formattato attraverso una concatenazione di stringhe mioNome + “: ” + messaggio.
  • Inviato il pacchetto con LoRa.endPacket().
  • Verifica di messaggi ricevuti: La funzione riceviMessaggio(LoRa.parsePacket()) viene chiamata per verificare se ci sono messaggi in arrivo.
4. Funzione riceviMessaggio(int packetSize)
  • Controllo della dimensione del pacchetto: Se packetSize è zero, la funzione termina.
  • Lettura degli indirizzi dal pacchetto: Vengono letti i primi due byte del pacchetto per determinare il destinatario e il mittente.
  • Lettura del contenuto del messaggio: Il messaggio viene letto dal buffer LoRa e memorizzato in msgRicevuto.
  • Verifica del destinatario: Se il destinatario non è l’indirizzo locale o il mittente non è l’indirizzo del destinatario atteso, la funzione termina.
  • Stampa del messaggio: Il messaggio ricevuto viene stampato sul terminale seriale.
  • Stampa del valore RSSI: Viene stampato il valore RSSI (Received Signal Strength Indicator) del pacchetto ricevuto, che indica la potenza del segnale.

Lo sketch che corrisponde al ruolo di “Bob” è identico al precedente, con l’unica differenza che le variabili mioNome, mioIndirizzo e indirizzoDestinatario sono ovviamente diverse.

Per tua comodità, di seguito è riportato anche questa versione dello sketch.

#include <SPI.h>
#include <LoRa.h>

// parametrizzo l'indirizzo locale e quello di destinazione
String mioNome = "Bob";
byte mioIndirizzo = 0xBB;  
byte indirizzoDestinatario = 0xAA;

void setup() {
  // inizializzo la comunicazione seriale
  // attend'apert del tenale seriale
  // e stampo il messaggio di benvenuto
  Serial.begin(9600);
  while(!Serial);
  Serial.println("Benvenuto nel Servizio di Chat via LoRa!");

  // inizializzo il modem LoRa
  // se viene restituito un errore fermo il programma
  if (!LoRa.begin(868E6)) {
    Serial.println("Errore nell'avvio del modem!");
    while (true);
  }
  // pausa per lasciar stabilizzare il modem
  delay(1000);
}

void loop() {

  if (Serial.available()) {
    String messaggio = Serial.readString();
  

    if (messaggio.length() > 0) {
      Serial.println(mioNome + ": " + messaggio); //visualizzato sul serial monitor

      // Trasmissione pacchetto LoRa
      LoRa.beginPacket();
      LoRa.write(indirizzoDestinatario);              
      LoRa.write(mioIndirizzo);
      LoRa.print(mioNome +": " + messaggio); //inviato sul canale LoRa
      LoRa.endPacket();
   }
  }
  // Verifico se è arrivato un messaggio per me
  riceviMessaggio(LoRa.parsePacket());

}

void riceviMessaggio(int packetSize) {
  if (packetSize == 0) return;          // se non ci sono messaggi termina la funzione
  
  // Leggo i primi due byte del pacchetto ricevuto
  int destinatario = LoRa.read();
  int mittente = LoRa.read();

  // inizializzo a stringa vuota la stringa che conterrà il msg ricevuto
  String msgRicevuto = "";

  // leggo il contenuto del buffer di ricezione
  // questa operazione deve essere sempre fatta
  // per svuotare il buffer
  while (LoRa.available()) {
    msgRicevuto += (char)LoRa.read();
  }

  // Verifico se il pacchetto ricevuto è destinato a me
  if ((destinatario != mioIndirizzo) || (mittente != indirizzoDestinatario)) {
    // Serial.println("Questo messaggio non è per me.");
    // il messaggio non è per me quindi termino la funzione
    return;                             
  }
  // stampo sul terminale il messaggio ricevuto
  Serial.print(msgRicevuto);

  // stampo sul terminale il valore RSSI del pacchetto ricevuto
  Serial.print(" || RSSI: ");
  Serial.println(LoRa.packetRssi());
  Serial.println();
}