En esta oportunidad quiero contarte sobre algunas pruebas que he estado haciendo con la tecnología inalámbrica LoRa. En particular, me interesan las pruebas de LoRa sin línea de vista, para ver su comportamiento en situaciones reales en un entorno urbano.
Hace tiempo que soy un entusiasta promotor de esta tecnología, que promete cambiar el panorama IoT en todo el mundo. Si te interesa aprender sobre LoRaWAN, aquí te dejo unos artículos sobre el tema.
Qué es la tecnología LoRa y por qué es importante para IoT
LoRa – Características y Aplicaciones
Cómo es la arquitectura LoRaWAN
El gateway LoRa de TTN para su comunidad
A principios de este año asistí a la conferencia de The Things Network en Amsterdam, Países Bajos. Fue una experiencia sorprendente y volví con la convicción de que tenemos mucho por hacer en Latinoamérica para poder aprovechar las ventajas y oportunidades que ofrece esta tecnología.
En esta ocasión he utilizado solo la capa física LoRa, es decir no implementé una solución LoRaWAN, con gateway y demás. Mi intención fue simplemente hacer unas pruebas de alcance dentro del complejo de edificios donde vivo.
La configuración
Lo que hice fue comunicar dos nodos, uno funcionando como transmisor y otro como receptor.
El hardware que utilicé para esta prueba fue la placa de desarrollo TTGO LoRa V2 basada en ESP32. Esta placa ofrece comunicación LoRa, Bluetooth y WiFi, por lo que es muy conveniente para desarrollar prototipos.
La programación de los nodos la hice de la siguiente manera:
- El transmisor envía un mensaje donde indica el número de transmisión. La transmisión se produce cada un segundo, aunque se puede utilizar cualquier otra frecuencia de envío.
- En el display del receptor se puede ver la potencia recibida en el mensaje y el número de mensaje. De este modo se puede saber si se están recibiendo todos los mensajes o si pierden algunos.
El código
Para hacer estas pruebas utilicé código prestado de Random Nerd Tutorials.
//Libraries for LoRa
#include <spi.h>
#include <lora.h>
//Libraries for OLED Display
#include <wire.h>
#include <adafruit_gfx.h>
#include <adafruit_ssd1306.h>
//define the pins used by the LoRa transceiver module
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
//433E6 for Asia
//866E6 for Europe
//915E6 for North America
#define BAND 866E6
//OLED pins
#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_RST 16
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
String LoRaData;
void setup() {
//reset OLED display via software
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(20);
digitalWrite(OLED_RST, HIGH);
//initialize OLED
Wire.begin(OLED_SDA, OLED_SCL);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(0,0);
display.print("LORA RECEIVER ");
display.display();
//initialize Serial Monitor
Serial.begin(115200);
Serial.println("LoRa Receiver Test");
//SPI LoRa pins
SPI.begin(SCK, MISO, MOSI, SS);
//setup LoRa transceiver module
LoRa.setPins(SS, RST, DIO0);
if (!LoRa.begin(BAND)) {
Serial.println("Starting LoRa failed!");
while (1);
}
Serial.println("LoRa Initializing OK!");
display.setCursor(0,10);
display.println("LoRa Initializing OK!");
display.display();
}
void loop() {
//try to parse packet
int packetSize = LoRa.parsePacket();
if (packetSize) {
//received a packet
Serial.print("Received packet ");
//read packet
while (LoRa.available()) {
LoRaData = LoRa.readString();
Serial.print(LoRaData);
}
//print RSSI of packet
int rssi = LoRa.packetRssi();
Serial.print(" with RSSI ");
Serial.println(rssi);
// Dsiplay information
display.clearDisplay();
display.setCursor(0,0);
// display.print("LORA RECEIVER");
// display.setCursor(0,20);
// display.print("Received packet:");
display.setCursor(0,10);
display.print(LoRaData);
display.setCursor(0,30);
display.print("RSSI:");
display.setCursor(30,50);
display.print(rssi);
display.display();
}
}
//Libraries for LoRa
#include <spi.h>
#include <lora.h>
//Libraries for OLED Display
#include <wire.h>
#include <adafruit_gfx.h>
#include <adafruit_ssd1306.h>
//define the pins used by the LoRa transceiver module
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
//433E6 for Asia
//866E6 for Europe
//915E6 for North America
#define BAND 866E6
//OLED pins
#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_RST 16
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
//packet counter
int counter = 0;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
void setup() {
//reset OLED display via software
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(20);
digitalWrite(OLED_RST, HIGH);
//initialize OLED
Wire.begin(OLED_SDA, OLED_SCL);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(0,5);
display.print("LORA SENDER ");
display.display();
//initialize Serial Monitor
Serial.begin(115200);
Serial.println("LoRa Sender Test");
//SPI LoRa pins
SPI.begin(SCK, MISO, MOSI, SS);
//setup LoRa transceiver module
LoRa.setPins(SS, RST, DIO0);
if (!LoRa.begin(BAND)) {
Serial.println("Starting LoRa failed!");
while (1);
}
Serial.println("LoRa Initializing OK!");
display.setCursor(0,20);
display.print("LoRa Initializing OK!");
display.display();
delay(2000);
}
void loop() {
Serial.print("Sending packet: ");
Serial.println(counter);
//Send LoRa packet to receiver
LoRa.beginPacket();
LoRa.print("hello ");
LoRa.print(counter);
LoRa.endPacket();
display.clearDisplay();
display.setCursor(0,5);
//display.println("LORA SENDER");
display.setCursor(0,20);
display.setTextSize(2);
display.print("LoRa packet sent.");
display.setCursor(0,10);
display.print("Counter:");
display.setCursor(80,50);
display.print(counter);
display.display();
counter++;
delay(10000);
}
Es importante modificar algunos valores del código para que este se adapte a la placa que vayas a usar, ya que cambian números de pines, frecuencias, etc.
Las pruebas
Con esta configuración dejé el nodo transmisor en el balcón de mi departamento y salí a caminar con el receptor. Y ahora sí ya pude hacer las pruebas de LoRa sin línea de vista.
Durante el transcurso de mi caminata pude ver que la conexión se mantenía aun sin tener línea de vista en absoluto, que por otro lado era lo esperado. De hecho, caminando entre los edificios la recepción era bastante buena y logré cobertura en la mayor parte del trayecto, salvo puntos muy específicos.
En la figura siguiente muestro dos puntos específicos donde obtuve una potencia de -115 dBm sin pérdida de mensajes. Algo notable considerando que la prueba era en sí bastante precaria y estaba utilizando antenas de muy baja ganancia en ambos nodos.
Conclusión
La tecnología LoRa ofrece grandes oportunidades en la implementación de sistemas IoT, por su largo alcance y bajo consumo. Esto permite desplegar nodos fácilmente, sin depender de otra infraestructura de comunicación.
Además, el muy bajo consumo eléctrico hace que los nodos puedan ser alimentados por baterías, evitando la complicación de una instalación eléctrica. También se pueden utilizar pequeñas pantallas solares o alguna otra técnica de cosecha de energía (energy harvesting).
Por último hay que tener en cuenta que estas pruebas se hicieron para evaluar la fiabilidad de conectar sensores en los alrededores. No se evaluó la máxima distancia posible de conexión ni se maximizó la configuración del hardware para esto último.
Te invito a que dejes tus dudas y comentarios abajo ;).
</adafruit_ssd1306.h></adafruit_gfx.h></wire.h></lora.h></spi.h></adafruit_ssd1306.h></adafruit_gfx.h></wire.h></lora.h></spi.h>