Talk2 Whisper Node – LoRA RFM69 sob medida

Tenho a impressão que o momento é de RF subgiga. Diversas opções estão surgindo e o preço está cada vez menor. Nesse outro artigo fiz a introdução do AFSmartRadio, que veremos muitas aplicações no decorrer dos próximos dias. Mas agora quero falar de uma bela placa que já escrevi alguns artigos anteriormente. A Talk2 Whisper Node, com LoRA RFM69!

Atenção

Essa dica é para qualquer módulo; sempre, sempre, SEMPRE tenha a antena conectada antes de ligar o dispositivo para evitar danos ao rádio. Sempre.

LoRA RFM69

Essa belezinha utiliza um módulo RFM69 e já escrevi alguns artigos sobre ela:

  • primeiros passos – instalação da board. Só troque a url da board por https://bitbucket.org/talk2/arduino-ide-boards/raw/master/package_talk2.wisen.com_index.json caso tenha algum problema de resolução com a URL do artigo.
  • introdução – muito importante, cito diversos detalhes sobre os recursos da placa
  • Acionando relé – simples

A biblioteca estará disponível também pela IDE do Arduino, é só seguir o link primeiros passos.

Nesse artigo, vou experimentar algo que ainda não havia experimentado; o alcance da board com obstáculos. Uma ficará dentro do meu apartamento (16º andar) e a outra levarei pra “passear” na rua.

Será fácil mantê-la alimentada por baterias, pois seu consumo é infinitesimal, podendo durar anos com uma única pilha AA. E é um Atmega328PU!

Ela pode ser alimentada simultaneamente por uma fonte e por baterias, de modo que se obtém um backup seguro em caso de queda de energia, pois ela continuará a funcionar.

Sugiro fortemente que leia os artigos supracitados, isso vai amolecer-lhe as pernas.

Cenário

Vou deixar uma board ligada a um carregador de celular, bem próximo à janela (ou na própria janela). Na outra board colocarei um display OLED que exibirá informação de tempo de resposta na troca de pacotes e/ou mostrará o RSSI (estou escrevendo enquanto planejo). Daí vou para a rua com essa board com OLED para medir o alcance; dentro do elevador, na portaria do prédio, caminhando pela rua até onde for possível. Pode não passar de uma quadra ou pode ser que eu tenha que voltar de Uber, enquanto escrevo é uma incógnita.

Materiais necessários

Se quiser fazer algo parecido, está muito fácil. Você vai precisar de pouca coisa:

Pinout

Para saber os pinos que são utilizados e os pinos que se pode utilizar, é fundamental saber o pinout da board em questão:

Talk2 Whisper Node com LoRA RFM69 - pinout

Desses, o A4 e A5 serão utilizados para o I2C.

Biblioteca SSD1306

Essa é a biblioteca utilizada, que você pode seguir esse tutorial para instalar. Se já a instalou para usar com ESP32  e fez a modificação sugerida no artigo supracitado, edite novamente o arquivo ~/Arduino/libraries/Adafruit_SSD1306/Adafruit_SSD1306.cpp e na linha 206, volte a inicialização do Wire para Wire.begin().

Tem também uma biblioteca do próprio Talk2, com alguns exemplos específicos da board. Para esse tutorial, utilizei um sketch de exemplo da biblioteca RadioHead. Baixando a biblioteca do Talk2, você a encontrará no diretório ~/Arduino/libraries/Talk2/extras. Basta copiá-la para ~/Arduino/libraries e extrair o pacote. Após feito, reinicie (ou inicie) a IDE do Arduino.

Sketch de exemplo

Eu recomendo muito que se faça isso, porque o sketch de exemplo tende a ser sempre a melhor implementação e te ajuda a entender o comportamento do hardware em questão. Mas preciso manifestar minha satisfação; a biblioteca do Talk2 é fantástica! Tem uma implementação criptográfica, tem implementação de altíssimo nível com timer, acesso fácil a todos os recursos da placa sem que precisemos esmiuçar bits! Como estou escrevendo algo mais simples, não utilizei os sketches da Talk2, mas pretendo fazê-lo.

