ESP32 - Controla Carro pela Web

Este guia mostra como usar o ESP32 para controlar um carro robô sem fio, a partir de um navegador no seu celular ou PC, usando WiFi. O controle é feito por uma interface web gráfica que usa o WebSocket, o que permite um controle suave e dinâmico do carro.

ESP32 controla carro robô pela Web

Sobre o Carro RC 2WD e o WebSocket

Por que usar o WebSocket? Veja o motivo:

  • Sem o WebSocket, mudar a direção do carro exigiria recarregar a página toda vez. Nada ideal!
  • Com o WebSocket, estabelecemos uma conexão especial entre a página web e o ESP32. Isso permite enviar comandos ao ESP32 em segundo plano, sem precisar recarregar a página. O resultado? O carro robô se move de forma suave e em tempo real. Bem legal, não é?

Resumindo, a conexão WebSocket permite o controle suave e em tempo real do robô.

Temos tutoriais específicos sobre o carro RC 2WD e o WebSocket. Cada tutorial traz informações detalhadas e instruções passo a passo sobre a pinagem do hardware, o princípio de funcionamento, a ligação com o ESP32, o código do ESP32... Saiba mais nos links a seguir:

Como Funciona

O código do ESP32 cria um servidor web e também um servidor WebSocket. Veja como funciona:

  • Quando você digita o endereço IP do ESP32 em um navegador, ele solicita ao ESP32 a página web (interface de usuário).
  • O servidor web do ESP32 responde enviando o conteúdo da página (HTML, CSS, JavaScript).
  • Em seguida, o navegador exibe a página web.
  • O código JavaScript da página estabelece uma conexão WebSocket com o servidor WebSocket do ESP32.
  • Depois que a conexão WebSocket é estabelecida, se você pressionar/soltar os botões na página web, o código JavaScript envia os comandos ao ESP32 discretamente, em segundo plano, por essa conexão WebSocket.
  • O servidor WebSocket do ESP32, ao receber os comandos, controla o carro robô de acordo com eles.

A tabela abaixo mostra a lista de comandos que a página web envia ao ESP32 conforme as ações do usuário:

Ação do Usuário Botão Comando Ação do Carro
PRESSIONAR UP 1 MOVER PARA FRENTE
PRESSIONAR DOWN 2 MOVER PARA TRÁS
PRESSIONAR LEFT 4 VIRAR À ESQUERDA
PRESSIONAR RIGHT 8 VIRAR À DIREITA
PRESSIONAR STOP 0 PARAR
SOLTAR UP 0 PARAR
SOLTAR DOWN 0 PARAR
SOLTAR LEFT 0 PARAR
SOLTAR RIGHT 0 PARAR
SOLTAR STOP 0 PARAR

Diagrama de Ligação entre o Carro RC 2WD e o ESP32

O diagrama abaixo mostra como conectar o ESP32, o driver de motor L9110S e os dois motores DC, usando uma protoboard para compartilhar as linhas comuns de alimentação e GND:

ESP32 carro RC 2WD diagrama de ligação em uma protoboard

This image is created using Fritzing. Click to enlarge image

Se você não sabe como alimentar o ESP32 e outros componentes, veja as instruções no tutorial a seguir: Como alimentar o ESP32.

Observação: O diagrama acima mostra a ligação correta. Na prática, conectar vários fios (como as linhas compartilhadas de VCC e GND) no mesmo furo do conector de pinos do ESP32 não é fácil. Uma solução prática é usar uma placa breakout com bornes de parafuso para ESP32 — vários fios podem ser presos no mesmo borne de parafuso, ou um fio no parafuso e outro no pino ao lado.

ESP32 carro RC 2WD diagrama de ligação usando bornes de parafuso

This image is created using Fritzing. Click to enlarge image

O módulo L9110S (que serve como driver de motor) alimenta os motores diretamente pelos pinos VCC e GND e não tem regulador de 5V integrado. Isso permite alimentar tudo com uma única fonte – quatro pilhas de 1,5V, totalizando 6V. Veja como:

  • Conecte a bateria de 6V aos pinos VCC e GND do módulo L9110S para alimentar os motores.
  • Conecte a mesma bateria de 6V aos pinos Vin e GND do ESP32 para alimentar a placa.
  • Verifique se o módulo L9110S e o ESP32 compartilham um GND comum.

Ao contrário do L298N, o L9110S não tem jumpers de habilitação ENA/ENB nem borne de parafuso de 12V, então a ligação é mais simples.

Como o carro RC 2WD tem uma chave liga/desliga, você pode, se quiser, conectar a bateria por meio da chave para poder ligar/desligar a energia do carro. Se quiser simplificar, é só ignorar a chave.

