banner

Ir para o Forum

ESP32 com Antena Externa Longa Distância


Um teste de distância com um ESP32 com Antena Externa. Vamos utilizar hoje dois módulos: um da Espressif e um da TTGO. Vamos, então, verificar o RSSI entre esses dois ESP32 com antenas, gerar um gráfico a partir do histórico e gravar um log dos valores em um arquivo .csv.


Temos, então, o ESP32 Wrover como AP e o ESP32 da TTGO como Station. Utilizei uma antena que tirei de um roteador TP-Link e outra, um pouco maior, conhecida como antena de 9dbm. Não percebemos diferença nenhuma entre as duas.
Enfim, os dois microcontroladores se conectam via socket e, a cada envio de pacote de dados, imprimimos em um display um gráfico com as barras que indicam a proporção de dbm.


Montagem do AP com o Wrover




Montagem do STATION com o TTGO




RESULTADO

Distância máxima com 2x antenas externas: 315 metros
Distância máxima com antena externa e outra interna: 157 metros






Arquivo LOG.CSV

Gravei os dados em um cartão do SD, com dados em milis, dbm e a string do pacote.





Biblioteca Adafruit GFX

Na IDE do Arduino vá em Sketch->Incluir Biblioteca->Gerenciar Bibliotecas...
Instale Adafruit GFX Library




Biblioteca Adafruit ST7735

Na IDE do Arduino vá em Sketch->Incluir Biblioteca->Gerenciar Bibliotecas...
Instale Adafruit ST7735




Configurando as placas

Fique atento às diferenças:





AP.ino

Incluímos as bibliotecas necessárias e definimos alguns parâmetros.

#include <WiFi.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <vector>
#include <SD.h>

//Rede que o ESP criará. No Station deve ser igual
#define SSID "RSSI_Test"
#define PASSWORD "87654321"

//Tempo de timeout para considerar a conexão pedida
#define TIMEOUT 2000

//Largura e altura do display
#define DISPLAY_WIDTH 160
#define DISPLAY_HEIGHT 128

//Configurações de cor, margem e tamanho do gráfico
#define PLOT_COLOR ST77XX_GREEN
#define PLOT_MARGIN 20
#define PLOT_SIZE (DISPLAY_HEIGHT - 2*PLOT_MARGIN)

//Arquivo de log no SD
#define FILE_PATH "/log.csv"


Definimos os pinos, entre outras variáveis

//Pinos do display
#define DISPLAY_DC 12 //A0
#define DISPLAY_CS 13 //CS
#define DISPLAY_MOSI 14 //SDA
#define DISPLAY_CLK 27 //SCK
#define DISPLAY_RST 0

//Pino do SDCard. Os pinos mosi, miso e sck são os nativos (23, 19 e 18 respectivamente)
#define SDCARD_CS 15

//Pixel onde o gráfico começa horizontalmente
int currentX = PLOT_MARGIN;

//Objeto responsável pelo display
Adafruit_ST7735 display = Adafruit_ST7735(DISPLAY_CS, DISPLAY_DC, DISPLAY_MOSI, DISPLAY_CLK, DISPLAY_RST);

//Criamos um server (qualquer porta válida serve contanto que o cliente utilize a mesma porta)
WiFiServer server(80);

//Variável para armazenar o cliente (no caso o ESP32 em modo station) conectado
WiFiClient client;

//String que recebemos do cliente
String received;

//RSSI enviado pelo cliente para este ESP32
long rssi = 0;

//Faz o controle do temporizador (interrupção por tempo)
hw_timer_t *timer = NULL;

//Utilizado para guardar os ultimos
std::vector<int> rssiHistory; 


Setup

void setup()
{
    Serial.begin(115200);
    setupDisplay();
    //Inicializa o SD
    if (!SD.begin(SDCARD_CS))
    {
        display.println("Erro ao inicializar lib SD!"); 
    }

    //Cria a rede WiFi, inicializa o server e espera o cliente conectar
    setupWiFi();
    server.begin();
    waitForClient();

    //Espera 3 segundos, limpa a tela e inicializa o Watchdog
    delay(3000);
    display.fillScreen(ST77XX_BLACK);
    display.setCursor(0, 0);
    setupWatchdog();
}


Setup WiFi

//Cria um Access Point e configura o IP
void setupWiFi()
{
    display.println("Creating softAP " + String(SSID));
    WiFi.disconnect();
    WiFi.mode(WIFI_AP);
    WiFi.softAPConfig(IPAddress(192, 168, 0, 1), IPAddress(192, 168, 0, 1), IPAddress(255, 255, 255, 0));
    WiFi.softAP(SSID, PASSWORD);
    display.println("softAP " + String(SSID) + " created!");
}