Se você viu os artigos relacionados ao NRF24L01, por mais que seja simples, não chega aos pés da simplicidade de uso da biblioteca do Talk2 Whisper Node, ou diretamente a RadioHead, sério.  Ela tem inclusive a opção de pegar o RSSI (a intensidade de sinal). Devido a esse recurso, resolvi escrever algumas linhas para explicar o que significa ter esse recurso.

RSSI e dBm

Ambas são unidades de medição de intensidade de sinal. A diferença é que o RSSI é um índice relativo, enquanto dBm é um número absoluto representando o nível de força em mW.

O RSSI é utilizado para medir a qualidade relativa de um sinal recebido de um dispositivo remoto, não tendo um valor absoluto. Pelas especificações do IEEE 802.11, a escala pode ser de 1 Byte, mas a norma permite que cada um implemente “a gosto”, então tem implementações que vão de 0 à 100 ou 0 à 60 etc. Então para utilizá-lo como referência, é necessário saber qual o padrão que está sendo utilizado no hardware em questão.

Na biblioteca RadioHead o valor do RSSI é representando por um número negativo. Quanto mais próximo de 0, maior a intensidade de sinal. Com o rádio lado a lado, o menor valor que obtive foi -30, e conforme se distancia o rádio, maior o valor negativo.

 

Vamos ao código, nele deixo alguns comentários pertinentes. Removi tudo do sketch que não achei necessário para essa implementação e adicionei ao código as funcionalidades que julguei necessárias para fazer esse teste de alcance.

Listener

O lado encarregado de exibir as informações no display eu chamei de “listener”. O código para ele, com display, mostrando RSSI, tempo de troca de mensagem e status, ficou desse jeito:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SPI.h>
#include <RH_RF69.h>

#define OLED_RESET 4

//instância do display
Adafruit_SSD1306 display(OLED_RESET);

// Instância do driver do rádio
RH_RF69 rf69;

long int interval  = 0;
long int last_time = 0;

/*Função para escrever no display. Os parâmetros são o texto e posições X e Y.*/
void drawText(const void *text,byte posX, byte posY, bool doClear){
    char *text2display = (char*) text;
    if (doClear){
        display.clearDisplay();
    }
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(posX,posY);
    display.println((char*)text);
    //display.setCursor(0,10);
    display.display();
}

void setup() 
{
  Serial.begin(115200);
  while (!Serial);
  if (!rf69.init()){
      Serial.println("init failed");
  }
  if (!rf69.setFrequency(916.0)){
      Serial.println("setFrequency failed");
  }
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 
  display.display();
  display.clearDisplay();
  
  rf69.setTxPower(13, true);
  //Criptografia entre os pontos. Deve ser igual em ambos os dispositivos.
  uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  rf69.setEncryptionKey(key);
  
#if 0
  // For compat with RFM69 Struct_send <- deixei o comentário original.
  //Basta manter esse padrão e tudo acontecerá.
  rf69.setModemConfig(RH_RF69::GFSK_Rb250Fd250);
  rf69.setPreambleLength(3);
  uint8_t syncwords[] = { 0x2d, 0x64 };
  rf69.setSyncWords(syncwords, sizeof(syncwords));
  rf69.setEncryptionKey((uint8_t*)"thisIsEncryptKey");
#endif

  last_time = millis();
}

