No artigo sobre a medição de turbidez com módulo WiFi LoRa 32(V2) - MEC324 foi mostrado desde os fundamentos e importância da turbidez da água até a como medi-la utilizando um sensor apropriado. Expandindo esta ideia, este artigo mostrará como fazer com que a medição, feito com o módulo citado, pode ser transmitida a outro módulo utilizando a tecnologia LoRa. Desta forma, a distância entre os módulos de medição e módulo de recepção poderão ser grandes (chegando na casa de alguns quilômetros), o que viabiliza aplicações reais e dentro do contexto urbano deste tipo de medição. Ainda, com mais alguns poucos incrementos e modificações, este projeto pode ser facilmente inserido no contexto da Internet das Coisas (IoT), se tornando uma aplicação interessante para projetos na área de cidades inteligentes (Smart Cities).
- Material necessário
- Para fazer o projeto deste artigo você precisará de:
- Dois módulos WiFi LoRa 32(V2)
- Um sensor de turbidez SKU: SEN0189
- Dois resistores de 18k 1/4W
- Dois resistores de 2k 1/4W
- Protoboard de 400 pontos ou maior
- Jumpers macho-macho
- Cabo micro-USB
- Duas fontes chaveadas 5V/2A micro-USB
Overview do projeto
O projeto abordado neste artigo consiste na expansão do abordado no artigo de Medição de turbidez com módulo WiFi LoRa 32(V2).
Aqui, um dos módulos WiFi LoRa 32(V2) faz a medição da turbidez da água. Este irá enviar utilizando LoRa (Fazendo uso da topologia ponto-a-ponto, conforme abordado neste nosso artigo) a turbidez medida para outro módulo WiFi LoRa 32(V2), o qual irá exibir a informação recebida em seu display OLED.
Observe o diagrama de funcionamento do projeto na figura 1.
Este projeto permite, portanto, o monitoramento a distância / monitoramento remoto da turbidez da água. Isso é algo muito útil em se tratando tanto de ambientes urbanos quanto rurais, onde a água cuja turbidez deve ser monitorada pode estar em local de difícil acesso.
Circuito esquemático - módulo medidor
O circuito esquemático do módulo medidor é exatamente igual ao do artigo de Medição de turbidez com módulo WiFi LoRa 32(V2).
Desta forma, monte o circuito esquemático do módulo medidor conforme é mostrado pela figura 2.
Circuito esquemático - módulo receptor
Como o módulo receptor utilizará apenas recursos de hardware já contidos no módulo WiFi LoRa 32(V2), você não precisa de circuitos externo ao módulo.
Em suma, o próprio módulo WiFi LoRa 32(V2) já é suficiente como módulo receptor.
Código-fonte - módulo medidor
O código-fonte do módulo medidor está abaixo. Preste bastante atenção nos comentários para maior entendimento do programa.
Você perceberá que é enviado de segundo em segundo a turbidez da água medida. Além disso, perceberá que o módulo medidor não irá utilizar o display OLED.
#include <LoRa.h> #include <SPI.h> #include <Wire.h> /* Definicoes para comunicação com radio LoRa */ #define SCK_LORA 5 #define MISO_LORA 19 #define MOSI_LORA 27 #define RESET_PIN_LORA 14 #define SS_PIN_LORA 18 #define HIGH_GAIN_LORA 20 /* dBm */ #define BAND 915E6 /* 915MHz de frequencia */ /* Definições gerais */ #define DEBUG_SERIAL_BAUDRATE 115200 /* Definições do buffer (para filtro de média móvel) */ #define TAMANHO_BUFFER 50 /* Definições da leitura do sensor de turbidez */ #define ADC_MAX 4095 /* ADC do modulo WiFi LoRa 32(V2) tem 12 bits de resolucao */ #define ENTRADA_ANALOGICA_SENSOR_TURBIDEZ 13 /* GPIO 13 => ADC2_CH4 */ #define TENSAO_MAXIMA_SAIDA_SENSOR_TURBIDEZ 5 /* Sensor apresenta saida analogica de 0 a 5V */ #define FATOR_DIVISOR_TENSAO 10 /* No projeto, para serem respeitados os limites de operação do ADC e fazer com que a tensão do sensor excursione corretamente em todo seu range, ha um divisor resistivo para que a tensão lida pelo canal do ADC utilizado seja igual a 10% da tensão real de saída do sensor. Portanto, no cálculo da tensão real, este fator é utilizado para se recuperar corretamente este valor */ #define NUM_LEITURAS_OVERSAMPLING 512 /* Variáveis globais */ float buffer_tensao_sensor_turbidez[TAMANHO_BUFFER]; /* Protótipos */ bool init_comunicacao_lora(void); float le_tensao_sensor_turbidez_sem_filtro(void); float le_tensao_sensor_turbidez_com_filtro(void); float le_turbidez_da_agua(void); /* Função: inicia comunicação com chip LoRa * Parâmetros: nenhum * Retorno: true: comunicação ok * false: falha na comunicação */ bool init_comunicacao_lora(void) { bool status_init = false; Serial.println("[Modulo medidor] Tentando iniciar comunicacao com o radio LoRa..."); SPI.begin(SCK_LORA, MISO_LORA, MOSI_LORA, SS_PIN_LORA); LoRa.setPins(SS_PIN_LORA, RESET_PIN_LORA, LORA_DEFAULT_DIO0_PIN); if (!LoRa.begin(BAND)) { Serial.println("[Modulo medidor] Comunicacao com o radio LoRa falhou. Nova tentativa em 1 segundo..."); delay(1000); status_init = false; } else { /* Configura o ganho do receptor LoRa para 20dBm, o maior ganho possível (visando maior alcance possível) */ LoRa.setTxPower(HIGH_GAIN_LORA); Serial.println("[Modulo medidor] Comunicacao com o radio LoRa ok"); status_init = true; } return status_init; } /* Função: faz a leitura da tensão de saída do sensor de turbidez (sem filtro) * Parâmetros: nenhum * Retorno: tensão de saída (de 0 até 5V) */ float le_tensao_sensor_turbidez_sem_filtro(void) { float tensao_saida_sensor = 0.0; int leitura_adc = 0; /* Faz a leitura do canal do ADC do modulo que a saida do sensor de turbidez está ligado */ leitura_adc = analogRead(ENTRADA_ANALOGICA_SENSOR_TURBIDEZ); /* converte a leitura do ADC (canal onde está ligada a saída do sensor de turbidez) em uma tensão de leitura de 0 a 5V */ tensao_saida_sensor = ((leitura_adc/(float)ADC_MAX)*(float)TENSAO_MAXIMA_SAIDA_SENSOR_TURBIDEZ); Serial.print("[Modulo medidor] Tensao de saida (no divisor): "); Serial.print(tensao_saida_sensor); Serial.println("V"); tensao_saida_sensor = tensao_saida_sensor*FATOR_DIVISOR_TENSAO; /* Corrige a leitura com base no divisor resistivo utilizado */ return tensao_saida_sensor; } /* Função: faz a leitura da tensao de saida do sensor de turbidez (com filtro) * Parâmetros: nenhum * Retorno: tensão de saída (de 0 até 5V) */ float le_tensao_sensor_turbidez_com_filtro(void) { float tensao_saida_sensor = 0.0; int leitura_adc = 0; long soma_leituras_adc = 0; int i = 0; float soma = 0.0; float tensao_filtrada = 0.0; /* Faz a leitura do canal do ADC do modulo que a saída do sensor de turbidez está ligado */ /* Para amenizar efeitos de leituras ruidosas / com oscilações, um oversampling é feito */ soma_leituras_adc = 0; for (i=0; i<NUM_LEITURAS_OVERSAMPLING; i++) soma_leituras_adc = soma_leituras_adc + analogRead(ENTRADA_ANALOGICA_SENSOR_TURBIDEZ); leitura_adc = soma_leituras_adc/NUM_LEITURAS_OVERSAMPLING; /* converte a leitura do ADC (canal onde está ligada a saída do sensor de turbidez) em uma tensão de leitura de 0 a 5V */ tensao_saida_sensor = ((leitura_adc/(float)ADC_MAX)*(float)TENSAO_MAXIMA_SAIDA_SENSOR_TURBIDEZ); Serial.print("Counts de ADC: "); Serial.println(leitura_adc); Serial.print("[Modulo medidor] Tensao de saida (no divisor): "); Serial.print(tensao_saida_sensor); Serial.println("V"); tensao_saida_sensor = tensao_saida_sensor*FATOR_DIVISOR_TENSAO; /* Corrige a leitura com base no divisor resistivo utilizado */ /* Desloca para a esquerda todas as medidas de tensão já feitas */ for(i=1; i<TAMANHO_BUFFER; i++) buffer_tensao_sensor_turbidez[i-1] = buffer_tensao_sensor_turbidez[i]; /* Insere a nova medida na última posição do buffer */ buffer_tensao_sensor_turbidez[TAMANHO_BUFFER-1] = tensao_saida_sensor; /* Calcula a média do buffer (valor da média móvel, ou valor filtrado) */ soma = 0.0; tensao_filtrada = 0.0; for(i=0; i<TAMANHO_BUFFER; i++) soma = soma + buffer_tensao_sensor_turbidez[i]; tensao_filtrada = soma/TAMANHO_BUFFER; return tensao_filtrada; } /* Função: faz a leitura da turbidez da agua * Parâmetros: nenhum * Retorno: turbidez da água (em NTU) */ float le_turbidez_da_agua(void) { float turbidez_agua = 0.0; float tensao_filtrada = 0.0; float primeiro_fator = 0.0; float segundo_fator = 0.0; float terceiro_fator = 0.0; /* Faz a leitura da tensão filtrada do sensor de turbidez */ tensao_filtrada = le_tensao_sensor_turbidez_com_filtro(); /* Limita a tensão a máxima permitida pelo sensor */ if (tensao_filtrada > 4.2) tensao_filtrada = 4.2; Serial.print("[Modulo medidor] Tensao de saida do sensor de turbidez: "); Serial.print(tensao_filtrada); Serial.println("V"); /* Calcula a turbidez */ primeiro_fator = ((-1)*(1120.4) * tensao_filtrada * tensao_filtrada); segundo_fator = (5742.3 * tensao_filtrada); terceiro_fator = ((-1)*4352.9); turbidez_agua = primeiro_fator + segundo_fator + terceiro_fator; return turbidez_agua; } /* Função de setup */ void setup() { int i; Serial.begin(DEBUG_SERIAL_BAUDRATE); /* Configura ADC em sua resolução máxima (12 bits) */ analogReadResolution(12); /* Inicializa buffer de leituras de tensão do sensor de turbidez (para inicializar o buffer do filtro de média móvel)*/ for(i=0; i<TAMANHO_BUFFER; i++) buffer_tensao_sensor_turbidez[i] = le_tensao_sensor_turbidez_sem_filtro(); while (!Serial); /* Tenta, até obter sucesso, comunicação com o chip LoRa */ while(init_comunicacao_lora() == false); } /* Programa principal */ void loop() { float turbidez_da_agua = 0.0; long inicio_medicoes = 0; /* Faz a leitura da turbidez da água (em NTU) */ inicio_medicoes = millis(); while ((millis() - inicio_medicoes) < 1000) { turbidez_da_agua = le_turbidez_da_agua(); } /* Envia a turbidez da água medida */ LoRa.beginPacket(); LoRa.write((unsigned char *)&turbidez_da_agua, sizeof(float)); LoRa.endPacket(); /* aguarda um segundo para nova leitura e envio */ delay(1000); }
Código-fonte - módulo receptor
O código-fonte do módulo receptor está abaixo. Preste bastante atenção nos comentários para maior entendimento do programa.
Será exibido no display OLED o valor de turbidez da água medido no módulo medidor.
#include <LoRa.h> #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> /* Definicoes para comunicação com radio LoRa */ #define SCK_LORA 5 #define MISO_LORA 19 #define MOSI_LORA 27 #define RESET_PIN_LORA 14 #define SS_PIN_LORA 18 #define HIGH_GAIN_LORA 20 /* dBm */ #define BAND 915E6 /* 915MHz de frequencia */ /* Definicoes do OLED */ #define OLED_SDA_PIN 4 #define OLED_SCL_PIN 15 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_ADDR 0x3C #define OLED_RESET 16 /* Offset de linhas no display OLED */ #define OLED_LINE1 0 #define OLED_LINE2 10 #define OLED_LINE3 20 #define OLED_LINE4 30 #define OLED_LINE5 40 #define OLED_LINE6 50 /* Definicoes gerais */ #define DEBUG_SERIAL_BAUDRATE 115200 /* Variaveis e objetos globais */ Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); /* Local prototypes */ void display_init(void); bool init_comunicacao_lora(void); /* Funcao: inicializa comunicacao com o display OLED * Parametros: nenhnum * Retorno: nenhnum */ void display_init(void) { if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { Serial.println("[Modulo receptor] Falha ao inicializar comunicacao com OLED"); } else { Serial.println("[Modulo receptor] Comunicacao com OLED inicializada com sucesso"); /* Limpa display e configura tamanho de fonte */ display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); } } /* Funcao: inicia comunicação com chip LoRa * Parametros: nenhum * Retorno: true: comunicacao ok * false: falha na comunicacao */ bool init_comunicacao_lora(void) { bool status_init = false; Serial.println("[Modulo receptor] Tentando iniciar comunicacao com o radio LoRa..."); SPI.begin(SCK_LORA, MISO_LORA, MOSI_LORA, SS_PIN_LORA); LoRa.setPins(SS_PIN_LORA, RESET_PIN_LORA, LORA_DEFAULT_DIO0_PIN); if (!LoRa.begin(BAND)) { Serial.println("[Modulo receptor] Comunicacao com o radio LoRa falhou. Nova tentativa em 1 segundo..."); delay(1000); status_init = false; } else { /* Configura o ganho do receptor LoRa para 20dBm, o maior ganho possível (visando maior alcance possível) */ LoRa.setTxPower(HIGH_GAIN_LORA); Serial.println("[Modulo receptor] Comunicacao com o radio LoRa ok"); status_init = true; } return status_init; } /* Funcao de setup */ void setup() { /* Configuracao da I²C para o display OLED */ Wire.begin(OLED_SDA_PIN, OLED_SCL_PIN); /* Display init */ display_init(); /* Print message telling to wait */ display.clearDisplay(); display.setCursor(0, OLED_LINE1); display.print("Aguarde..."); display.display(); Serial.begin(DEBUG_SERIAL_BAUDRATE); while (!Serial); /* Tenta, até obter sucesso, comunicacao com o chip LoRa */ while(init_comunicacao_lora() == false); } /* Programa principal */ void loop() { char byte_recebido; int packet_size = 0; float turbidez_recebida = 0; char str_turbidez_agua[30] = {0}; char * ptTurbidezRecebida = NULL; /* Verifica se chegou alguma informação do tamanho esperado */ packet_size = LoRa.parsePacket(); if (packet_size == sizeof(float)) { Serial.print("[Modulo receptor] Há dados a serem lidos"); /* Recebe turbidez enviada */ ptTurbidezRecebida = (char *)&turbidez_recebida; while (LoRa.available()) { byte_recebido = (char)LoRa.read(); *ptTurbidezRecebida = byte_recebido; ptTurbidezRecebida++; } /* Cria uma string do valor da turbidez da água lida (com 2 casas decimais) */ sprintf(str_turbidez_agua, "%.2fNTU", turbidez_recebida); /* Exibe a turbidez da agua recebida via LoRa no display OLED */ display.clearDisplay(); display.setCursor(0, OLED_LINE1); display.println("Turbidez da agua:"); display.setCursor(0, OLED_LINE2); display.print(str_turbidez_agua); display.display(); } }
Projeto em ação!
Veja o projeto em ação no vídeo abaixo:
https://www.youtube.com/watch?v=0BLh68r6kAA&feature=youtu.be
Conclusão
Neste artigo vimos como expandir o projeto da Medição de turbidez com módulo WiFi LoRa 32(V2) , de forma a permitir que seja monitorada a turbidez da água à distância, enviando a informação de um módulo WiFi LoRa 32(V2) para outro via LoRa (topologia ponto-a-ponto).
Com este projeto, o leque de aplicabilidade da medição de turbidez de água se multiplica, uma vez que tanto em cenário urbano quanto rural o acesso à água cuja turbidez deve ser monitorada muitas vezes é difícil.
Além disso, este projeto abre possibilidades de inserção da medição de turbidez de água no contexto da Internet das Coisas (IoT), o que pode ser usado em projetos de cidades inteligentes (Smart Cities). Dada a importância da qualidade da água para todo e qualquer ser vivo, este projeto se torna uma interessante ferramenta para medição para a qualidade de vida de cidades inteligentes (em um futuro não tão distante, espero).