Com a constante evolução tecnológica, tanto em telecomunicações quanto em sistemas embarcados, muitas soluções inviáveis ou impraticáveis há alguns (poucos) anos agora são perfeitamente possíveis de serem realizadas. Uma das evoluções mais significativas em telecomunicações foi a popularização da conectividade LPWAN (Low Power Wide Area Network), que consiste em redes de conectividade focadas em alcance longo (algumas dezenas de quilômetros, em alguns casos) ao custo de baixíssimo consumo energético e baixo tráfego de dados ( = baixa quantidade de bytes transmitidos por mensagem e poucas mensagens ao dia). Das LPWANs disponíveis no mercado atualmente, um dos nomes mais fortes é LoRaWAN, devido a ser muito flexível em termos de infraestrutura e com transceivers facilmente encontrados no mercado.
Associando LoRaWAN às aplicações com microcontroladores pode-se, por exemplo, monitorar grandezas muito relevantes à distância, e considerando o longo alcance que LoRaWAN pode ter, o dispositivo pode estar em uma área de difícil acesso que mesmo assim é possível fazer tal monitoramento.
Este artigo visa mostrar uma aplicação prática neste sentido, com um projeto de um dispositivo capaz de monitorar nível (de reservatórios de algo líquido ou sólido) à distância, com LoRaWAN.
Material necessário
Para reproduzir o projeto aqui abordado, você precisará dos seguintes items:
Um kit de desenvolvimento ESP32 (link de referência: https://www.filipeflop.com/produto/modulo-wifi-esp32-bluetooth/ ), conforme mostra a figura 1.
Um cabo micro-USB para alimentação e programação do ESP32 (link de referência: https://www.filipeflop.com/produto/cabo-micro-usb-1-metro/ )
Um módulo LoRaWAN do fabricante Radioenge (link de referência: https://www.radioenge.com.br/produto/modulo-lorawan/ ), conforme visto na figura 2.
Um protoboard de 830 pontos (link de referência: https://www.filipeflop.com/produto/protoboard-830-pontos/ )
Um sensor de distância ultrassônico HC-SR04 (link de referência: https://www.filipeflop.com/produto/sensor-de-distancia-ultrassonico-hc-sr04/ )
Dois resistores 10k / 1/4W (link de referência: https://www.filipeflop.com/produto/resistor-10k%cf%89-14w-x20-unidades/ )
Jumpers macho-macho (link de referência: https://www.filipeflop.com/produto/kit-jumpers-macho-macho-x65-unidades/ )
Como medir o nível de um reservatório com um sensor ultrassônico de distância?
O sensor ultrassônico de distância consiste em um sensor contendo dois elementos: um transmissor e um receptor ultrassônico. Este sensor é usado para medir distâncias (de 2 centímetros até 4 metros), utilizando como base a velocidade do som no ar e a diferença de tempo entre emissão e recepção de um sinal ultrassônico. Observe a figura 3.
Seu funcionamento pode ser descrito da seguinte maneira:
Ao ser dado o “gatilho” / trigger, o transmissor ultrassônico faz a emissão de um sinal sonoro em frequência ultrassônica. Tal frequência é inaudível por nós, humanos.
Ao atingir a superfície de um objeto, este sinal sonoro ultrassônico é refletido novamente para o sensor, onde é captado pelo receptor ultrassônico.
No momento da recepção, é gerado no sensor um sinal de eco (echo), indicando que o sinal ultrassônico emitido foi captado.
Como o dispositivo que controla o sensor ultrassônico sabe o momento em que o gatilho foi dado e também quando este chegou (em função da recepção do sinal de echo), e também conhecendo a velocidade de propagação do som no ar (340m/s), é possível determinar a distância entre o sensor ultrassônico e a superfície atingida por:
É importante ressaltar que o som em frequência ultrassônica é refletido tanto ao atingir superfícies de sólidos quanto líquidos. Logo, este método aqui descrito se aplica para ambos os tipos de materiais.
Uma vez em posse da distância entre sensor e objeto, é possível determinar o nível do reservatório (em metros) por:
Sendo:
H: altura total do sensor até o fundo do reservatório
Dobj: distância medida pelo sensor ultrassônico, correspondente a altura do sensor até o nível do líquido
Dsensor: distância entre o sensor e a borda do reservatório
LoRaWAN: hardware para fazer a conectividade
Das formas disponíveis de um hardware para se utilizar conectividade LoRaWAN, uma das mais simples e práticas maneiras é usar um módulo LoRaWAN de mercado. Estes módulos consistem de placas eletrônicas (similar a um shield / placa soquetada) que já contém toda a circuitaria necessária para, a partir de comandos AT via interface UART, configurar e estabelecer uma comunicação LoRaWAN. Estes módulos LoRaWAN contém:
Circuitaria de radiofrequência com soquete para antena externa ou, em alguns casos, antena desenhada na própria PCB;
Um microcontrolador simples, também usualmente low-power ou ultra low-power, para permitir comunicação serial entre o rádio LoRa do módulo e o microcontrolador principal do projeto. Ainda, tal microcontrolador do módulo LoRaWAN contém embarcada a stack LoRaWAN, de forma a dividir tarefas e diminuir a complexidade do projeto;
Um rádio LoRa (para a faixa de frequência LoRaWAN no Brasil, uma possibilidade é o SX1276);
Circuitaria de alimentação e proteções pertinentes ao módulo.
Estes módulos possuem enorme facilidade de uso, uma vez que simples comandos AT enviados via UART podem permitir a conectividade LoRaWAN do projeto desejado, pois assim delega-se ao módulo todas as responsabilidades da comunicação LoRaWAN. Ainda, desta maneira, pode se contar com módulos já devidamente testados e, inclusive, homologados na Anatel, sendo, portanto, um ponto extremamente importante se você almeja construir um produto com LoRaWAN.
Neste artigo, é utilizado o módulo LoRaWAN do fabricante Radioenge, mostrado na Figura 2 (link: https://www.radioenge.com.br/produto/modulo-lorawan/ ). Este módulo possui dimensões muito diminutas (3mm x 22mm x 33mm), opera nos modos de operação LoRaWAN OTAA e ABP e utiliza uma UART (3V3, com 9600 de baudrate, 8 bits, sem paridade e um stop-bit) como interface de comunicação com microcontrolador principal do projeto. Em termos de potência, disponibiliza uma potência de transmissão de 20dBm e comporta uso de antena sintonizada na frequência 915MHz com conector SMA (o módulo inclusive acompanha uma antena com 2.1dBi de ganho isotrópico).
Este módulo é homologado na Anatel (Código: 02021-18-07215) e pode, portanto, ser integrado com segurança em um produto eletrônico. O datasheet completo do módulo pode ser acessado em: https://www.radioenge.com.br/storage/2021/08/manual-lorawan-2021.pdf .
Circuito esquemático
O circuito esquemático do projeto pode ser visto na figura 4.
Código-fonte do projeto
Segue abaixo o código-fonte completo do projeto.
Importante: não se esqueça de substituir as credenciais / chaves LoRaWAN (network session key, application session key, device address e application EUI) pelas credenciais a serem usadas pelo seu projeto, assim como as alturas / distâncias pelas do seu reservatório.
#include <Ultrasonic.h>
/* Definições - sensor ultrassônico */
#define TRIGGER_PIN 26
#define ECHO_PIN 25
/* Definições - serial para módulo LoRaWAN */
#define UART_LORAWAN_BAUDRATE 9600
#define UART_LORAWAN_RX 14
#define UART_LORAWAN_TX 13
#define TAM_NWSKEY_APPSKEY 60
#define TAM_APPEUI 30
#define TAM_DEVADDR 15
/* Definições - parâmetros de medição de distância */
#define NUM_MEDIDAS_DISTANCIA 10
#define ALTURA_TOTAL_SENSOR_ATE_FUNDO 200 //cm
#define DISTANCIA_SENSOR_RESERVATORIO 30 //cm
/* Definições - debug */
#define MOSTRA_DEBUG
#define NUM_LINHAS_PARA_PULAS 80
/* Credenciais LoRaWAN */
const char nwskey[TAM_NWSKEY_APPSKEY] = "NNNNNNNNNN\0"; // Network session key
const char appskey[TAM_NWSKEY_APPSKEY] = "AAAAAAAAAA\0"; // Application session key
const char appeui[TAM_APPEUI] = "AAAAAAAAAA\0"; // Application EUI
const char devaddress[TAM_DEVADDR] = "EEEEEEEEEE\0"; // Device Address
//variaveis e objetos globais
Ultrasonic ultrasonic(TRIGGER_PIN, ECHO_PIN);
unsigned long timestamp_envio = 0;
//prototypes
int mede_distancia_centimetros(void);
int calcula_media_distancias(void);
/*
* Implementações
*/
/*
* Função: Média de medidas de distância
* Parâmetros: nenhum
* Retorno: média das medidas de distância
*/
int calcula_media_distancias(void)
{
int i;
int soma_medidas;
int media;
soma_medidas = 0.0;
for(i=0; i<NUM_MEDIDAS_DISTANCIA; i++)
soma_medidas = soma_medidas + mede_distancia_centimetros();
media = (soma_medidas / NUM_MEDIDAS_DISTANCIA);
return media;
}
/*
* Função: mede distancia em centímetros
* Parametros: nenhum
* Retorno: distancia (cm)
*/
int mede_distancia_centimetros(void)
{
int cmMsec;
long microsec = ultrasonic.timing();
cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM);
#ifdef MOSTRA_DEBUG
Serial.println("[DADOS DO SENSOR]");
Serial.print("Tempo(ms): ");
Serial.print(microsec);
Serial.print(", Distancia(cm): ");
Serial.print(cmMsec);
#endif
return cmMsec;
}
/*
* Função: envia comando AT para módulo LoRaWAN
* Parametros: ponteiro para comando AT a ser enviado e tamanho
* do comando
* Retorno: nenhum
*/
void envia_comando_at(char * pt_cmd_at, int tamanho)
{
Serial2.write(pt_cmd_at, tamanho);
delay(1000);
Serial.print("Comando enviado: ");
Serial.println(pt_cmd_at);
Serial.println("Resposta: ");
while(Serial2.available())
{
Serial.print(Serial2.read());
}
Serial.println("");
}
void setup()
{
char comando_at[200] = {0};
int tam_comando;
Serial.begin(115200);
Serial.println("Dispositivo iniciado");
/* Configura módulo LoRaWAN */
Serial.println("Configurando modulo LoRaWAN...");
Serial2.begin(UART_LORAWAN_BAUDRATE, SERIAL_8N1, UART_LORAWAN_RX, UART_LORAWAN_TX);
/* Envio do channel mask */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+CHMASK=00FF:0000:0000:0000:0000:0000\n\r");
envia_comando_at(comando_at, strlen(comando_at));
/* Envio do join mode */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+NJM=0\n\r");
envia_comando_at(comando_at, strlen(comando_at));
/* Envio do device address */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+DADDR=%s\n\r", devaddress);
envia_comando_at(comando_at, strlen(comando_at));
/* Envio do application EUI */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+APPEUI=%s\n\r", appeui);
envia_comando_at(comando_at, strlen(comando_at));
/* Envio do application session key */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+APPSKEY=%s\n\r", appskey);
envia_comando_at(comando_at, strlen(comando_at));
/* Envio do network session key */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+NWKSKEY=%s\n\r", nwskey);
envia_comando_at(comando_at, strlen(comando_at));
/* Desabilita ADR (Automatic Data Rate) */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+ADR=0\n\r");
envia_comando_at(comando_at, strlen(comando_at));
/* Configura Data Rate e Spread Factor para máximo alcance
e menor payload. Aqui, o consumo do módulo é o maior
possível, porém a chance do payload chegar ao gateway é
significativamente maior.
*/
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+DR=0\n\r");
envia_comando_at(comando_at, strlen(comando_at));
/* Configura classe A para o LoRaWAN */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+CLASS=A\n\r");
envia_comando_at(comando_at, strlen(comando_at));
/* Liga confirmação de envio */
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+CFM=1\n\r");
envia_comando_at(comando_at, strlen(comando_at));
Serial.println("Modulo LoRaWAN configurado!");
timestamp_envio = millis();
}
void loop()
{
int distancia_cm;
int nivel_calculado;
char comando_at[200] = {0};
int tam_comando;
int i;
/* faz as mmedição da distância (considerando a media) e
calcula nível
*/
distancia_cm = calcula_media_distancias();
nivel_calculado = ALTURA_TOTAL_SENSOR_ATE_FUNDO - (distancia_cm - DISTANCIA_SENSOR_RESERVATORIO);
for (i=0; i<NUM_LINHAS_PARA_PULAS; i++)
Serial.println("");
#ifdef MOSTRA_DEBUG
Serial.println("[DADOS DA MEDICAO]");
Serial.print("Medida: ");
Serial.print(distancia_cm);
Serial.println("cm");
Serial.print("Nuvel: ");
Serial.print(nivel_calculado);
Serial.print("cm");
#endif
/* Envia, de hora em hora, o nivel medido */
if ( (millis() - timestamp_envio) >= 3600000 )
{
Serial.println("Enviando nivel...");
memset(comando_at, 0x00, sizeof(comando_at));
snprintf(comando_at, sizeof(comando_at), "AT+SEND=%d:%d\n\r", nivel_calculado);
envia_comando_at(comando_at, strlen(comando_at));
Serial.println("Nivel enviado!");
timestamp_envio = millis();
}
delay(5000);
}
Uma vez feito o upload do código-fonte ao ESP32, as mensagens contendo o nível (em centímetros) do reservatório monitorado serão enviadas a cada hora via LoRaWAN.
Conclusão
Neste artigo, foi possível observar como fazer o monitoramento remoto via LoRaWAN de nível (de sólidos ou líquidos). Desta forma, é possível monitorar reservatórios de insumos importantes (alimentos em comedouros de animais, água, nível de silos, etc.) utilizando pouca energia elétrica e em um alcance de até algumas dezenas de quilômetros.
Este projeto pode facilmente ser expandido e modificado para o monitoramento de outras grandezas (exemplo: temperatura, umidade do ar, pressão atmosférica, etc.), de forma a servir de base para muitos projetos em âmbito urbano ou rural.