Setup Display 

//Incializa o display, muda a orientação e limpa a tela
void setupDisplay()
{
  //Inicializa o display
  display.initR(INITR_BLACKTAB);
  //Rotaciona o conteúdo mostrado
  display.setRotation(3);
  //Pinta a tela de preto
  display.fillScreen(ST77XX_BLACK);
}


waitForClient

void waitForClient()
{
    display.println("Waiting for client");

    //Aguarda o cliente conectar
    while(!(client = server.available()))
    {
        display.print(".");
        delay(500);
    }

    display.println("Client connected");
    //Tempo máximo que o cliente deve demorar para responder
    //antes de dizermos que a conexão foi perdida
    client.setTimeout(TIMEOUT);
}


IRAM_ATTR resetModule e setupWatchdog

//função que o temporizador irá chamar, para reiniciar o ESP32
void IRAM_ATTR resetModule(){
    ets_printf("(watchdog) reiniciar\n");
    esp_restart_noos(); //reinicia o chip
}

void setupWatchdog()
{
    timer = timerBegin(0, 80, true); //timerID 0, div 80
    //timer, callback, interrupção de borda
    timerAttachInterrupt(timer, &resetModule, true);
    //timer, tempo (us), repetição
    timerAlarmWrite(timer, 10000000, true);
    timerAlarmEnable(timer); //habilita a interrupção 
}


Loop

void loop() 
{
    timerWrite(timer, 0); //reseta o temporizador (alimenta o watchdog) 
    checkConnection(); //checa se possui conexão com o cliente
    readFromClient(); //lê os dados do cliente
    sendToClient(); //envia confirmação para o cliente
    plot(); //mostra o gráfico de histórico de rssi
    log(); //salva um log no cartão SD
}


checkConnection

void checkConnection()
{
    //Se o cliente não estiver conectado
    if(!client.connected())
    {
        //Limpa a tela e espera pelo cliente
        display.fillScreen(ST77XX_BLACK);
        display.println("Client disconnected");
        waitForClient();
    }
}


readFromClient

void readFromClient()
{
    //Espera até o cliente enviar algo ou desconectar
    while(client.connected() && !client.available())
    {
        delay(100);
    }

    //Se chegou aqui e ainda estiver conectado é porque possui algo para receber do cliente
    if(client.connected())
    {
        received = client.readStringUntil('\n'); //Lê o texto que o cliente enviou
        received.remove(received.length()-1); //Remove o \n do final
        rssi = client.parseInt(); //Lê o rssi que o cliente enviou
        clearText(); //Limpa o texto
        display.setCursor(0, 0); //Move o cursor do texto para o começo do display
        display.println("RSSI: " + String(rssi)); //Mostra o RSSI no display
        display.println("Received: " + received); //Mostra a mensagem recebida do cliente

        //Se a quantidade de barras do gráfico passou do limite apagamos o registro mais antigo
        if(rssiHistory.size() == (DISPLAY_WIDTH - 2*PLOT_MARGIN)/2)
        {
            rssiHistory.erase(rssiHistory.begin());
        }

        //Adiciona no final do histórico (mais recente)
        rssiHistory.push_back(rssi);
    }
}


sendToClient

void sendToClient()
{
    //Se o cliente estiver conectado enviamos de volta a mensagem com um OK
    if(client.connected())
    {
        String sending = received + " OK";
        client.println(sending);
    }
}


plot

void plot()
{
    //Coloca no ponto inicial e limpamos o gráfico
    currentX = PLOT_MARGIN;
    display.fillRect(PLOT_MARGIN, 2*PLOT_MARGIN, DISPLAY_WIDTH - 2*PLOT_MARGIN, DISPLAY_HEIGHT - 2*PLOT_MARGIN, ST77XX_BLACK);

    //Para cada valor do histórico fazemos o cálculo do tamanho da barra do gráfico, desenhamos e avançamos para o próximo
    for (int i = 0; i < rssiHistory.size(); i++) 
    {
        int value = rssiHistory[i] > -120 ? map(rssiHistory[i], -120, 0, 0, PLOT_SIZE) : 0;
        display.drawFastVLine(currentX, DISPLAY_HEIGHT - value, value, PLOT_COLOR);
        currentX += 2;
    }
}


clearText e log

void clearText()
{
    //Limpa a área com o texto da mensagem vinda do cliente
    display.fillRect(0, 0, DISPLAY_WIDTH, 2*PLOT_MARGIN, ST77XX_BLACK);
}