void loop()
{
  if (rf69.available()){
    //recepção da mensagem...
    uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    if (rf69.recv(buf, &len)){
      Serial.print("got request: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(rf69.lastRssi(), DEC);
      
      //...e réplica.
      uint8_t data[] = "And hello back to you";
      rf69.send(data, sizeof(data));
      rf69.waitPacketSent();
      Serial.println("Resposta enviada.");
      drawText("Good for now :-)",0,0,true);

      interval  = millis()-last_time;
      last_time = millis();

      char timeToDisplay[6];
      String val = String(interval);
      val = val + "ms";
      val.toCharArray(timeToDisplay,6);
      Serial.println(timeToDisplay);
      drawText("Interval: ",0,20,false);
      drawText(timeToDisplay,55,20,false);
    }
    
    int rssi        = rf69.lastRssi();
    char bufChar[4] = {0};
    String val      = String(rssi);
    val.toCharArray(bufChar,4);
    
    drawText("RSSI    :",0,10,false);
    drawText(bufChar,55,10,false);
  }
  else{
      while (!rf69.available()){
          Serial.println("Sem resposta!");
          drawText("No answer :-(",0,0,true);
      }
    }
  
}

Screamer

O lado que ficará conectado em meu apartamento, pendurado na janela, chamei de “screamer”. Se não gostou dos nomes, sem problemas, apenas escolha o que preferir em seu sketch! O código ficou assim (se não me engano, original):

// rf69_client.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messageing client
// with the RH_RF69 class. RH_RF69 class does not provide for addressing or
// reliability, so you should only use RH_RF69  if you do not need the higher
// level messaging abilities.
// It is designed to work with the other example rf69_server.
// Demonstrates the use of AES encryption, setting the frequency and modem 
// configuration
// Tested on Moteino with RFM69 http://lowpowerlab.com/moteino/
// Tested on miniWireless with RFM69 www.anarduino.com/miniwireless
// Tested on Teensy 3.1 with RF69 on PJRC breakout board

#include <SPI.h>
#include <RH_RF69.h>

// Singleton instance of the radio driver
RH_RF69 rf69;
//RH_RF69 rf69(15, 16); // For RF69 on PJRC breakout board with Teensy 3.1
//RH_RF69 rf69(4, 2); // For MoteinoMEGA https://lowpowerlab.com/shop/moteinomega
//RH_RF69 rf69(8, 7); // Adafruit Feather 32u4

void setup() 
{
  Serial.begin(9600);
  while (!Serial) 
    ;
  if (!rf69.init())
    Serial.println("init failed");
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
  // No encryption
  if (!rf69.setFrequency(916.0))
    Serial.println("setFrequency failed");

  // If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
  // ishighpowermodule flag set like this:
  rf69.setTxPower(14, true);

  // The encryption key has to be the same as the one in the server
  uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  rf69.setEncryptionKey(key);
}


void loop()
{
  Serial.println("Sending to rf69_server");
  // Send a message to rf69_server
  uint8_t data[] = "Hello World!";
  rf69.send(data, sizeof(data));
  
  rf69.waitPacketSent();
  // Now wait for a reply
  uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  if (rf69.waitAvailableTimeout(500))
  { 
    // Should be a reply message for us now   
    if (rf69.recv(buf, &len))
    {
      Serial.print("got reply: ");
      Serial.println((char*)buf);
    }
    else
    {
      Serial.println("recv failed");
    }
  }
  else
  {
    Serial.println("No reply, is rf69_server running?");
  }
  delay(400);
}

Upload

Para subir o sketch, você precisará de um FTDI, e não pode ser conversor USB-serial porque é necessário ter o pino DTR. Se não tem um, pegue o seu na Eletrogate. Precisa ser esse modelo porque é possível selecionar o nível de tensão entre 3V3 e 5V e para a Talk2 Whisper Node será necessário que esteja em 3V3.

Video do teste

Agora vou dar uma sacaneada. Terminei o artigo muito tarde e não resisti em publicá-lo. Mas o video será colocado no primeiro nascer do sol após a publicação, então, se tiver interesse em ver o teste, assine nosso canal no YouTube!

Siga-nos no Do bit Ao Byte no Facebook.

Prefere twitter? @DobitAoByte.

Inscreva-se no nosso canal Do bit Ao Byte Brasil no YouTube.

Nossos grupos:

Arduino BR – https://www.facebook.com/groups/microcontroladorarduinobr/
Raspberry Pi BR – https://www.facebook.com/groups/raspberrybr/
Orange Pi BR – https://www.facebook.com/groups/OrangePiBR/
Odroid BR – https://www.facebook.com/groups/odroidBR/
Sistemas Embarcados BR – https://www.facebook.com/groups/SistemasEmbarcadosBR/
MIPS BR – https://www.facebook.com/groups/MIPSBR/
Do Bit ao Byte – https://www.facebook.com/groups/dobitaobyte/

Próximo post a caminho!

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.