ESP32 With External Long Distance Antenna
by Fernando Koyanagi in Circuits > Microcontrollers
24113 Views, 6 Favorites, 0 Comments
ESP32 With External Long Distance Antenna
Today’s topic concerns a distance test with an ESP32 with External Antenna. Let's use two modules today: from Espressif and TTGO. Let's then check the RSSI between these two ESP32 antennas, generate a graph from the history, and write a log of the values in a .csv file.
We then have the ESP32 Wrover as AP, and the ESP32 of TTGO as Station. I used an antenna that I took from a slightly larger TP-Link and another router known as a 9dbm antenna. I haven’t noticed any difference between the two.
Finally, the two microcontrollers connect via socket and, with each sending of data packets, we print on a display a graph with the bars that indicate the ratio of dbm.
Mounting the AP With Wrover
Assembly of STATION With TTGO
RESULT
Maximum distance with 2x external antennas: 315 meters
Maximum distance with external and internal antenna: 157 meters
Archive LOG.CSV
I recorded the data on an SD card, with data in millis, dbm, and the package string.
Adafruit GFX Library
In the Arduino IDE, go to Sketch-> Include Library-> Manage Libraries...
Install Adafruit GFX Library
Adafruit ST7735 Library
In the Arduino IDE, go to Sketch-> Include Library-> Manage Libraries...
Install Adafruit ST7735
Configuring the Cards
Stay tuned for differences:
AP.ino
We have included the necessary libraries and defined some parameters.
#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"
We define the pins, among other variables
//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 and 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 and 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
We have included the necessary libraries and defined some parameters.
#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"
We define the settings that involve the display and the 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 and 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 and 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(); }