void log()
{   
    //Abrimos o arquivo para escrevermos no final dele
    File file = SD.open(FILE_PATH, FILE_APPEND);

    //Se não conseguimos abrir o arquivo mostramos uma mensagem de erro
    if(!file)
    {
        Serial.println("Failed to open file");
        return;
    }

    //Gravamos uma linha com o tempo desde o boot, o rssi atual e a mensagem recebida
    String data = String(millis()) + ";" + String(rssi) + ";" + received;
    file.println(data);
    file.close();
}


Station.ino

Incluímos as bibliotecas necessárias e definimos alguns parâmetros.

#include <WiFi.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <vector>
#include <SD.h>

//Nome da rede que nos conectaremos. Criado pelo AP
#define SSID "RSSI_Test"
#define PASSWORD "87654321"

#define HOST "192.168.0.1" //IP que foi configurado no setup do AP
#define PORT 80 //Porta do sever. Qualquer porta válida contanto que seja igual nos dois arquivos

//Tempo de timeout para considerar a conexão pedida
#define TIMEOUT 2000

//Largura e altura do display
#define DISPLAY_WIDTH 160
#define DISPLAY_HEIGHT 128

//Configurações de cor, margem e tamanho do gráfico
#define PLOT_COLOR ST77XX_GREEN
#define PLOT_MARGIN 20
#define PLOT_SIZE (DISPLAY_HEIGHT - 2*PLOT_MARGIN)

//Arquivo de log no SD
#define FILE_PATH "/log.csv"


Definimos as configurações que envolvem o display e o SD Card.

long count = 0; //Contador de mensagens enviadas
long rssi = 0; //RSSI calculado
String received; //Mensagem de confirmação que o AP nos envia

//Pixel onde o gráfico começa horizontalmente
int currentX = PLOT_MARGIN;

//Utilizado para conexão com o server
WiFiClient socket;

#define DISPLAY_DC 12 //A0
#define DISPLAY_CS 13 //CS
#define DISPLAY_MOSI 14 //SDA
#define DISPLAY_CLK 27 //SCK
#define DISPLAY_RST 0

//Pino do SDCard. Os pinos mosi, miso e sck são os nativos (23, 19 e 18 respectivamente)
#define SDCARD_CS 15

//Objeto responsável pelo display
Adafruit_ST7735 display = Adafruit_ST7735(DISPLAY_CS, DISPLAY_DC, DISPLAY_MOSI, DISPLAY_CLK, DISPLAY_RST);

hw_timer_t *timer = NULL; //faz o controle do temporizador (interrupção por tempo)

//Utilizado para guardar os ultimos
std::vector rssiHistory; 


Setup

void setup()
{
    setupDisplay();

    //Inicializa o SD
    if (!SD.begin(SDCARD_CS))
    {
        display.println("Erro ao inicializar lib SD!");
    }

    //Conecta no access point criado pelo outro ESP32 e conecta ao server
    setupWiFi();
    connectToServer();

    //Espera 3 segundos, limpa a tela e inicializa o Watchdog
    delay(3000);
    display.fillScreen(ST77XX_BLACK);
    display.setCursor(0, 0);
    setupWatchdog();
}


setupDisplay

//Incializa o display, muda a orientação e limpa a tela
void setupDisplay()
{
  //Inicializa o display
  display.initR(INITR_BLACKTAB);
  //Rotaciona o conteúdo mostrado
  display.setRotation(1);
  //Pinta a tela de branco
  display.fillScreen(ST77XX_BLACK);
  display.setTextColor(ST77XX_WHITE);
}


setupWiFi

//Conecta ao AP 
void setupWiFi()
{
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);

  WiFi.begin(SSID, PASSWORD);
  display.println("Connecting to " + String(SSID));

  //Enquanto não estiver conectado à rede WiFi
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      display.print(".");
  }

  display.println("");
  display.print("Connected to ");
  display.println(SSID);
}


connectToServer

void connectToServer()
{
    display.println("Trying socket connection");

    //Espera a conexão com o server
    while(!socket.connect(HOST, PORT)) 
    {
        display.print(".");
        delay(500);
    }

    display.println();
    display.println("Connected!");
    //Tempo máximo que o cliente deve demorar para responder
    //antes de dizermos que a conexão foi perdida
    socket.setTimeout(TIMEOUT);
}


IRAM_ATTR resetModule e setupWatchdog

//função que o temporizador irá chamar, para reiniciar o ESP32
void IRAM_ATTR resetModule(){
    ets_printf("(watchdog) reiniciar\n");
    esp_restart_noos(); //reinicia o chip
}

void setupWatchdog()
{
    timer = timerBegin(0, 80, true); //timerID 0, div 80
    //timer, callback, interrupção de borda
    timerAttachInterrupt(timer, &resetModule, true);
    //timer, tempo (us), repetição
    timerAlarmWrite(timer, 10000000, true);
    timerAlarmEnable(timer); //habilita a interrupção
}