Código ESP32

O conteúdo da página web (HTML, CSS, JavaScript) fica armazenado separadamente em um arquivo index.h. Assim, teremos dois arquivos de código no Arduino IDE:

  • Um arquivo .ino, que é o código do ESP32, o qual cria um servidor web e um servidor WebSocket e controla o carro
  • Um arquivo .h, que contém o conteúdo da página web.

Passos Rápidos

  • Se esta é a primeira vez que você usa o ESP32, veja como configurar o ambiente do ESP32 no Arduino IDE.
  • Faça a ligação como na imagem acima.
  • Conecte a placa ESP32 ao seu PC com um cabo micro USB
  • Abra o Arduino IDE no seu PC.
  • Selecione a placa ESP32 correta (por exemplo, ESP32 Dev Module) e a porta COM.
  • Abra o Library Manager clicando no ícone Library Manager na barra de navegação à esquerda do Arduino IDE.
  • Pesquise “DIYables ESP32 WebServer” e encontre a biblioteca Web Server criada pela DIYables.
  • Clique no botão Install para instalar a biblioteca Web Server.
Biblioteca ESP32 Web Server
  • No Arduino IDE, crie um novo sketch. Dê um nome a ele, por exemplo, newbiely.com.ino
  • Copie o código abaixo e abra no Arduino IDE