loop

void loop() 
{
    timerWrite(timer, 0); //reseta o temporizador (alimenta o watchdog) 
    checkConnection(); //checa se possui conexão com o server
    checkRSSI(); //verifica o rssi
    plot(); //mostra o gráfico de histórico de rssi
    sendToServer(); //envia uma mensagem com um contador para o server
    readFromServer(); //espera a confirmação do server
    log(); //salva um log no cartão SD
    delay(1000); //espera um segundo
}


checkConnection

void checkConnection()
{
    //Verifica a conexão com o AP
    if(WiFi.status() != WL_CONNECTED)
    {
        display.fillScreen(ST77XX_BLACK);
        display.setCursor(0, 0);
        display.println("WiFi disconnected");
        setupWiFi();
        delay(1000);
    }

    //verifica a conexão do socket
    if(!socket.connected())
    {
        display.fillScreen(ST77XX_BLACK);
        display.setCursor(0, 0);
        display.println("Socket disconnected");
        connectToServer();
        delay(3000);
        display.fillScreen(ST77XX_BLACK);
    }
}


checkRSSI

void checkRSSI()
{
    //Verifica o RSSI
    rssi = WiFi.RSSI(); 

    //Limpa o texto e mostra o RSSI no display
    clearText();
    display.setCursor(0, 0);
    display.print("RSSI: " + String(rssi));

    //Se a quantidade de barras do gráfico passou do limite apagamos o registro mais antigo
    if(rssiHistory.size() == (DISPLAY_WIDTH - 2*PLOT_MARGIN)/2)
    {
        rssiHistory.erase(rssiHistory.begin());
    }

    //Adiciona no final do histórico (mais recente)
    rssiHistory.push_back(rssi);
}


plot

void plot()
{
    //Coloca no ponto inicial e limpamos o gráfico
    currentX = PLOT_MARGIN;
    display.fillRect(PLOT_MARGIN, 2*PLOT_MARGIN, DISPLAY_WIDTH - 2*PLOT_MARGIN, DISPLAY_HEIGHT - 2*PLOT_MARGIN, ST77XX_BLACK);

    //Para cada valor do histórico fazemos o cálculo do tamanho da barra do gráfico, desenhamos e avançamos para o próximo
    for (int i = 0; i < rssiHistory.size(); i++) 
    {
        int value = rssiHistory[i] > -120 ? map(rssiHistory[i], -120, 0, 0, PLOT_SIZE) : 0;
        display.drawFastVLine(currentX, DISPLAY_HEIGHT - value, value, PLOT_COLOR);
        currentX += 2;
    }
}


sendToServer

void sendToServer()
{
    //Se estiver conectado com o server
    if(socket.connected())
    {
        //Envia um hello com um contador, mostra no display e incrementa o contador
        String sending = "Hello " + String(count);
        display.setCursor(0, 10);
        display.println("Sending: " + sending);
        socket.println(sending);
        socket.print(String(rssi));
        count++;
    }
}


readFromServer 

void readFromServer()
{
    //Espera até o server enviar algo ou desconectar
    while(socket.connected() && !socket.available())
    {
        delay(100);
    }

    //Se tem algo para receber
    if(socket.available())
    {
        //Faz a leitura, remove o \n do final e mostra no display
        received = socket.readStringUntil('\n');
        received.remove(received.length()-1);
        display.println("Received: " + received);
    }
}


clearText e log

void clearText()
{
    //Limpa a área com o texto da mensagem vinda do cliente
    display.fillRect(0, 0, DISPLAY_WIDTH, 2*PLOT_MARGIN, ST77XX_BLACK);
}

void log()
{
    //Abrimos o arquivo para escrevermos no final dele
    File file = SD.open(FILE_PATH, FILE_APPEND);

    //Se não conseguimos abrir o arquivo mostramos uma mensagem de erro
    if(!file)
    {
        Serial.println("Failed to open file");
        return;
    }

    //Gravamos uma linha com o tempo desde o boot, o rssi atual e a mensagem recebida
    String data = String(millis()) + ";" + String(rssi) + ";" + received;
    file.println(data);
    file.close();
}



Faça o download dos arquivos:




2 comentários:

  1. excelente tutorial , obrigado vai ser de muito uso para mim.
    gostaria de outros testes com antena externa melhor .
    Parabens

    ResponderExcluir
  2. Esqueci d ebotar meu nome
    excelente tutorial , obrigado vai ser de muito uso para mim.
    gostaria de outros testes com antena externa melhor .
    Parabens

    ResponderExcluir

Tecnologia do Blogger.