/* * Este código de ESP32 foi desenvolvido por pt.newbiely.com * Este código de ESP32 é disponibilizado ao público sem nenhuma restrição. * Para tutoriais completos e diagramas de ligação, visite: * https://pt.newbiely.com/tutorials/esp32/esp32-controls-car-via-web */ #include <DIYables_ESP32_WebServer.h> #include "index.h" #define CMD_STOP 0 #define CMD_FORWARD 1 #define CMD_BACKWARD 2 #define CMD_LEFT 4 #define CMD_RIGHT 8 #define MOTOR_A_IA_PIN 14 // The ESP32 pin GPIO14 connected to the A-IA pin of the L9110S (Motor A) #define MOTOR_A_IB_PIN 27 // The ESP32 pin GPIO27 connected to the A-IB pin of the L9110S (Motor A) #define MOTOR_B_IA_PIN 33 // The ESP32 pin GPIO33 connected to the B-IA pin of the L9110S (Motor B) #define MOTOR_B_IB_PIN 32 // The ESP32 pin GPIO32 connected to the B-IB pin of the L9110S (Motor B) // WiFi credentials const char WIFI_SSID[] = "YOUR_WIFI_SSID"; const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD"; // Create web server instance DIYables_ESP32_WebServer server; DIYables_ESP32_WebSocket* webSocket; // Web Page handlers void handleHome(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { server.sendResponse(client, HTML_CONTENT); // HTML_CONTENT is from index.h } // WebSocket event handlers void onWebSocketOpen(net::WebSocket& ws) { Serial.println("New WebSocket connection"); // Send welcome message const char welcome[] = "Connected to ESP32 WebSocket Server!"; } void onWebSocketMessage(net::WebSocket& ws, const net::WebSocket::DataType dataType, const char* message, uint16_t length) { String angle = String(message); int command = angle.toInt(); Serial.print("command: "); Serial.println(command); switch (command) { case CMD_STOP: Serial.println("Stop"); CAR_stop(); break; case CMD_FORWARD: Serial.println("Move Forward"); CAR_moveForward(); break; case CMD_BACKWARD: Serial.println("Move Backward"); CAR_moveBackward(); break; case CMD_LEFT: Serial.println("Turn Left"); CAR_turnLeft(); break; case CMD_RIGHT: Serial.println("Turn Right"); CAR_turnRight(); break; default: Serial.println("Unknown command"); } } void onWebSocketClose(net::WebSocket& ws, const net::WebSocket::CloseCode code, const char* reason, uint16_t length) { Serial.println("WebSocket client disconnected"); } void setup() { Serial.begin(9600); delay(1000); pinMode(MOTOR_A_IA_PIN, OUTPUT); pinMode(MOTOR_A_IB_PIN, OUTPUT); pinMode(MOTOR_B_IA_PIN, OUTPUT); pinMode(MOTOR_B_IB_PIN, OUTPUT); Serial.println("ESP32 Web Server and WebSocket Server"); // Configure web server routes server.addRoute("/", handleHome); // Start web server with WiFi connection server.begin(WIFI_SSID, WIFI_PASSWORD); // Enable WebSocket functionality webSocket = server.enableWebSocket(81); if (webSocket != nullptr) { // Set up WebSocket event handlers webSocket->onOpen(onWebSocketOpen); webSocket->onMessage(onWebSocketMessage); webSocket->onClose(onWebSocketClose); } else { Serial.println("Failed to start WebSocket server"); } } void loop() { // Then handle HTTP requests server.handleClient(); // Handle WebSocket server.handleWebSocket(); } void CAR_moveForward() { digitalWrite(MOTOR_A_IA_PIN, HIGH); digitalWrite(MOTOR_A_IB_PIN, LOW); digitalWrite(MOTOR_B_IA_PIN, HIGH); digitalWrite(MOTOR_B_IB_PIN, LOW); } void CAR_moveBackward() { digitalWrite(MOTOR_A_IA_PIN, LOW); digitalWrite(MOTOR_A_IB_PIN, HIGH); digitalWrite(MOTOR_B_IA_PIN, LOW); digitalWrite(MOTOR_B_IB_PIN, HIGH); } void CAR_turnLeft() { digitalWrite(MOTOR_A_IA_PIN, HIGH); digitalWrite(MOTOR_A_IB_PIN, LOW); digitalWrite(MOTOR_B_IA_PIN, LOW); digitalWrite(MOTOR_B_IB_PIN, LOW); } void CAR_turnRight() { digitalWrite(MOTOR_A_IA_PIN, LOW); digitalWrite(MOTOR_A_IB_PIN, LOW); digitalWrite(MOTOR_B_IA_PIN, HIGH); digitalWrite(MOTOR_B_IB_PIN, LOW); } void CAR_stop() { digitalWrite(MOTOR_A_IA_PIN, LOW); digitalWrite(MOTOR_A_IB_PIN, LOW); digitalWrite(MOTOR_B_IA_PIN, LOW); digitalWrite(MOTOR_B_IB_PIN, LOW); }
  • Modifique as informações de WiFi (SSID e senha) no código para corresponder às credenciais da sua rede.
  • Crie o arquivo index.h no Arduino IDE assim:
    • Clique no botão logo abaixo do ícone do Serial Monitor e escolha New Tab, ou use as teclas Ctrl+Shift+N.
    Arduino IDE 2 adiciona arquivo
    • Dê ao arquivo o nome index.h e clique no botão OK
    Arduino IDE 2 adiciona arquivo index.h
    • Copie o código abaixo e cole no index.h.
    /* * Este código de ESP32 foi desenvolvido por pt.newbiely.com * Este código de ESP32 é disponibilizado ao público sem nenhuma restrição. * Para tutoriais completos e diagramas de ligação, visite: * https://pt.newbiely.com/tutorials/esp32/esp32-controls-car-via-web */ const char *HTML_CONTENT = R"=====( <!DOCTYPE html> <html> <head> <title>ESP32 Control Car via Web</title> <meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=1, user-scalable=no"> <style type="text/css"> body { text-align: center; font-size: 24px;} button { text-align: center; font-size: 24px;} #container { margin-right: auto; margin-left: auto; width: 400px; height: 400px; position: relative; margin-bottom: 10px; } div[class^='button'] { position: absolute; } .button_up, .button_down { width:214px; height:104px;} .button_left, .button_right { width:104px; height:214px;} .button_stop { width:178px; height:178px;} .button_up { background: url('https://esp32io.com/images/tutorial/up_inactive.png') no-repeat; background-size: contain; left: 200px; top: 0px; transform: translateX(-50%); } .button_down { background: url('https://esp32io.com/images/tutorial/down_inactive.png') no-repeat; background-size: contain; left:200px; bottom: 0px; transform: translateX(-50%); } .button_right { background: url('https://esp32io.com/images/tutorial/right_inactive.png') no-repeat; background-size: contain; right: 0px; top: 200px; transform: translateY(-50%); } .button_left { background: url('https://esp32io.com/images/tutorial/left_inactive.png') no-repeat; background-size: contain; left:0px; top: 200px; transform: translateY(-50%); } .button_stop { background: url('https://esp32io.com/images/tutorial/stop_inactive.png') no-repeat; background-size: contain; left:200px; top: 200px; transform: translate(-50%, -50%); } </style> <script> var CMD_STOP = 0; var CMD_FORWARD = 1; var CMD_BACKWARD = 2; var CMD_LEFT = 4; var CMD_RIGHT = 8; var img_name_lookup = { [CMD_STOP]: "stop", [CMD_FORWARD]: "up", [CMD_BACKWARD]: "down", [CMD_LEFT]: "left", [CMD_RIGHT]: "right" } var ws = null; function init() { var container = document.querySelector("#container"); container.addEventListener("touchstart", mouse_down); container.addEventListener("touchend", mouse_up); container.addEventListener("touchcancel", mouse_up); container.addEventListener("mousedown", mouse_down); container.addEventListener("mouseup", mouse_up); container.addEventListener("mouseout", mouse_up); } function ws_onmessage(e_msg) { e_msg = e_msg || window.event; // MessageEvent //alert("msg : " + e_msg.data); } function ws_onopen() { document.getElementById("ws_state").innerHTML = "OPEN"; document.getElementById("wc_conn").innerHTML = "Disconnect"; } function ws_onclose() { document.getElementById("ws_state").innerHTML = "CLOSED"; document.getElementById("wc_conn").innerHTML = "Connect"; console.log("socket was closed"); ws.onopen = null; ws.onclose = null; ws.onmessage = null; ws = null; } function wc_onclick() { if(ws == null) { ws = new WebSocket("ws://" + window.location.host + ":81"); document.getElementById("ws_state").innerHTML = "CONNECTING"; ws.onopen = ws_onopen; ws.onclose = ws_onclose; ws.onmessage = ws_onmessage; } else ws.close(); } function mouse_down(event) { if (event.target !== event.currentTarget) { var id = event.target.id; send_command(id); event.target.style.backgroundImage = "url('https://esp32io.com/images/tutorial/" + img_name_lookup[id] + "_active.png')"; } event.stopPropagation(); event.preventDefault(); } function mouse_up(event) { if (event.target !== event.currentTarget) { var id = event.target.id; send_command(CMD_STOP); event.target.style.backgroundImage = "url('https://esp32io.com/images/tutorial/" + img_name_lookup[id] + "_inactive.png')"; } event.stopPropagation(); event.preventDefault(); } function send_command(cmd) { if(ws != null) if(ws.readyState == 1) ws.send(cmd + "\r\n"); } window.onload = init; </script> </head> <body> <h2>ESP32 - RC Car via Web</h2> <div id="container"> <div id="0" class="button_stop"></div> <div id="1" class="button_up"></div> <div id="2" class="button_down"></div> <div id="8" class="button_right"></div> <div id="4" class="button_left"></div> </div> <p> WebSocket : <span id="ws_state" style="color:blue">closed</span><br> </p> <button id="wc_conn" type="button" onclick="wc_onclick();">Connect</button> <br> <br> <div class="sponsor">Sponsored by <a href="https://amazon.com/diyables">DIYables</a></div> </body> </html> )=====";
    • Agora você tem o código em dois arquivos: newbiely.com.ino e index.h
    • Clique no botão Upload do Arduino IDE para fazer upload do código para o ESP32
    • Abra o Serial Monitor
    • Confira o resultado no Serial Monitor.
    ∞
    Newbiely | Arduino IDE 2.3.8
    ──
    ☐
    ✕
    File
    Edit
    Sketch
    Tools
    Help
    ESP32 Dev Module
    Newbiely.ino
    ···
    8 Serial.println("Hello World!");
    Output
    Serial Monitor
    Message (Enter to send message to 'ESP32 Dev Module' on 'COM15')
    New Line
    9600 baud
    Connecting to WiFi... Connected to WiFi ESP32 Web Server's IP address IP address: 192.168.0.2
    Ln 11, Col 1
    ESP32 Dev Module on COM15
    2
    • Anote o endereço IP exibido e digite esse endereço na barra de endereços de um navegador no seu celular ou PC.
    • Você verá a página web como abaixo:
    ESP32 controla carro pelo navegador web
    • O código JavaScript da página web cria automaticamente a conexão WebSocket com o ESP32.
    • Agora você pode controlar o carro para virar à esquerda/direita e andar para frente/para trás pela interface web.

    Para economizar a memória do ESP32, as imagens dos botões de controle NÃO ficam armazenadas no ESP32. Elas ficam armazenadas na internet, então seu celular ou PC precisa ter conexão com a internet para carregar as imagens da página web de controle.

    ※ Nota:

    • Se você modificar o conteúdo HTML no index.h e não mexer em nada no arquivo newbiely.com.ino, ao compilar e fazer upload do código para o ESP32, o Arduino IDE não vai atualizar o conteúdo HTML.
    • Para fazer o Arduino IDE atualizar o conteúdo HTML nesse caso, faça uma alteração no arquivo newbiely.com.ino (por exemplo, adicione uma linha vazia ou um comentário....)

    Explicação do Código Linha por Linha

    O código do ESP32 acima contém uma explicação linha por linha. Leia os comentários no código!

※ NOSSAS MENSAGENS

  • Fique à vontade para compartilhar o link deste tutorial. Porém, por favor, não use nosso conteúdo em outros sites. Investimos muito esforço e tempo para criar este conteúdo, por favor respeite nosso trabalho!