Kit Robô 2WD ESP32-CAM Vision com Câmera e WiFi RB2686 – Curso Completo

Kit Robô 2WD Robótica Aprendizagem Wifi ESP32 Camera Tutorial App RB2686 — Curso Completo com Projetos Práticos

Introdução

Este curso profissional apresenta uma formação técnica completa, progressiva e detalhada em robótica móvel com visão computacional embarcada, sistemas embarcados com WiFi e transmissão de vídeo em tempo real utilizando a plataforma ESP32-CAM com sensor de imagem OV2640 e o Kit Robô 2WD Robótica Aprendizagem Wifi ESP32 Camera Tutorial App RB2686. Ao longo de módulos estruturados em página única, são explorados desde a montagem mecânica do chassi com tração diferencial de duas rodas motrizes e roda boba, passando pelos fundamentos de eletrônica digital, modulação por largura de pulso (PWM — Pulse Width Modulation), comunicação entre circuitos integrados por barramento I2C (Inter-Integrated Circuit), redes sem fio WiFi nos modos estação (STA — Station) e ponto de acesso (AP — Access Point), até a construção de servidores Web (WebServer) para teleoperação e de sistemas de vídeo com streaming MJPEG sobre HTTP para navegador e aplicativo móvel.

Projetado para iniciantes absolutos e também útil para estudantes, hobbistas, técnicos e professores, este material ensina cada etapa como se fosse a primeira vez que você toca em um ferro de solda, em um cabo USB ou na IDE Arduino (Integrated Development Environment — ambiente integrado de desenvolvimento). Cada lição contém teoria de engenharia explicada sem pressa, tabela de componentes, imagens do passo a passo, tabela de conexões, código-fonte completo em C++ comentado linha a linha em português, procedimento de gravação e validação prática com o que você deve ver acontecer no robô, no Monitor Serial e no navegador.

Kit Robô 2WD ESP32-CAM Vision RB2686 totalmente montado com câmera frontal e faróis de LED Vista traseira do robô 2WD ESP32-CAM com placa driver, chave liga desliga e conector USB

O que você vai aprender:

  • Compreender a arquitetura do ESP32-S dual-core a 240 MHz, memória Flash e PSRAM, WiFi 2,4 GHz e câmera OV2640 de 2 megapixels
  • Realizar a montagem mecânica completa do chassi 2WD: roda boba, suporte de câmera, placa ESP32-CAM, rodas de borracha e pilhas 18650
  • Instalar do zero a IDE Arduino oficial, o driver USB-serial CH340/CH340C e o pacote de placas ESP32 versão 2.0.12 sem erros de ambiente
  • Dominar saídas digitais, constantes, temporização com delay, sinais analógicos simulados com PWM e efeito de LED respiratório
  • Controlar tração diferencial com motores N20 via I2C entre ESP32-CAM mestre e microcontrolador STC8G1K08 escravo com driver HR8833
  • Escanear redes WiFi, conectar em modo STA com eventos e IP, criar ponto de acesso AP próprio com monitoramento de clientes por MAC
  • Construir servidor Web embarcado com páginas HTML, rotas HTTP, comandos fetch e controle de velocidade em tempo real
  • Integrar câmera, vídeo ao vivo, farol com brilho PWM, ajuste de resolução e teleoperação completa no navegador e no aplicativo Kuongshun para Android e iOS

Material utilizado: Kit Robô 2WD Robótica Aprendizagem Wifi ESP32 Camera Tutorial App RB2686


Visão Geral do Kit e Arquitetura de Hardware

O Kit Robô 2WD ESP32-CAM Vision RB2686 (família AD179 / Kuongshun) é uma plataforma educacional compacta de robótica móvel com visão. Diferente dos kits 4WD com Arduino Uno e ponte H L298N, aqui o chassi de circuito impresso é ao mesmo tempo estrutura mecânica e placa eletrônica driver: os dois motores com caixa de redução, os dois faróis de LED branco de 10 mm, o circuito de carga das pilhas via USB, a indicação de nível de bateria com 4 LEDs, a chave liga/desliga, o conversor USB-serial CH340C e o soquete para a placa ESP32-CAM ACEBOTT já vêm integrados. Você monta poucas peças mecânicas e concentra o aprendizado em firmware, redes e vídeo — que é onde está o valor deste kit.

A tração é diferencial 2WD: duas rodas de borracha tracionadas de forma independente pelos motores esquerdo e direito, mais uma roda boba giratória livre na dianteira para equilíbrio. Para andar reto, os dois motores giram no mesmo sentido e velocidade. Para girar no próprio eixo, eles giram em sentidos opostos. A câmera fica na dianteira, entre os dois faróis, apontando para frente como os olhos do robô. O vídeo capturado é comprimido em JPEG pelo ESP32 e transmitido por WiFi para o celular ou computador.

Inventário completo do Kit Robô 2WD ESP32-CAM Vision RB2686 com chassi driver, ESP32-CAM, rodas, roda boba e fixadores

Especificações da Placa ESP32-CAM com OV2640

Parâmetro de EngenhariaEspecificação TécnicaObservações de Operação
SoC principalESP32-S dual-core Xtensa LX6 até 240 MHz, até 600 DMIPSUm núcleo pode cuidar do WiFi e vídeo, o outro da lógica do robô
Memória interna520 KB SRAMVariáveis, pilha, buffers de rede e câmera
Memória externa4 MB PSRAM + 32 Mbit (4 MB) Flash SPIPSRAM é essencial para segurar quadros JPEG da câmera
ConectividadeWiFi 802.11 b/g/n somente 2,4 GHz + Bluetooth 4.2 BR/EDR + BLENão enxerga redes 5 GHz; antena PCB onboard de 2 dBi
CâmeraOmniVision OV2640 2 MP, 1600x1200 UXGA, até 15 fps em UXGA, 30 fps em SVGAFormatos JPEG, BMP, tons de cinza; foco fixo, rolling shutter
InterfacesUART, SPI, I2C, PWM, ADC, DAC, slot microSD até 4 GBNeste kit, I2C é usado para comandar os motores
Alimentação típica5 VDC via placa driver; consumo 180 mA sem flash, até 310 mA com flash no máximoPicos de corrente do WiFi + motores exigem pilhas 18650 boas e carregadas
Dimensões do módulo40,5 mm x 27 mm x 4,5 mm, encapsulamento DIPEncaixa direto no soquete do chassi driver
Taxa serial padrão115200 bps no Monitor SerialDeve ser igual no código e na janela do monitor
Mapa de pinos da placa ESP32-CAM ACEBOTT com GPIO12, GPIO13, GPIO16, alimentação e câmera OV2640

Na placa ACEBOTT que acompanha o kit, observe três pinos que usaremos o tempo todo: GPIO12 comanda os faróis de LED branco através de transistor, GPIO16 é o SDA do I2C e GPIO13 é o SCL do I2C para falar com a placa driver. O endereço escravo I2C da driver é 0x30. A câmera usa um conector flat flexível dedicado — nunca puxe o cabo flat pelo fio laranja, sempre pela trava plástica do conector.

Placa Driver-Chassi Integrada: STC8G1K08 + HR8833

A grande sacada deste kit é não expor uma ponte H para você ligar fio por fio. A placa driver recebe comandos digitais simples via I2C do ESP32-CAM e traduz em PWM de potência para os motores:

  1. Seu programa chama Car_forward(100) no ESP32-CAM.
  2. A biblioteca SetMotor.h empacota direção + velocidade e envia pelo barramento I2C (SDA GPIO16, SCL GPIO13).
  3. O microcontrolador STC8G1K08 na placa driver, atuando como escravo I2C, interpreta o pacote.
  4. O STC8G1K08 gera sinais PWM que entram no driver de potência HR8833 (duplo ponte H para motores DC de baixa tensão).
  5. O HR8833 aplica tensão e sentido nas duas saídas dos motores N20.

O mesmo chassi gerencia a carga das pilhas pelo conector USB com 4 LEDs indicadores de nível. Esta placa não carrega e descarrega ao mesmo tempo: quando o chip de carga percebe consumo da carga, ele interrompe a carga e passa a descarregar. Por isso, para carregar, desligue a chave geral (posição OFF) antes de ligar o cabo USB.

⚠️ Atenção: nunca alimente os motores pela porta USB do computador sem as pilhas 18650 instaladas e carregadas. A USB serve para gravar o programa e carregar as pilhas com a chave desligada, não para tracionar o robô em teste de pista. Tentar andar só na USB causa reset por queda de tensão (brownout) e pode derrubar a porta USB do PC.

Inventário Completo de Componentes (Packing List do Kit RB2686)

O kit acompanha somente os componentes mecânicos, eletrônicos e de fixação abaixo. Pilhas 18650 não inclusas — providencie 2 unidades de boa procedência, com proteção, carregadas antes de começar:

  • 1x Chassi-placa driver integrada Kuongshun preta 2WD (com 2x motores N20 com redução metálica já soldados, 2x faróis LED branco 10 mm, circuito de carga USB, 4x LED de nível, chave ON/OFF, soquete ESP32-CAM, barra de pinos de expansão SVG)
  • 1x Placa controladora ESP32-CAM ACEBOTT com câmera OV2640 e suporte plástico de câmera
  • 2x Rodas de borracha com cubo branco e encaixe em D para eixo N20
  • 1x Roda boba giratória (caster wheel) com base plástica
  • 2x Espaçadores plásticos brancos M3x6 mm para nivelar a roda boba
  • 2x Parafusos cabeça chata Phillips M3x10 mm + 2x porcas sextavadas M3 para a roda boba
  • 3x Parafusos + 3x porcas para fixações auxiliares e câmera (conforme lote)
  • 2x Fitas adesivas dupla face para fixar a base da câmera e a ESP32-CAM
  • 1x Cabo USB de dados (para gravação e carga — use cabo de dados, não cabo só de carga)
  • 1x Chave de fenda pequena para montagem

💡 Dica: antes de montar, separe tudo sobre uma toalha clara, conte os parafusos e fotografe o kit aberto. Essa foto salva você se uma porca rolar para debaixo da mesa no meio da montagem.

O Que Você Precisa Providenciar Separadamente

  • 2x Pilhas recarregáveis 18650 de lítio (3,7 V nominais cada) com placa de proteção, de marca confiável, carregadas em carregador externo de qualidade
  • 1x Computador Windows 10/11 ou macOS com porta USB livre e permissão para instalar drivers
  • 1x Smartphone Android ou iPhone para as lições de vídeo (Android usa o APK Kuongshun fornecido; iPhone baixa o app kuongshun na App Store)
  • Opcional, mas recomendado: multímetro para medir tensão das pilhas e continuidade, e um pano seco para limpar as lentes da câmera sem riscar

⛔ Perigo: use apenas pilhas 18650 íntegras, sem amassados, rasgos na capa ou vazamento. Nunca inverta a polaridade no berço, nunca curto-circuite os terminais e nunca carregue com a chave do robô ligada. Bateria de lítio maltratada pode aquecer, inchar e causar queimadura ou incêndio.


Módulo 0 — Montagem Mecânica Passo a Passo e Arquitetura Elétrica

A montagem mecânica deste kit é propositalmente curta — 5 passos — para que o iniciante ganhe confiança rápido e passe logo para o software, que é o coração do curso. Mesmo assim, cada detalhe mecânico importa: uma roda boba sem espaçador deixa o chassi torto, uma câmera colada torta entorta o horizonte do vídeo, uma roda mal encaixada no eixo D patina e o robô anda em círculos. Siga na ordem, sem pular.

Ferramentas necessárias: apenas a chave de fenda que acompanha o kit e as próprias mãos. Não use furadeira, alicate de pressão ou cola quente — o chassi de PCB trinca com torque excessivo.

Passo 1: Instalar a Roda Boba Dianteira com Espaçadores

A roda boba é a terceira roda, pequena e giratória, que sustenta a frente do robô enquanto as duas rodas grandes tracionam atrás. Ela é fixada por baixo do chassi com dois parafusos M3x10 que atravessam o chassi, dois espaçadores plásticos brancos M3x6 no meio e duas porcas por baixo da base da roda boba.

Passo 1: diagrama explodido da instalação da roda boba com parafusos M3, espaçadores e porcas Passo 2: base do suporte da câmera com fitas dupla face e alinhamento na placa

Como fazer, sem pressa:

  1. Vire o chassi com a face dos componentes para cima e localize os dois furos da dianteira arredondada, entre os dois faróis de LED.
  2. Passe os dois parafusos M3x10 de cima para baixo pelos furos, deixando a cabeça chata assentada na face superior.
  3. Por baixo, encaixe um espaçador branco em cada parafuso. Este espaçador é obrigatório: ele garante a altura correta para o robô ficar nivelado. Sem ele, a frente arrasta no chão.
  4. Encaixe a base da roda boba nos dois parafusos, com a esfera para baixo.
  5. Rosqueie as duas porcas com os dedos até encostar, depois dê apenas um quarto de volta com a chave. A base deve ficar firme, mas sem deformar o plástico.

⚠️ Atenção: não aperte as porcas com força total. O aperto excessivo espana a rosca do parafuso, trinca a base plástica e empena o chassi. O correto é firme com dois dedos, sem folga lateral.

Validação: vire o chassi de lado sobre a mesa. As duas rodas grandes ainda não estão instaladas, então apoie com a mão. A roda boba deve girar 360 graus livremente com um toque de dedo, sem travar e sem balançar a base.

Passo 2: Preparar a Base do Suporte da Câmera com Fita Dupla Face

O suporte da câmera é uma moldura plástica preta que segura a ESP32-CAM na vertical, com a lente apontando para frente. Ele é fixado ao chassi e à placa por fita dupla face — solução simples, mas que exige capricho no alinhamento, pois a fita, uma vez colada, é difícil de reposicionar sem perder aderência.

Detalhe da separação da câmera e alinhamento da base com a borda da placa ESP32

Como fazer:

  1. Localize as duas tiras de fita dupla face e a base plástica do suporte.
  2. Descole a película protetora de um lado das duas fitas e cole-as paralelas na base do suporte, sem sobrepor as bordas.
  3. Descole a película do outro lado de uma das fitas e cole com cuidado o módulo da câmera nessa fita, centralizando a lente na janela do suporte.
  4. Descole a película restante e fixe o conjunto base + câmera sobre a placa ESP32-CAM, alinhando a borda externa da base rente à borda externa da placa. A lente deve ficar para o lado da borda, não para o centro da placa.
  5. Pressione por 10 segundos com os polegares, distribuindo a pressão, para ativar o adesivo.

💡 Dica: faça este passo com as mãos limpas e secas. Gordura dos dedos na fita ou na lente da câmera reduz a aderência e embaça a imagem. Se borrar a lente, limpe com haste flexível seca, sem álcool e sem soprar com a boca.

Passo 3: Encaixar a Placa ESP32-CAM no Soquete do Chassi

Com a câmera já presa à placa, o conjunto é plugado no soquete de pinos do chassi driver, na região dianteira entre os faróis. A base do suporte fica voltada para a traseira do robô, e a lente aponta para frente, por cima do espaço entre os faróis.

Passo 3: encaixe da placa ESP32-CAM com câmera no soquete do chassi driver

Como fazer:

  1. Desligue a chave geral do chassi (posição OFF) e não conecte USB nem pilhas neste momento.
  2. Segure a ESP32-CAM pelas bordas, sem tocar nos contatos dourados nem na lente.
  3. Alinhe todos os pinos macho da ESP32-CAM com as fêmeas do soquete do chassi. Confira que nenhum pino está torto ou fora do furo.
  4. Pressione verticalmente, com força distribuída nos dois lados, até sentir o encaixe completo. Não balance de um lado para o outro.
  5. Confira visualmente de lado: não pode haver vão entre a placa e o soquete, nem pino dobrado para fora.

⚠️ Atenção: nunca encaixe ou remova a ESP32-CAM com o robô ligado ou com USB conectado. Plugar com energia pode queimar o regulador da placa ou corromper a Flash no meio de uma escrita.

Validação: com o robô ainda desligado, segure o chassi e balance de leve. A placa não deve balançar nem fazer barulho de mal contato. A câmera deve estar aprumada, sem inclinar para um lado.

Passo 4: Instalar as Rodas de Borracha nos Eixos D dos Motores N20

As duas rodas de borracha encaixam sob pressão nos eixos dos motores N20. Tanto o eixo quanto o furo do cubo têm um lado achatado em forma de D — é um sistema anti-giro: só entra na posição certa e depois não patina.

Passo 4: encaixe das rodas de borracha nos eixos D dos motores com alinhamento do lado chato Detalhe do acoplamento do cubo em D com o eixo do motor N20

Como fazer:

  1. Segure firme o corpo metálico do motor com uma mão — nunca puxe pelos fios finos soldados.
  2. Com a outra mão, alinhe o lado chato do furo da roda com o lado chato do eixo.
  3. Empurre reto, sem girar, até a face interna do cubo encostar no ressalto do eixo. O encaixe termina quando o lado chato do eixo fica rente à face interna da roda.
  4. Repita do outro lado. As duas rodas devem ficar na mesma profundidade.

⚠️ Atenção: sempre segure o motor pelo corpo metálico ao colocar ou tirar rodas. Se segurar o chassi e forçar a roda, você arranca os fios do motor da solda — o defeito mais comum em assistências deste kit e de reparo chato para iniciantes.

Validação: gire cada roda com o dedo. Ela deve girar o motor com resistência suave e uniforme, sem escapar do eixo e sem roçar no chassi. As duas rodas devem estar paralelas e na mesma altura.

Passo 5: Instalar as 2 Pilhas 18650 com Polaridade Correta

Vire o robô de barriga para cima. O berço das pilhas fica na face inferior do chassi. O positivo de cada célula deve ficar para o lado esquerdo quando o robô está de costas (conforme a serigrafia + e − no chassi). Este é o passo elétrico mais importante da montagem: polaridade invertida impede o funcionamento e pode danificar o circuito de proteção.

Passo 5: instalação das pilhas 18650 no berço inferior com positivo à esquerda

Como fazer, com o robô desligado e sem USB:

  1. Confira que a chave geral está em OFF.
  2. Identifique no berço os símbolos + e − em relevo ou serigrafia.
  3. Encaixe primeiro o polo negativo (lado chato da pilha) contra a mola, comprimindo-a, depois abaixe o polo positivo (com botão) no contato liso.
  4. Repita para a segunda célula, respeitando a mesma orientação indicada.
  5. Empurre de leve cada pilha: elas devem ficar presas, sem folga, sem girar sozinhas.

⛔ Perigo: se alguma pilha aquecer, chiar ou soltar cheiro forte logo ao encaixar, remova imediatamente com pano seco, sem tocar nos terminais com os dedos, e não use mais essa célula. É sinal de curto ou célula danificada.

Validação inicial de energia: com as pilhas instaladas e ainda sem programa novo, ligue a chave para ON por 3 segundos. Os LEDs indicadores de bateria devem acender. Desligue em seguida. Se nenhum LED acender, desligue, retire as pilhas e revise polaridade e carga antes de prosseguir. Não siga para o software com alimentação duvidosa.


Módulo 1 — Preparação do Ambiente e Ferramental de Software para Iniciantes

Este módulo foi escrito para quem nunca instalou nada de eletrônica no computador. Vamos instalar três coisas, nesta ordem obrigatória: 1) a IDE Arduino oficial, 2) o driver USB-serial CH340/CH340C, 3) o pacote de placas ESP32 versão 2.0.12. Só depois vamos selecionar placa, porta e gravar o primeiro programa. Não inverta a ordem: sem IDE não há onde programar, sem driver o computador não enxerga o robô, sem o pacote ESP32 a IDE não sabe compilar para o chip do robô.

Conceito essencial: a IDE Arduino é o programa onde você escreve, verifica e envia o código para o robô. O driver CH340 é o tradutor entre a porta USB do computador e a porta serial do robô — o chip CH340C na placa driver faz essa conversão. O pacote ESP32 é um complemento que ensina a IDE a gerar código de máquina para o processador Xtensa do ESP32, que é totalmente diferente do ATmega do Arduino Uno.

Lição 0.1: Instalar a IDE Arduino Oficial Passo a Passo no Windows

A documentação oficial do kit usa o site arduino.cc e o instalador clássico com telas de licença e seleção de componentes. Siga exatamente:

Página oficial de download da IDE Arduino com opções para Windows Botão Just Download para baixar a IDE sem doação obrigatória
  1. Acesse https://www.arduino.cc/en/software no navegador. É o único endereço oficial — não baixe de sites agregadores, que embutem adware.
  2. Na seção de Windows, escolha o instalador .exe (não a versão ZIP nem a da Microsoft Store para este curso, pois o instalador registra drivers e atalhos corretamente).
  3. Na página de doação, clique em JUST DOWNLOAD para baixar sem contribuir (ou contribua se quiser apoiar o projeto open-source).
  4. Aguarde o download concluir. O arquivo tem centenas de megabytes — não pause nem troque de rede no meio.
Assistente de instalação da IDE Arduino com aceite da licença Seleção de componentes do instalador incluindo drivers USB
  1. Dê duplo clique no instalador e confirme a elevação de administrador quando o Windows pedir.
  2. Clique em I Agree na licença, mantenha todos os componentes marcados (principalmente USB driver e atalhos) e clique em Next.
  3. Mantenha a pasta padrão C:\Program Files (x86)\Arduino e clique em Install. Aguarde a barra concluir sem fechar a janela.
  4. Se o Windows perguntar se deseja instalar o driver da Arduino LLC, clique em Instalar. É o driver das placas originais — não conflita com o CH340 que veremos a seguir.
  5. Ao final, marque a opção de abrir a IDE e clique em Close. Um ícone da IDE aparece na área de trabalho.

💡 Dica: no macOS o processo é arrastar o ícone da IDE para a pasta Aplicativos a partir do .dmg baixado no mesmo site oficial. No Linux, prefira o AppImage oficial, dê permissão de execução e adicione seu usuário ao grupo dialout para ter acesso à serial sem sudo.

Validação: abra a IDE. Você deve ver a janela com menu Arquivo, Editar, Sketch, Ferramentas, Ajuda, um editor em branco com void setup() e void loop() no exemplo padrão, e a barra de status inferior. Se a IDE abrir sem erro, a etapa 1 está cumprida.

Lição 0.2: Instalar e Confirmar o Driver USB-serial CH340/CH340C

O chip USB-serial deste robô é o CH340C, conforme a documentação oficial do fabricante na pasta 2_Programming_Preparation. No Windows 10/11 e no macOS modernos, ao ligar o robô pela primeira vez com um cabo USB de dados bom, o sistema tenta instalar sozinho. Se falhar — caso mais comum em PCs corporativos ou com Windows desatualizado — instale manualmente com o pacote USB_Drive_CH341_3_1 fornecido na documentação.

Conexão da placa controladora ao computador com cabo USB de dados Gerenciador de Dispositivos mostrando dispositivo USB-Serial desconhecido

Passo a passo de verificação primeiro (não instale sem necessidade):

  1. Com a IDE fechada, ligue o robô na posição OFF (só para o driver, sem tracionar) e conecte o cabo USB entre o conector da placa driver e uma porta USB direta do computador (evite hub sem alimentação).
  2. Abra o Gerenciador de Dispositivos do Windows (botão direito em Este Computador → Gerenciar → Gerenciador de Dispositivos).
  3. Observe a seção Portas (COM e LPT) e Outros dispositivos:
    • Se aparecer USB-SERIAL CH340 (COMx) em Portas, o driver já está ok. Anote o número COM e pule a instalação.
    • Se aparecer USB-Serial ou Dispositivo Desconhecido com ponto de exclamação em Outros dispositivos, siga para a instalação manual abaixo.

Instalação manual no Windows com o pacote oficial:

Atualização manual do driver apontando para a pasta USB Drive CH341 Confirmação de instalação bem sucedida do driver CH340
  1. Descompacte a pasta USB_Drive_CH341_3_1 da documentação para um caminho simples, por exemplo C:\Drivers\CH340.
  2. No Gerenciador de Dispositivos, clique com o botão direito sobre o dispositivo desconhecido e escolha Atualizar driver.
  3. Escolha Procurar driver no computador, não a busca automática.
  4. Clique em Procurar, aponte para C:\Drivers\CH340 e marque Incluir subpastas. Avance.
  5. Aguarde a mensagem de sucesso e clique em Fechar. Desconecte e reconecte o USB. Agora deve aparecer USB-SERIAL CH340 (COMx) em Portas.

No macOS: use a pasta CH340 Driver file-mac da documentação. Instale o .pkg (ou o .dmg arrastando CH34xVCPDriver para Aplicativos e executando Instalar, conforme a versão do sistema), autorize nas Preferências → Segurança e Privacidade se o sistema bloquear, reinicie se solicitado (10.9 a 10.15) e confira no Relatório do Sistema → Hardware → USB a presença de dispositivo com Vendor ID 0x1a86. Esse VID é a assinatura do fabricante WCH do CH340.

⚠️ Atenção: use sempre cabo USB de dados completo (4 fios). Cabos baratos de só carga (2 fios) acendem LED mas nunca criam porta COM — é a causa número 1 de “meu robô não aparece”. Teste com outro cabo de celular conhecido antes de culpar o driver. E conecte direto na USB traseira do desktop ou em porta do notebook, não em hub passivo.

Validação final do driver: com o robô conectado, abra a IDE → menu Ferramentas → Porta. Deve existir uma porta COMx (Windows) ou /dev/cu.wchusbserial... (macOS). Desconecte o USB e veja a porta sumir; reconecte e veja voltar. Se sumir e voltar, você identificou a porta certa do robô.

Lição 0.3: Instalar o Pacote de Placas ESP32 Versão 2.0.12 Sem Erro

Com IDE e driver prontos, falta ensinar a IDE a falar ESP32. A documentação oficial exige a versão 2.0.12 e proíbe versões 3.0 ou superiores, que quebram as bibliotecas de câmera e os exemplos deste kit. Siga pelo Método 1 online; use o Método 2 offline só se a internet bloquear o download.

Menu Arquivo Preferências da IDE Arduino para adicionar URLs de placas Campo URLs Adicionais do Gerenciador de Placas com endereços ESP32

Método 1 — online (Windows e macOS):

  1. Abra a IDE Arduino. Acesse Arquivo → Preferências.
  2. No campo URLs Adicionais para Gerenciador de Placas, cole exatamente as duas linhas abaixo (uma por linha), sem espaços extras:
    • http://arduino.esp8266.com/stable/package_esp8266com_index.json
    • https://www.arduino.me/package_esp32_index.json
  3. Clique em OK para salvar e fechar as Preferências.
  4. Acesse Ferramentas → Placa → Gerenciador de Placas.
  5. Na busca, digite esp32. Localize o pacote esp32 (mantenedor Arduino/Espressif conforme o índice) e no seletor de versão escolha 2.0.12 — não a mais recente.
  6. Clique em Instalar e aguarde sem fechar a IDE nem desligar a internet. São centenas de megabytes com toolchain, framework e exemplos. Ao terminar, feche e reabra a IDE.
Gerenciador de Placas com pacote ESP32 versão 2.0.12 selecionada Seleção da placa ESP32 Dev Module no menu Ferramentas

Método 2 — offline (somente Windows, se o Método 1 falhar repetidamente):

  1. Repita o passo das URLs, mas usando https://arduino.me/packages/esp32.json no campo de Preferências.
  2. Na pasta 2. Install the ESP32 plugin in the Arduino IDE da documentação, execute esp32_package_2.0.12_arduinome.exe como administrador. O programa extrai os arquivos para o local correto automaticamente.
  3. Reabra a IDE e confira em Ferramentas → Placa se o grupo ESP32 Arduino aparece.

Configuração obrigatória para este curso em Ferramentas:

  • Placa: ESP32 Dev Module (é o nome genérico que compila para a ESP32-CAM deste kit nos exemplos)
  • Porta: a COMx / /dev/cu.wchusbserial... identificada na lição anterior
  • Taxa de upload: mantenha o padrão (921600 ou 115200 conforme o exemplo — não altere se o upload funcionar)
  • Deixe as demais opções no padrão do pacote 2.0.12.

⚠️ Atenção: se você já tinha ESP32 3.x instalado de outro curso, desinstale pelo Gerenciador de Placas e instale a 2.0.12 limpa. Misturar núcleos causa erros famosos como camera_config_t não declarado, ledcSetup inexistente e falha de upload com Brownout detector was triggered. Este kit foi validado na 2.0.12.

Validação do ambiente completo: abra na IDE o exemplo Arquivo → Exemplos → Basics → Blink (só para teste da toolchain, sem gravar no robô ainda), clique no botão Verificar (✓). Deve compilar sem erro e mostrar Sketch uses ... bytes na saída. Se compilar, seu ambiente está pronto. Na próxima parte gravaremos o primeiro firmware real do robô e veremos os faróis piscarem sob nosso comando.

💡 Dica: crie agora a estrutura de pastas Documentos\Arduino\RB2686_Lessons e copie para dentro a pasta 4_Code original da documentação sem renomear arquivos internos. Manter os nomes originais (LED.ino, Brightness_light.ino, Car_Motor.ino etc.) evita erros de #include com caminhos que os exemplos esperam.


Módulo 2 — Fundamentos Digitais, Luz e Modulação PWM

Este módulo ensina o alfabeto da eletrônica embarcada: ligar e desligar coisas com precisão de milissegundos e, em seguida, fingir que existe meio-termo entre ligado e desligado usando chaveamento rápido. Parece truque, mas é a base de faróis com brilho ajustável, controle de velocidade de motores e até som. Faremos isso nos faróis de LED do próprio robô, sem protoboard e sem fios soltos — o circuito já está pronto no chassi, esperando seu comando no GPIO12.

Projeto 1 (Lição 2): Faróis Piscantes e Controle de Saídas Digitais

Visão Geral e Teoria

Na vida real, os faróis de um carro têm duas missões: ver e ser visto. Ver à noite ou na neblina e sinalizar presença, frenagem e mudança de direção para os outros. No nosso robô, os dois LEDs brancos de 10 mm da dianteira cumprem exatamente esse papel didático: são a carga mais simples e segura para aprender saída digital antes de partir para motores que consomem centenas de miliamperes e exigem driver de potência.

O circuito dos faróis, extraído do esquemático oficial do kit, é uma aula de eletrônica em si. Os dois LEDs estão ligados ao +5 V através de resistores limitadores de 1 kΩ cada. O retorno à terra (GND) passa pelo transistor NPN S8050, que funciona como chave eletrônica comandada pelo pino IO12 da ESP32-CAM através de um resistor de base de 1 kΩ, com um resistor de pull-down de 10 kΩ garantindo que a base não flutue quando o pino está em alta impedância. Quando IO12 está em nível alto, o transistor satura e a corrente flui: +5 V → LED → resistor 1 kΩ → coletor-emissor do S8050 → GND, e os faróis acendem. Quando IO12 está em nível baixo, o transistor corta, o caminho abre e os faróis apagam. Sem o transistor, o pino do ESP32 teria que fornecer toda a corrente dos LEDs, o que o sobrecarregaria; com o transistor, o pino fornece apenas uma pequena corrente de base e o transistor chaveia a corrente maior dos LEDs — conceito de amplificação de corrente e isolação que você reencontrará em relés, MOSFETs e drivers de motor.

Esquemático oficial dos faróis de LED com transistor S8050 comandado pelo pino IO12 Vista superior do chassi com os dois faróis de LED branco e a placa ESP32-CAM encaixada

A programação Arduino segue a mesma lógica de qualquer sketch: duas funções obrigatórias, setup() que roda uma única vez para configurar, e loop() que repete para sempre. Colocar o pisca no setup() faz o LED piscar uma vez ao ligar; colocar no loop() faz piscar continuamente. Usaremos uma constante chamada LED valendo 12 para nunca mais espalhar o número mágico 12 pelo código — se um dia o hardware mudar, altera-se uma linha.

Tabela de Componentes Necessários

ComponenteQuantidadeEspecificação
Robô RB2686 montado (chassi + ESP32-CAM + câmera)1Com pilhas 18650 instaladas e chave em OFF para conectar USB
Cabo USB de dados1Completo 4 fios, conectado direto ao PC
Computador com IDE + driver CH340 + pacote ESP32 2.0.121Conforme Módulo 1, porta COM identificada
Faróis de LED branco do próprio chassi210 mm, já soldados, comandados por IO12 via S8050

Nenhum componente avulso é necessário: protoboard, jumpers e resistores externos estão dispensados porque o circuito de potência dos LEDs já está no chassi.

Tabela de Conexões de Pinos

Pino ESP32-CAMDestino no ChassiFunção
GPIO12 (IO12)Base do transistor S8050 via resistor 1 kΩComando digital dos faróis: HIGH acende, LOW apaga
5VAnodos dos LEDs via resistores 1 kΩAlimentação dos faróis
GNDEmissor do S8050 + pull-down 10 kΩRetorno e referência, evita acendimento espúrio

Não há fiação para fazer: a tabela acima documenta o que já está soldado, para você entender o caminho da corrente e diagnosticar defeitos.

Código-Fonte Completo Comentado Linha a Linha

Abra na IDE o arquivo LED.ino em 4_Code\lesson 2 LED\LED ou digite o código abaixo em um sketch novo e salve como RB2686_L2_LED:

// ============================================================
// RB2686 - PROJETO 1 (LICAO 2): FAROIS PISCANTES NO GPIO12
// Placa: ESP32 Dev Module | Núcleo ESP32 2.0.12 | 115200 bps
// Hardware: 2x LED branco 10mm via transistor S8050 no IO12
// Comportamento: acende 1 s, apaga 1 s, repete para sempre
// ============================================================

#define LED 12  // Cria o apelido LED para o pino 12: o resto do
                // programa usa LED em vez do número puro, o que
                // deixa a leitura clara e a manutenção trivial.

void setup() {
  // Configura o pino dos faróis como SAÍDA digital.
  // OUTPUT significa que a ESP32 vai impor tensão (3,3 V / 0 V)
  // nesse pino, em vez de ler tensão externa como faria em INPUT.
  pinMode(LED, OUTPUT);
}

void loop() {
  // Liga os faróis: impõe nível ALTO no GPIO12.
  // O transistor S8050 satura e fecha o caminho LED -> GND.
  digitalWrite(LED, HIGH);

  // Congela o programa por 1000 milissegundos (1 segundo).
  // Durante o delay nada mais executa: é bloqueio proposital
  // para didática de temporização. Em projetos com WiFi e vídeo
  // evitaremos delays longos no loop principal.
  delay(1000);

  // Desliga os faróis: impõe nível BAIXO no GPIO12.
  // O transistor corta e abre o caminho LED -> GND.
  digitalWrite(LED, LOW);

  // Mantém apagado por mais 1 segundo antes de repetir o ciclo.
  delay(1000);
}

Funções novas deste projeto, para guardar no caderno: pinMode(pino, modo) define se o pino empurra tensão (OUTPUT) ou escuta tensão (INPUT); digitalWrite(pino, valor) impõe HIGH (3,3 V) ou LOW (0 V) em pino configurado como saída — antes de usar digitalWrite, o pinMode como OUTPUT é obrigatório; delay(ms) pausa tudo pelo tempo em milissegundos. Nível alto na ESP32-CAM deste kit significa cerca de 3,3 V, nível baixo significa 0 V. Quando o anodo do LED está em 5 V e o catodo é puxado a 0 V pelo transistor, surge diferença de potencial, circula corrente limitada pelos resistores e o LED converte energia em luz. Com 0 V dos dois lados, sem diferença, sem corrente, sem luz.

Gravação Passo a Passo para Iniciantes (vale para todo o curso)

Este ritual de gravação será repetido em todas as lições, então faça com calma uma vez e decore:

Robô RB2686 conectado ao computador com cabo USB de dados para gravação Seleção da placa ESP32 Dev Module e da porta COM na IDE Arduino
  1. Com a chave do robô em OFF, conecte o cabo USB entre o conector da placa driver e o PC. Aguarde o som de dispositivo conectado e a porta COM aparecer.
  2. Na IDE, acesse Ferramentas → Placa → ESP32 Arduino → ESP32 Dev Module. Confira que não está selecionado Arduino Uno nem outro ESP32.
  3. Acesse Ferramentas → Porta e marque a porta do robô (a que some ao desplugar e volta ao plugar, identificada no Módulo 1).
  4. Abra o sketch LED.ino. Clique no botão Verificar (✓) primeiro: deve compilar sem erros em laranja na saída.
  5. Clique no botão Carregar (→). Acompanhe a barra de progresso e as mensagens: Connecting..., Writing..., Hard resetting via RTS pin.... Não toque no cabo durante a escrita.
  6. Aguarde Done uploading. Se aparecer erro de conexão, desconecte, reconecte, confira placa e porta, e tente de novo antes de mudar qualquer outra coisa.
Botão de upload e mensagens de gravação concluída com sucesso na IDE

Instruções de Teste e Validação

  1. Após o upload, observe os dois faróis da dianteira: devem acender juntos por 1 segundo e apagar por 1 segundo, em ciclo contínuo.
  2. Desconecte o USB com cuidado, coloque o robô sobre a mesa com as rodas livres, ligue a chave para ON: o pisca continua, agora alimentado pelas 18650 — prova de que o programa ficou gravado na Flash e roda sem PC.
  3. Teste de sanidade: tampe os faróis com a mão em ambiente escuro — a luz deve vazar entre os dedos de forma perceptível. Se um LED acende e o outro não, anote: é defeito de LED ou solda, não de código, pois ambos obedecem ao mesmo transistor.
  4. Para provar a diferença entre setup() e loop(), mova temporariamente o bloco de pisca para dentro do setup() deixando o loop() vazio, grave de novo e resete: os faróis piscam uma única vez e param — exatamente o comportamento documentado na teoria.

💡 Dica: se nada acender, não reescreva o código ainda. Confira nesta ordem de 1 minuto cada: chave ON com pilhas carregadas para teste sem USB, cabo USB de dados (não de carga), placa ESP32 Dev Module, porta COM certa, resistor e transistor (teste visual de solda fria). Noventa por cento dos “defeitos de código” nesta lição são ambiente ou alimentação.

⚠️ Atenção: durante o upload deixe o robô parado sobre a mesa, longe da borda, sem as rodas tracionando nada. Nesta lição os motores ficam parados, mas o hábito de bancada segura evita quedas nas lições de movimento.

Projeto 2 (Lição 3): Farol Respiratório com PWM e Sinais Analógicos

Visão Geral e Teoria

No projeto anterior só existiam dois estados: tudo ou nada. Na vida real, a luz do painel do carro à noite não fica no máximo — ela dimeriza suavemente. O robô parado “respirando” com os faróis pulsando parece vivo. Para esse efeito precisamos de meio-termo entre 0 V e 5 V, mas o pino digital só sabe 0 e 1. A solução é o PWM (Pulse Width Modulation): chavear rapidíssimo entre 0 e 1 de modo que a média pareça um valor intermediário para o olho humano e para o LED.

Sinal digital tem só dois patamares (0 V ou nível alto) em cada instante — como resposta de sim ou não. Sinal analógico varia continuamente entre 0 e 5 V — como temperatura, som e luz ambiente. O PWM usa sinal digital para simular analógico: dentro de cada período fixo, mantém nível alto por uma fração chamada largura de pulso; a razão entre largura e período é o duty cycle. Com 0% o LED fica apagado (0 V médio), 25% brilha fraco (~1,25 V médios), 50% meio brilho (~2,5 V), 75% forte (~3,75 V) e 100% máximo. Chaveando a milhares de hertz, o olho não vê o pisca individual — vê brilho contínuo proporcional ao duty.

Gráfico de sinal digital com apenas dois níveis 0 V e 5 V Gráfico de sinal analógico variando continuamente entre 0 e 5 V
Princípio do PWM com período fixo e largura de pulso variável Trem de pulsos PWM e tensão média resultante no LED

No ESP32, a função analogWrite(pino, valor) com valor de 0 a 255 abstrai o PWM: 0 é sempre apagado, 255 sempre aceso, 127 é meio brilho. Por dentro, ela configura um canal do periférico LEDC do ESP32 com frequência e resolução e ajusta o duty. O efeito respiratório nasce de variar esse valor em rampa: sobe de 0 a 255 de 5 em 5 com pequena pausa, depois desce de 255 a 0 — e repete. A rampa lenta (5 ms por degrau) é o que o olho percebe como inspiração e expiração suaves.

Para a rampa precisamos de dois recursos de linguagem: variáveis (caixas com nome que guardam valores mutáveis, como int brightness para o brilho atual) e laço for (repetição com início, condição e passo explícitos). A sintaxe for (brightness = 0; brightness <= 255; brightness += 5) lê-se: comece em 0, enquanto for menor ou igual a 255 execute o corpo e some 5 ao final de cada volta. É a forma compacta e segura de percorrer os 52 degraus de subida sem escrever 52 linhas.

Tabela de Componentes Necessários

ComponenteQuantidadeEspecificação
Robô RB2686 montado e funcional do Projeto 11Pisca validado prova que GPIO12, transistor e alimentação estão sadios
IDE com ESP32 2.0.12 e porta COM1Mesmo ambiente, sem trocar nada
Olho humano e ambiente com luz controlável1Para perceber a rampa: teste também no escuro para ver a respiração

Tabela de Conexões de Pinos

Idêntica ao Projeto 1 — nenhum fio muda, só a forma de comandar o mesmo pino:

Pino ESP32-CAMComando Neste ProjetoEfeito
GPIO12analogWrite(LED, brightness) com brightness 0–255Brilho proporcional ao duty cycle do PWM

A lição propositalmente reaproveita o hardware para isolar a variável didática: o que muda é software (digital fixo vs. PWM variável), não o circuito.

Código-Fonte Completo Comentado Linha a Linha

Abra Brightness_light.ino em 4_Code\lesson 3 Brightness\Brightness_light ou crie RB2686_L3_Respiracao:

// ============================================================
// RB2686 - PROJETO 2 (LICAO 3): FAROL RESPIRATORIO COM PWM
// Hardware: mesmos faróis do Projeto 1, agora com brilho
// Comportamento: clareia de 0 a 255 e escurece de 255 a 0
// Conceitos: variável, laço for, analogWrite (PWM 0-255)
// ============================================================

#define LED 12  // Apelido para o pino dos faróis. Mantém o
                // código legível e centraliza eventual mudança
                // de hardware em um único ponto.

int brightness; // Declara a variável global que guarda o brilho
                // atual (0 a 255). Tipo int comporta folgado.
                // Global para ser visível nos dois laços do loop.

void setup() {
  // Configura o pino como saída. Obrigatório antes de qualquer
  // escrita, seja digitalWrite ou analogWrite.
  pinMode(LED, OUTPUT);
}

void loop() {
  // ---- RAMPA DE SUBIDA: inspiração suave ----
  // Começa em 0 (apagado), repete enquanto <= 255, soma 5 por
  // volta. Cada volta escreve o brilho e espera 5 ms.
  for (brightness = 0; brightness <= 255; brightness += 5) {
    // Impõe no pino um PWM com duty proporcional a brightness.
    // 0 = 0% (apagado), 127 ~= 50% (meio), 255 = 100% (máximo).
    analogWrite(LED, brightness);
    // Pausa curta que define a velocidade da respiração.
    // 52 degraus x 5 ms ~= 260 ms por rampa. Aumente para
    // respirar mais devagar, diminua para mais rápido.
    delay(5);
  }

  // ---- RAMPA DE DESCIDA: expiração suave ----
  // Começa em 255 (máximo), repete enquanto >= 0, subtrai 5
  // por volta. Espelha a subida para simetria visual.
  for (brightness = 255; brightness >= 0; brightness -= 5) {
    // Mesmo PWM, agora com valores decrescentes: o olho vê
    // o brilho caindo sem degraus perceptíveis.
    analogWrite(LED, brightness);
    // Mesma pausa da subida para manter o ritmo simétrico.
    delay(5);
  }
  // Ao terminar a descida, o loop recomeça na subida: o ciclo
  // respiratório continua para sempre até reset ou novo upload.
}

Detalhe de engenharia: analogWrite(pino, valor) na ESP32 deste núcleo configura PWM por software/hardware com resolução de 8 bits (256 níveis). Não é tensão analógica verdadeira — é média temporal. LEDs respondem rápido o suficiente para que a média vire brilho. Motores responderão com velocidade. É o mesmo princípio, duas percepções.

Instruções de Teste e Validação

  1. Grave com o mesmo ritual do Projeto 1 (ESP32 Dev Module + porta + Carregar). Observe: os faróis agora não piscam seco — clareiam progressivamente, atingem o pico e escurecem progressivamente, sem saltos.
  2. Cronometre uma respiração completa (subida + descida): deve durar cerca de meio segundo com delay(5). Altere ambos os delay(5) para delay(20) e grave de novo: a respiração fica ~4x mais lenta — prova viva de que o delay controla a velocidade do efeito, não o brilho final.
  3. Teste de degraus: troque o passo += 5 por += 51 (apenas 6 níveis: 0, 51, 102, 153, 204, 255) e observe os saltos visíveis — demonstração de quantização do PWM de 8 bits.
  4. Volte aos valores originais (+= 5, delay(5)) antes de seguir: os próximos projetos assumem o código padrão da documentação.

💡 Dica: se o LED parecer sempre no máximo sem respirar, suspeite de analogWrite em pino errado ou núcleo ESP32 3.x instalado por engano, onde a API de PWM mudou. Confira #define LED 12 e reinstale o pacote 2.0.12 conforme o Módulo 1 antes de culpar o hardware.


Módulo 3 — Tração Diferencial e Comando de Motores via Barramento I2C

Chegou a hora de tirar as rodas do chão — literalmente nos testes iniciais — e entender como duas rodas independentes viram um carro que anda reto, ré e gira no próprio eixo. Este é o módulo mecatrônico do curso: eletromagnetismo nos motores, ponte H de potência e comunicação digital entre dois chips. Ao final, seu robô executará sozinho a coreografia padrão da documentação: frente 2 s, ré 2 s, esquerda 2 s, direita 2 s, parada — o “olá, mundo” da robótica móvel.

Projeto 3 (Lição 4): Fazer o Carrinho Andar com Biblioteca SetMotor

Visão Geral e Teoria

Um motor DC converte energia elétrica em rotação por indução eletromagnética: corrente nas bobinas cria campo que interage com ímãs e gera torque no eixo. Inverter a polaridade inverte o sentido. Variar a tensão média (com PWM, de novo ele) varia a velocidade. Parece simples, mas o ESP32 não pode ligar o motor direto: o motor puxa centenas de miliamperes com picos de partida, enquanto o pino do ESP32 fornece dezenas de miliamperes. Entre eles entra o driver de potência — aqui o HR8833, dupla ponte H que recebe lógica fraca e entrega potência forte, com proteção e chaveamento adequado para N20 de baixa tensão.

Nosso chassi é um 2WD diferencial com roda boba: dois N20 independentes + uma roda livre. A cinemática é intuitiva: mesma velocidade e sentido nos dois motores, o robô anda reto (frente se ambos para frente, ré se ambos para trás); sentidos opostos com mesma velocidade, o robô gira no próprio eixo (esquerda/direita conforme qual motor vai para frente). A roda boba só equilibra e permite o giro sem arrastar. É o mesmo princípio de cadeira de rodas motorizada e de robôs aspiradores.

A particularidade deste kit é o I2C como idioma entre placas: a ESP32-CAM é mestre, o STC8G1K08 na driver é escravo no endereço 0x30. A ESP32 não gera PWM de potência — ela envia pacotes curtos direção_esquerda, direção_direita, velocidade pelo par SDA (GPIO16) + SCL (GPIO13). O STC8G1K08 decodifica e produz os PWMs que o HR8833 precisa. Vantagem didática e prática: economiza pinos da ESP32 (só 2 fios para os dois motores), isola ruído de potência da lógica e permite evoluir a driver sem trocar o código de alto nível — você chama Car_forward(100) e a biblioteca resolve o resto.

Tabela de Componentes Necessários

ComponenteQuantidadeEspecificação
Robô RB2686 com Projetos 1–2 validados1Faróis ok provam alimentação e gravação sadias
Pilhas 18650 carregadas (tensão medida se possível)2Acima de 3,7 V cada em repouso; abaixo disso recarregue antes do teste de pista
Espaço de teste seguro1Mesa larga com anteparo ou chão liso com 2 m livres; nada de bancada alta sem proteção
Suporte para elevar as rodas (opcional, recomendado)1Caixa baixa ou livro para o primeiro teste com rodas livres

Tabela de Conexões de Pinos (lógica, já soldada)

SinalPino ESP32Fio I2C / FunçãoDestino
SDAGPIO16Dados do barramento I2C mestreSTC8G1K08 escravo addr 0x30 na driver
SCLGPIO13Clock do barramento I2C mestreSTC8G1K08 escravo addr 0x30 na driver
FaróisGPIO12PWM/digital dos LEDs (projetos anteriores)Transistor S8050 (mantido)

Nenhum jumper para ligar: o barramento já está roteado no PCB. A tabela serve para diagnosticar com multímetro ou osciloscópio no futuro e para não reutilizar GPIO16/13 para sensores sem entender o conflito.

Biblioteca SetMotor.h Desvendada Linha a Linha

O arquivo SetMotor.h em 4_Code\lesson 4 Make the Car Move\Car_Motor é o motorista particular do robô. Leia com atenção antes do sketch principal:

// Trecho essencial do SetMotor.h oficial (comentários traduzidos
// e expandidos para didática — lógica 100% preservada):
#ifndef SERMOTOR_H
#define SERMOTOR_H
#include "Arduino.h"  // Núcleo Arduino: tipos, pinMode, delay etc.
#include <Wire.h>     // Biblioteca I2C do ESP32: begin, transmissão.

#define sda 16  // Pino físico do SDA do I2C neste kit: GPIO16.
#define scl 13  // Pino físico do SCL do I2C neste kit: GPIO13.
uint8_t slave_addr = 0x30;  // Endereço de 8 bits do escravo STC8.
// Na transmissão usa-se slave_addr >> 1 (desloca 1 bit) porque
// a Wire espera endereço de 7 bits + bit R/W separado.

void i2c_init() {
  Wire.begin(sda, scl);  // Entra no barramento como mestre,
                         // informando quais pinos são SDA e SCL.
}

void i2c_Write(uint8_t d1, uint8_t d2, uint16_t speed) {
  Wire.beginTransmission(slave_addr >> 1);  // Abre conversa com escravo.
  Wire.write(0x00);   // Cabeçalho do protocolo da driver (fixo).
  Wire.write(d1);     // Comando do motor 1: 0=para, 1=frente, 2=ré.
  Wire.write(d2);     // Comando do motor 2: mesma codificação.
  Wire.write(speed);  // Velocidade PWM (0-255 típico neste kit).
  Wire.endTransmission();  // Fecha e efetivamente transmite.
}

// Car_run traduz intenção em pacote: d1/d2 codificam sentido.
void Car_run(int d1, int d2, uint16_t speed) {
  if (d1 == 2) d1 = 2;  // Guarda explícita do código original:
  if (d2 == 2) d2 = 2;  // 2 significa ré em ambas as rodas.
  i2c_Write(d1, d2, speed);  // Envia o pacote montado via I2C.
}

void Car_forward(uint16_t speed)  { Car_run(1, 1, speed); }
void Car_backwards(uint16_t speed) { Car_run(2, 2, speed); }
void Car_left(uint16_t speed)     { Car_run(1, 2, speed); }
void Car_right(uint16_t speed)    { Car_run(2, 1, speed); }
void Car_stop()                   { Car_run(0, 0, 0); }
#endif

Perceba a elegância: seu loop() nunca toca em registrador, PWM ou Wire diretamente — chama verbos de intenção (forward, backwards, left, right, stop) com velocidade, e a biblioteca converte em bytes I2C. É abstração de hardware na prática, o mesmo padrão de drivers profissionais.

Código Principal Car_Motor.ino Comentado

// ============================================================
// RB2686 - PROJETO 3 (LICAO 4): COREOGRAFIA BASICA DE MOVIMENTO
// Arquivo: Car_Motor.ino + SetMotor.h na mesma pasta
// Sequência: frente 2 s -> ré 2 s -> esquerda 2 s -> direita
// 2 s -> parada 2 s, repetindo para sempre
// ============================================================

#include "SetMotor.h"  // Importa i2c_init + Car_forward/backwards/
// left/right/stop. As aspas (não <>) indicam arquivo local,
// na mesma pasta do .ino — mantenha os dois juntos.

void setup() {
  i2c_init();  // Inicializa o I2C como mestre em SDA=16, SCL=13.
               // Obrigatório uma vez antes de qualquer comando
               // de motor. Sem isso, o escravo nunca é endereçado.
}

void loop() {
  Car_forward(100);  // Ambos os motores para frente a PWM 100.
                     // 100 é moderado: anda com segurança na mesa
                     // sem arrancada violenta. Abaixo de ~30 o
                     // motor pode nem partir por torque insuficiente.
  delay(2000);       // Mantém o comando por 2000 ms (2 segundos).

  Car_backwards(100);  // Ambos para trás: ré em linha reta.
  delay(2000);         // 2 segundos de ré.

  Car_left(100);   // Diferencial para girar à esquerda no eixo:
                   // um motor para frente, outro para trás.
  delay(2000);     // 2 segundos girando.

  Car_right(100);  // Espelha a esquerda: gira à direita no eixo.
  delay(2000);     // 2 segundos girando.

  Car_stop();    // Manda 0,0,0: corta PWM dos dois motores.
  delay(2000);   // 2 segundos parado para respirar e observar.
  // O loop recomeça na frente: coreografia contínua para teste.
}

Instruções de Teste e Validação em Segurança

  1. Primeiro teste com rodas livres (obrigatório): com a chave OFF e sem USB, eleve o robô sobre caixa baixa de modo que as duas rodas girem no ar e a roda boba fique suspensa. Grave o programa com o USB, mantenha o USB conectado para observar, e só então ligue a chave para ON. Você deve ver e ouvir: ambas as rodas para frente 2 s, ambas para trás 2 s, girando opostas 2 s para cada lado, paradas 2 s. Se alguma roda não girar no ar, desligue e revise carga das pilhas e encaixe do eixo D antes de ir para o chão.
  2. Segundo teste no chão: desconecte o USB, coloque o robô em área livre de 2x2 m, ligue e afaste as mãos. A sequência deve desenhar: avanço reto, recuo reto, giro no eixo para esquerda, giro para direita, pausa. Filmando de cima com o celular fica fácil comparar os tempos com os delay(2000).
  3. Teste de velocidade mínima: troque todos os 100 por 30, grave e observe no ar: as rodas mal partem ou tremem — prova do torque mínimo. Volte para 100 para os próximos módulos. Valores acima de 150 só em área ampla e com pilhas cheias.
  4. Teste de simetria: se o “reto” sai curvo, anote qual lado atrasa. Pode ser roda mal encaixada, atrito na roda boba sem espaçador ou pilha fraca — não é erro de código, pois o comando é idêntico para os dois motores.

⛔ Perigo: nunca teste a coreografia pela primeira vez na borda da mesa ou com o robô apontado para escada, animais ou pés descalços. Motores N20 com redução têm torque suficiente para derrubar o robô da bancada e danificar a câmera. Área de teste isolada não é exagero — é procedimento.

💡 Dica: se os motores vibram mas não giram, ou o ESP32 reseta ao partir, meça as 18650: soma abaixo de 7 V em carga é pilha fraca. Recarregue em carregador externo e repita. Queda de tensão na partida (brownout) é o sintoma clássico de “código que funcionava e parou” quando na verdade a bateria esvaziou.


Módulo 4 — Redes Sem Fio WiFi: Escanear, Conectar e Criar o Próprio Hotspot

Até aqui o robô obedecia a coreografias gravadas: ele andava sozinho, sem ouvir ninguém. A partir deste módulo ele ganha ouvidos de rádio. A ESP32-CAM tem WiFi de 2,4 GHz integrado — o mesmo que liga seu celular ao roteador de casa — e vamos dominar os três usos fundamentais: farejar redes ao redor (scan), entrar numa rede existente como cliente (modo STA) e criar a própria rede para o celular se conectar (modo AP). Os dois projetos finais do curso (navegador e aplicativo) são construídos sobre o modo AP, então cada linha desta lição será reutilizada adiante.

Teoria Essencial de Redes para Iniciantes

O que é WiFi: família de redes locais sem fio (WLAN — Wireless Local Area Network) no padrão IEEE 802.11, apelidada de Wireless Fidelity. Seu celular, notebook e agora o robô falam esse idioma para trocar pacotes de dados pelo ar, sem cabo, através de ondas de rádio.

Faixas de frequência — detalhe que reprova iniciantes: o WiFi doméstico usa 2,4 GHz (alcance maior, velocidade menor, mais interferência de micro-ondas e Bluetooth) e 5 GHz (velocidade maior, alcance menor, menos interferência). A ESP32-CAM deste kit só entende 2,4 GHz. Na prática: se sua casa tem rede MinhaCasa e MinhaCasa_5G, o robô só enxerga e conecta na primeira. Roteadores com banda única de 5 GHz ou com band steering agressivo precisam ter o 2,4 GHz habilitado com SSID visível para os testes.

Os dois modos de operação:

  • STA (Station — estação/cliente): o robô é o aluno que entra na sala existente. Ele pede licença ao roteador da sua casa com nome (SSID) e senha, recebe um número de chamada (IP) e passa a conversar na rede local. É o modo dos experimentos de conexão e de futuros projetos IoT com internet.
  • AP (Access Point — ponto de acesso): o robô vira o professor e abre a própria sala. Ele cria um hotspot (neste curso, ESP32 ou ESP32-Car com senha 12345678), o celular se conecta nele e os dois conversam direto, sem roteador e sem internet. É o modo dos carros com vídeo — funciona no quintal, na escola sem WiFi e na feira de ciências.

Endereço IP — o número da casa na rua: todo dispositivo na mesma rede precisa de um IPv4 único de 4 blocos (ex.: 192.168.4.1). Os 3 primeiros blocos identificam a rua (a rede), o último identifica a casa (o dispositivo). No modo AP deste kit, o robô é sempre 192.168.4.1 — decore, pois você digitará no navegador nas próximas lições. No modo STA, quem distribui o número é o roteador via DHCP, e o Monitor Serial mostra qual foi sorteado.

Lógica de decisão no código — if e switch: os programas WiFi tomam decisões o tempo todo (se achou rede, se conectou, se caiu). O if simples executa um bloco só quando a condição é verdadeira; o if...else escolhe entre dois caminhos; o encadeado if...else if...else testa várias condições em ordem. O switch escolhe entre muitos valores de uma mesma expressão (ideal para eventos WiFi numerados), com case para cada valor, break para não escorregar para o próximo caso e default para o resto. Esquecer o break é o erro clássico que executa dois casos sem querer.

Intensidade do sinal (RSSI): medida em dBm, sempre negativa: perto de -30 é excelente, -60 é bom, -80 é fraco, abaixo de -90 é quase inaudível. O scanner mostra o RSSI de cada rede para você posicionar o robô e o roteador.

Experimento 1: Escaneamento de Redes WiFi ao Redor

Visão Geral

O robô vira um radar: lista todas as redes 2,4 GHz audíveis com nome (SSID) e força (RSSI) no Monitor Serial. É o teste de sanidade do rádio — se o scan lista vizinhos, o hardware e a antena estão sadios e o problema de um projeto futuro será senha ou modo, não rádio queimado.

ComponenteQuantidadeObservação
Robô RB2686 + USB de dados + IDE 2.0.121Chave pode ficar em OFF no teste de bancada USB
Roteador 2,4 GHz por perto + celulares com hotspot—Quanto mais redes, mais bonita a lista

Código 5_1Wifi_Scanning.ino Comentado Linha a Linha

Arquivo original em 4_Code\lesson 5 WIFI\5_1Wifi_Scanning:

// ============================================================
// RB2686 - EXPERIMENTO 1: SCANNER DE REDES WIFI (MODO STA)
// Mostra SSID + RSSI de cada rede 2,4 GHz no Monitor Serial
// ============================================================

#include <WiFi.h>  // Biblioteca oficial de WiFi do núcleo ESP32.
// Traz WiFi.mode, disconnect, scanNetworks, SSID, RSSI.

void setup() {
  // Abre a serial USB com o PC a 115200 bps. O valor deve ser
  // idêntico ao selecionado na janela do Monitor Serial,
  // senão aparecem caracteres corrompidos.
  Serial.begin(115200);

  // Coloca o rádio em modo estação (cliente). Mesmo só para
  // escanear, o ESP32 precisa estar em STA.
  WiFi.mode(WIFI_STA);

  // Desconecta de qualquer rede anterior gravada na Flash.
  // Garante scan limpo, sem resto de conexão antiga.
  WiFi.disconnect();

  // Pausa de 100 ms para o rádio assentar após a troca de modo.
  delay(100);

  Serial.println("Scanning WiFi networks...");  // Avisa o início.

  // Dispara o escaneamento e guarda quantas redes foram ouvidas.
  // Esta chamada bloqueia por ~2-3 segundos varrendo os canais.
  int networkCount = WiFi.scanNetworks();

  // Decisão simples: se zero, informa; senão, lista uma a uma.
  if (networkCount == 0) {
    Serial.println("No networks found");  // Nenhuma rede 2,4 GHz audível.
  } else {
    // Mostra o total encontrado antes da lista detalhada.
    Serial.print(networkCount);
    Serial.println(" networks found:");

    // Laço de 0 até networkCount-1: para cada índice, imprime
    // nome e força. Índice começa em zero por convenção C++.
    for (int i = 0; i < networkCount; ++i) {
      Serial.print("WiFi name: ");    // Rótulo amigável.
      Serial.println(WiFi.SSID(i));   // Nome da i-ésima rede.

      // RSSI varia tipicamente de -100 (fraco) a -30 (forte).
      // Quanto menos negativo, mais forte o sinal.
      Serial.print("WiFi strength: ");
      Serial.println(WiFi.RSSI(i));   // Força em dBm.
      Serial.println("-----------------------");  // Separador visual.
    }
  }
}

void loop() {
  // Nada para repetir: o scan roda uma vez no setup. O loop
  // vazio mantém o programa vivo sem gastar processamento.
}

Teste e Validação do Scanner

  1. Grave com o ritual padrão (ESP32 Dev Module + porta + Carregar).
  2. Abra Ferramentas → Monitor Serial, selecione 115200 baud no canto inferior direito e Sem fim de linha. Pressione o botão RST da ESP32-CAM ou reconecte o USB para reiniciar e ver a mensagem Scanning WiFi networks... seguida da lista.
  3. Confira que sua rede 2,4 GHz aparece com RSSI entre -30 e -75 se o roteador está no mesmo cômodo. Redes _5G não devem aparecer — se aparecerem, desconfie que são de banda dupla com sufixo enganoso.
  4. Posicione o robô a 1 m e a 10 m com parede no meio e compare o RSSI da mesma rede: a queda de 15–25 dB é a física do ambiente, não defeito.

💡 Dica: se a lista vem sempre vazia, teste com um hotspot 2,4 GHz do celular ao lado do robô (nome curto, sem caracteres especiais). Se nem o hotspot aparece, revise núcleo 2.0.12 e antena (a trilha PCB perto da câmera não pode estar coberta com fita metálica ou dedo durante o teste).

Experimento 2: Conexão a Uma Rede Existente (Modo STA)

Visão Geral

Agora o robô entra na sua rede como qualquer celular: você informa SSID e senha no código, ele autentica, recebe IP e mantém a conexão com reconexão automática se cair. O Monitor Serial narra cada evento (iniciou, conectou, ganhou IP, desconectou) através de uma função de callback registrada com WiFi.onEvent.

ItemValor no ExemploO Que Trocar
SSID da sua rede 2,4 GHzESP32 no exemploPelo nome exato da sua rede, respeitando maiúsculas e espaços
Senha12345678 no exemploPela sua senha real, mínimo 8 caracteres
Taxa serial115200Igual na janela do monitor

Código 5_2Wifi_connect.ino Comentado

// ============================================================
// RB2686 - EXPERIMENTO 2: CONEXAO WIFI EM MODO STA COM EVENTOS
// Conecta no SSID/senha informados e imprime o IP obtido.
// Inclui proteção anti-brownout e reconexão automática.
// ============================================================

#include <WiFi.h>           // Base do WiFi ESP32.
#include "soc/soc.h"        // Acesso a registradores do SoC.
#include "soc/rtc_cntl_reg.h"  // Registrador do detector brownout.

// ---- TROQUE AQUI pelos dados da SUA rede 2,4 GHz ----
const char* ssid = "ESP32";       // Nome exato da rede (case-sensitive).
const char* password = "12345678";  // Senha com 8+ caracteres.

// Função chamada automaticamente a cada mudança de estado WiFi.
// event diz qual evento; info traz detalhes (não usados em todos).
void WiFiEventCallback(arduino_event_id_t event, arduino_event_info_t info) {
  // O switch escolhe a mensagem conforme o código do evento.
  switch (event) {
    case WIFI_EVENT_STA_START:  // Rádio STA inicializado com sucesso.
      Serial.println("WiFi STA started");
      break;  // Sem break, escorregaria para o próximo case.
    case ARDUINO_EVENT_WIFI_STA_CONNECTED:  // Autenticou no roteador.
      Serial.println("Connected to AP");
      break;
    case ARDUINO_EVENT_WIFI_STA_GOT_IP:  // DHCP entregou o IP local.
      Serial.print("Got IP: ");
      Serial.println(WiFi.localIP());  // Ex.: 192.168.1.105.
      break;
    case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:  // Perdeu a conexão.
      Serial.println("Disconnected from AP");
      WiFi.reconnect();  // Tenta reconectar sozinho, sem reset.
      break;
    default:  // Qualquer outro evento não tratado explicitamente.
      break;
  }
}

void setup() {
  // Desliga o detector de brownout que resetaria o chip em quedas
  // rápidas de tensão durante picos do WiFi + câmera. Essencial
  // neste kit alimentado por pilhas e USB compartilhada.
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);

  Serial.begin(115200);  // Serial para acompanhar os eventos.
  WiFi.onEvent(WiFiEventCallback);  // Registra o narrador de eventos.
  WiFi.begin(ssid, password);  // Inicia a tentativa de conexão.
}

void loop() {
  // Todo o trabalho é por eventos: o loop fica livre para futuras
  // tarefas sem travar a reconexão automática.
}

Teste e Validação da Conexão STA

  1. Edite ssid e password com seus dados, grave e abra o Monitor Serial a 115200. Sequência esperada: WiFi STA started → Connected to AP → Got IP: 192.168.x.y.
  2. Digite o IP mostrado no navegador de um celular na mesma rede: nesta lição ainda não há página (ela vem na Lição 6), então esperamos apenas timeout — o teste aqui é o IP impresso, não a página.
  3. Teste de resiliência: desligue o roteador por 10 s e religue. O monitor deve mostrar Disconnected from AP seguido de nova conexão e novo Got IP sem você resetar o robô — prova da reconexão.
  4. Se travar em WiFi STA started sem conectar: confira SSID/senha caractere por caractere, confirme que a rede é 2,4 GHz e aproxime o robô a 2 m do roteador para eliminar sinal fraco da equação.

⚠️ Atenção: nunca publique seu SSID e senha reais em fotos do código, vídeos ou repositórios públicos. Antes de compartilhar prints do sketch, volte os campos para valores fictícios. Vazamento de credencial WiFi é falha de segurança, não detalhe.

Experimento 3: Robô Criando o Próprio Hotspot (Modo AP)

Visão Geral

O modo que sustentará o carro com vídeo: o robô abre a rede ESP32 (senha 12345678, canal 5), o celular conecta nela e o Monitor Serial registra cada entrada e saída pelo endereço MAC (identidade física da placa de rede) e o total de clientes. É rede sem internet propositalmente — o celular avisará “sem internet, manter conectado?” e você deve manter, pois o destino é o robô, não a nuvem.

Parâmetro AP no ExemploValorObservação
SSID do hotspotESP32Nome que aparece na lista do celular
Senha12345678Mínimo 8 caracteres exigido pelo WPA2
Canal5Fixar canal evita varredura e estabiliza
Potência TX19,5 dBmMáxima prática para alcance em campo aberto

Código 5_3Wifi_AP.ino Comentado (trechos-chave)

O arquivo completo está em 4_Code\lesson 5 WIFI\5_3Wifi_AP. Abaixo os blocos que merecem leitura atenta, com lógica 100% preservada:

#include <WiFi.h>      // Base do WiFi.
#include <esp_wifi.h>  // Necessário para esp_wifi_ap_get_sta_list,
                       // que lista os clientes conectados no AP.
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"

// ---- CONFIG DO HOTSPOT CRIADO PELO ROBO ----
const char *ssid = "ESP32";       // Nome visível na lista WiFi.
const char *password = "12345678";  // Senha WPA2 (8+ caracteres).

// Converte 6 bytes de MAC em texto legível AA:BB:CC:DD:EE:FF.
// snprintf formata com dois dígitos hex por byte, completando
// com zero à esquerda (%02X) e separando por dois-pontos.
String macToString(const uint8_t* mac) {
  char buf[18];  // 17 caracteres + terminador nulo.
  snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X",
           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  return String(buf);
}

// Pergunta ao driver quantos e quais clientes estão associados
// agora e imprime no monitor. Útil para saber se o celular
// realmente grudou no hotspot do robô.
void listConnectedDevices() {
  wifi_sta_list_t wifi_sta_list;  // Estrutura que recebe a lista.
  // Preenche a estrutura; retorna ESP_OK se deu certo.
  esp_err_t result = esp_wifi_ap_get_sta_list(&wifi_sta_list);
  if (result == ESP_OK) {
    Serial.printf("Number of connected devices: %d\n",
                  wifi_sta_list.num);  // Total associado.
    for (int i = 0; i < wifi_sta_list.num; i++) {
      wifi_sta_info_t station = wifi_sta_list.sta[i];  // i-ésimo cliente.
      Serial.printf("Device %d MAC: %s\n", i + 1,
                    macToString(station.mac).c_str());  // MAC em texto.
    }
  } else {
    Serial.println("Failed to get client list");  // Falha de leitura.
  }
  Serial.println("-------------------");
}

// Narrador de eventos do modo AP: novos connects e disconnects.
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
  switch (event) {
    case ARDUINO_EVENT_WIFI_AP_STACONNECTED:  // Alguém entrou.
      Serial.printf("New device connected, total connected: %d\n",
                    WiFi.softAPgetStationNum());  // Total atual.
      Serial.print("Device MAC: ");
      // MAC de quem acabou de entrar, vindo no próprio evento.
      Serial.println(macToString(info.wifi_ap_staconnected.mac));
      listConnectedDevices();  // Mostra a lista completa atualizada.
      break;
    case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED:  // Alguém saiu.
      Serial.printf("Device disconnected, remaining connected: %d\n",
                    WiFi.softAPgetStationNum());
      listConnectedDevices();
      break;
    default:
      break;
  }
}

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);  // Anti-reset em picos.
  Serial.begin(115200);  // Monitor para ver entradas e saídas.
  WiFi.setTxPower(WIFI_POWER_19_5dBm);  // Potência máxima prática.
  WiFi.mode(WIFI_MODE_AP);  // Rádio como ponto de acesso.
  // Cria o hotspot: nome, senha e canal 5 fixo.
  WiFi.softAP(ssid, password, 5);
  WiFi.onEvent(WiFiEvent);  // Registra o narrador de eventos AP.
}

void loop() {
  // Eventos fazem todo o trabalho; loop livre para o futuro.
}

Teste e Validação do Hotspot

  1. Grave, abra o Monitor Serial a 115200 e aguarde o silêncio inicial (AP não imprime IP próprio neste exemplo — ele só narra eventos).
  2. No celular, abra a lista WiFi e conecte em ESP32 com senha 12345678. Aceite “manter conectado sem internet” quando o sistema perguntar.
  3. No monitor deve aparecer New device connected, total connected: 1 + MAC + lista. Desligue o WiFi do celular: aparece Device disconnected, remaining connected: 0. Essa dança confirma AP funcional nas duas direções.
  4. Conecte um segundo celular: o total vai a 2 com dois MACs distintos — prova de múltiplos clientes, usada nas demonstrações em sala.

💡 Dica: se o hotspot ESP32 nem aparece na lista, confira se você gravou o sketch AP mesmo (e não o STA anterior), aproxime a menos de 3 m sem parede metálica no meio e desligue VPN ou “WiFi inteligente” do celular que pula sozinho para redes com internet. Em iPhones, desative temporariamente a troca automática de rede fraca.

Tabela de Funções WiFi Usadas no Módulo

FunçãoPapelRetorno / Parâmetro Típico
WiFi.mode(WIFI_STA / WIFI_MODE_AP)Define o modo do rádioSem retorno; chame antes de scan, begin ou softAP
WiFi.disconnect()Sai da rede atualLimpa conexão anterior antes de novo teste
WiFi.scanNetworks()Varrer redes 2,4 GHzNúmero de redes encontradas
WiFi.SSID(i) / WiFi.RSSI(i)Nome e força da i-ésima redeTexto do SSID; inteiro dBm (-100 a -30)
WiFi.begin(ssid, password)Entrar numa rede (STA)Inicia conexão assíncrona com eventos
WiFi.onEvent(callback)Registrar narrador de eventosChamado em connect, IP, disconnect
WiFi.softAP(ssid, password, canal)Criar hotspot (AP)Sobe a rede própria no canal indicado
WiFi.softAPgetStationNum()Total de clientes no APInteiro com associados atuais
WiFi.localIP()IP do robô na redeEx.: 192.168.4.1 no AP, DHCP no STA
esp_wifi_ap_get_sta_list(&lista)Lista detalhada de MACs no APESP_OK + estrutura com num e sta[]

Com o rádio validado nos três modos e o Monitor Serial a 115200 dominado, o próximo passo natural é pendurar um servidor Web nesse rádio e mandar o robô obedecer a botões no navegador — exatamente o Projeto 4 da Parte 4.


Módulo 5 — Servidor Web Embarcado e Teleoperação sem Câmera (Lição 6)

Até a Lição 5 o robô falava com o Monitor Serial pelo cabo. Agora ele vai falar com o navegador pelo ar. Nesta lição construímos um WebServer leve dentro da própria ESP32-CAM: o robô cria o hotspot, escuta na porta 80 e entrega uma página de controle com botões e slider de velocidade. É o ensaio geral antes do vídeo — toda a mecânica de rotas HTTP, parâmetros e comandos de motor será reaproveitada na Lição 7 com câmera ligada.

Teoria: Cliente, Servidor, TCP e HTTP em Linguagem Simples

WebServer embarcado: programa de serviço que recebe pedidos do navegador e devolve páginas ou confirmações. Quando você digita http://192.168.4.1 no celular, está pedindo recursos ao servidor que mora no robô — sem internet, sem nuvem, só os dois conversando no hotspot.

A conversa em 5 atos: 1) o celular abre conexão TCP (Transmission Control Protocol — protocolo confiável com aperto de mão de 3 vias que garante ordem e retransmite perdas); 2) o celular envia pedido HTTP (ex.: GET /control?cmd=car&direction=Forward); 3) o servidor interpreta (lê cmd e direction); 4) executa (chama Car_forward) e responde (OK em texto puro ou a página HTML); 5) encerra ou mantém a conexão para o próximo toque. O TCP garante que o comando de parar chegue íntegro — detalhe de segurança quando o robô anda em direção à parede.

A página (HTML + CSS + JavaScript): o arquivo html.h guarda a interface como texto dentro do firmware. O HTML monta os botões, o CSS os deixa roxos e arredondados e o JavaScript usa fetch() para mandar cada toque como requisição sem recarregar a página — por isso dá para segurar o botão e o carro obedece em tempo real.

Projeto 4: Carrinho com Controle Remoto via Navegador

ComponenteQuantidadeObservação
Robô RB2686 com WiFi AP validado1Pilhas carregadas; área de teste livre de 2x2 m
Celular ou notebook com WiFi1Para conectar no hotspot e abrir o navegador
IDE com pacote 2.0.121Mesmo ambiente das lições anteriores
Rota HTTPParâmetrosEfeito no Firmware
GET /—Devolve a página html com botões e slider
GET /control?cmd=car&direction=Forwarddirection: Forward, Backward, Left, Right, StopChama a função de motor correspondente com Car_Speed atual
GET /control?cmd=Resolution&angle=NNangle: 0–255 como textoConverte para inteiro e atualiza Car_Speed

Código Remote_Control_Car.ino Comentado

Arquivo em 4_Code\lesson 6 Remote Control Car\Remote_Control_Car:

// ============================================================
// RB2686 - PROJETO 4 (LICAO 6): TELEOPERACAO WEB SEM CAMERA
// AP ESP32-Car / 12345678 | Página em http://192.168.4.1/
// Rotas: / (página) e /control (comandos de motor e velocidade)
// ============================================================

#include <WiFi.h>       // Hotspot AP do robô.
#include <WebServer.h>  // Servidor HTTP leve na porta 80.
#include "html.h"       // Página com botões e slider (texto).
#include "SetMotor.h"   // Motores via I2C (módulo anterior).

WebServer webServer(80);  // Cria o servidor escutando na porta
                          // 80, padrão do HTTP sem indicar porta.
uint32_t Car_Speed = 100; // Velocidade inicial moderada e segura.

void setup() {
  Serial.begin(115200);  // Monitor para ver comandos recebidos.
  i2c_init();            // I2C dos motores (SDA 16, SCL 13).

  // Sobe o hotspot que o celular vai procurar na lista WiFi.
  WiFi.softAP("ESP32-Car", "12345678");
  Serial.println("AP Started. Connect to: ESP32-Car");

  // Rota raiz: quando o navegador pede /, devolve a página HTML
  // com status 200 (OK) e tipo text/html para renderizar botões.
  webServer.on("/", []() {
    webServer.send(200, "text/html", html);
  });

  // Rota de comando: interpreta cmd + direction/angle e executa.
  webServer.on("/control", []() {
    // Lê o parâmetro cmd (?cmd=car ou ?cmd=Resolution).
    String cmd = webServer.arg("cmd");

    if (cmd == "car") {  // Comando de movimento dos botões.
      // Lê a direção pedida pelo botão pressionado.
      String dir = webServer.arg("direction");
      if (dir == "Forward") Car_forward(Car_Speed);
      else if (dir == "Backward") Car_backwards(Car_Speed);
      else if (dir == "Left") Car_left(Car_Speed);
      else if (dir == "Right") Car_right(Car_Speed);
      else if (dir == "Stop") Car_stop();
    }

    if (cmd == "Resolution") {  // Nome herdado do exemplo; aqui
      // significa velocidade: lê o valor do slider como texto.
      String val = webServer.arg("angle");
      Car_Speed = val.toInt();  // Converte "95" em número 95.
      Serial.printf("Car Speed Set: %d\n", Car_Speed);  // Confirma.
    }

    // Responde OK em texto puro para o fetch não travar esperando.
    webServer.send(200, "text/plain", "OK");
  });

  webServer.begin();  // Liga o servidor e começa a escutar clientes.
}

void loop() {
  // Atende um pedido HTTP por vez, sem bloquear os motores.
  // Sem esta chamada contínua, o navegador conectaria e nada
  // aconteceria — é o coração do servidor.
  webServer.handleClient();
}

O html.h completa o circuito: cada botão dispara fetch(/control?cmd=car&direction=${dir}) e o slider dispara fetch(/control?cmd=Resolution&angle=${valor}) mostrando o número ao vivo. O servidor lê com webServer.arg("cmd"), webServer.arg("direction") e webServer.arg("angle") — três leituras que decidem tudo.

Teste e Validação da Teleoperação Web

Diagrama de envio de comandos do navegador para o servidor do robô Interface ESP32 Car Control no celular em 192.168.4.1 com botões e slider de velocidade
  1. Grave, abra o Monitor Serial a 115200 e aguarde AP Started. Connect to: ESP32-Car.
  2. No celular, conecte no WiFi ESP32-Car com senha 12345678 e mantenha mesmo sem internet. Abra o navegador em http://192.168.4.1 (sem :81 nesta lição — a porta 80 é implícita).
  3. Segure Forward: o robô anda enquanto pressionado; solte e toque Stop — ele deve parar em menos de 1 s na mesma rede. Teste Backward, Left e Right com espaço livre.
  4. Arraste o slider para 95 e avance; depois para 40 e avance de novo: a diferença de velocidade deve ser nítida. Abaixo de ~30 ele pode vibrar sem sair do lugar — é o limite físico documentado, não bug.
  5. Observe o Monitor Serial a cada comando: as linhas de velocidade confirmam que os fetch estão chegando.
Botões de direção da interface Web com segurar para mover e soltar para parar Slider de velocidade da interface com valor exibido em tempo real

⚠️ Atenção: se a página não carrega, confira nesta ordem: hotspot conectado mesmo (ícone WiFi com ESP32-Car), URL sem s (http, não https), sem :81 nesta lição, e VPN do celular desligada. Página em branco com OK ao acessar /control manualmente indica servidor vivo e problema só no html.h — regrave os dois arquivos juntos.

💡 Dica: em demonstrações, fixe Car_Speed inicial em 60–80 no código antes de entregar o celular a uma criança. Velocidade menor dá tempo de reação e evita colisões com móveis enquanto ela aprende os botões.


Módulo 6 — Carro com Visão e Vídeo ao Vivo no Navegador (Lição 7)

Agora juntamos tudo: o hotspot e o WebServer da Lição 6, os motores via I2C da Lição 4, os faróis com PWM das Lições 2–3 e, pela primeira vez, a câmera OV2640 transmitindo JPEG contínuo (MJPEG) para o navegador. O resultado é o projeto-símbolo do kit: ver pelos olhos do robô enquanto dirige com os polegares.

Arquitetura do Firmware de Vídeo

  • Servidor de câmera (porta 80 padrão do stream): inicializado por CameraWebServer_init() em CameraWebServer.cpp + app_httpd.cpp + camera_index.h, entrega o fluxo MJPEG e a página com o player.
  • Servidor de controle (porta 81): o WebServer webServer(81) das rotas / e /control de movimento, qualidade, velocidade e faróis — por isso o endereço desta lição tem :81 no final.
  • Motores e faróis: mesmos SetMotor.h (I2C) e LED no GPIO12, agora com brilho via ledc (PWM por hardware do ESP32) em vez de liga/desliga.
  • Segurança: se nenhum celular estiver associado ao AP, o loop() chama Car_stop() continuamente — o robô parado sem dono não sai andando sozinho.
Comando /controlParâmetroEfeito
cmd=cardirection: Forward, Backward, Left, Right, stopMove/para com Car_Speed atual; espelha bytes para Serial2 de telemetria
cmd=Qualityangle: 1 (QQVGA leve), 2 (VGA médio), 3 (XGA pesado)Troca framesize do sensor via s->set_framesize
cmd=Resolutionangle: número 0–255Atualiza Car_Speed (nome herdado, função velocidade)
cmd=Lightsangle: 0–255Ajusta brilho do farol com ledcWrite(0, valor) no GPIO12

Código Video_Car_Web.ino Comentado (essência)

Arquivo em 4_Code\lesson 7 Video Smart Car - Web\Video_Car_Web (trechos com lógica preservada e comentários expandidos):

// Inclusões: WiFi + câmera + servidor + página + motores.
#include <WiFi.h>
#include "esp_camera.h"  // Driver OV2640: init, framesize, flip.
#include <WebServer.h>
#include "html.h"        // Página com player + botões + sliders.
#include <vector>        // Vetor de bytes para telemetria Serial2.
#include "SetMotor.h"

WiFiServer server(100);   // Canal TCP 100 p/ telemetria do exemplo.
WebServer webServer(81);  // Controle em http://192.168.4.1:81/
#define LED 12            // Faróis (agora com brilho PWM).
void CameraWebServer_init();  // Sobe o stream da câmera.
uint32_t Car_Speed = 40;  // Velocidade inicial prudente com vídeo.

void setup() {
  Serial.begin(115200);  // Debug dos comandos recebidos.
  Serial2.begin(115200, SERIAL_8N1, 14, 13);  // Telemetria auxiliar.
  i2c_init();              // Motores via I2C (mestre ESP32).
  CameraWebServer_init();  // Câmera + stream MJPEG no ar.
  server.begin();          // Abre o TCP 100.
  delay(100);

  // PWM por hardware do farol: canal 0, 3 kHz, 8 bits (0-255).
  ledcSetup(0, 3000, 8);
  ledcAttachPin(LED, 0);  // Liga o GPIO12 ao canal 0.
  ledcWrite(0, 25);       // Brilho inicial suave (não ofusca).

  // Página principal com player e controles.
  webServer.on("/", []() {
    webServer.send(200, "text/html", html);
  });

  // Central de comandos: carro + qualidade + velocidade + farol.
  webServer.on("/control", []() {
    String cmd = webServer.arg("cmd");
    Serial.println(cmd);  // Eco no monitor para depurar.
    std::vector<uint8_t> data;  // Pacote de telemetria Serial2.

    if (cmd == "car") {
      String direction = webServer.arg("direction");
      // Cabeçalho do protocolo de telemetria do exemplo original.
      data = { 0xFF, 0x55, 0x0A, 0x00, 0x00, 0x00,
               0x00, 0x00, 0x00, 0x01, 0x0C, 0x00 };
      if (direction == "Forward")  { Car_forward(Car_Speed);  data.push_back(0x01); }
      if (direction == "Backward") { Car_backwards(Car_Speed); data.push_back(0x02); }
      if (direction == "Left")     { Car_left(Car_Speed);     data.push_back(0x03); }
      if (direction == "Right")    { Car_right(Car_Speed);    data.push_back(0x04); }
      if (direction == "stop")     { Car_stop();              data.push_back(0x00); }
    }

    if (cmd == "Quality") {  // Troca a resolução do vídeo ao vivo.
      uint32_t angleValue = webServer.arg("angle").toInt();
      sensor_t *s = esp_camera_sensor_get();  // Sensor ativo.
      if (angleValue == 1) s->set_framesize(s, FRAMESIZE_QQVGA);
      if (angleValue == 2) s->set_framesize(s, FRAMESIZE_VGA);
      if (angleValue == 3) s->set_framesize(s, FRAMESIZE_XGA);
      // Se a imagem sair de ponta-cabeça, ajuste vflip; se
      // espelhada, hmirror (detalhe abaixo em Dicas).
    }

    if (cmd == "Resolution") {  // Velocidade do carro (nome herdado).
      Car_Speed = webServer.arg("angle").toInt();
      Serial.println(Car_Speed);
    }

    if (cmd == "Lights") {  // Brilho do farol 0-255 via PWM.
      uint32_t angleValue = webServer.arg("angle").toInt();
      ledcWrite(0, angleValue);  // Duty no canal 0 do GPIO12.
      Serial.println(angleValue);
    }

    uint8_t *buffer = &data[0];  // Envia telemetria via Serial2.
    Serial2.write(buffer, data.size());
    webServer.send(200, "text/plain", "ok");  // Confirma ao fetch.
  });

  webServer.begin();  // Escuta clientes do controle + vídeo.
}

void loop() {
  // Conta clientes no AP: com gente conectada, atende HTTP;
  // sem ninguém, garante parada por segurança.
  uint8_t numStations = WiFi.softAPgetStationNum();
  if (numStations)
    webServer.handleClient();
  else
    Car_stop();
}

Para trocar nome e senha do hotspot, altere os valores de ssid e password onde o AP é criado (na função de câmera/rede do exemplo) e regrave — o novo nome aparece na lista do celular. Para corrigir imagem de ponta-cabeça, inverta s->set_vflip(s, 1) para 0 (e hmirror de 0 para 1 se espelhada), conforme documentado nos comentários do exemplo.

Teste e Validação do Vision Web

Interface Vision Web em 192.168.4.1:81 com vídeo ao vivo, Start Screen e sliders de Lights, Quality e Car Speed
  1. Grave o projeto Web, conecte o celular no hotspot (mesmo SSID/senha da Lição 6 ou os definidos no código Web) e abra http://192.168.4.1:81 — os dois-pontos com 81 são obrigatórios aqui.
  2. Toque Start Screen: o vídeo ao vivo aparece no retângulo superior. Aponte o robô para uma cena clara a 1–2 m: texto grande deve ser legível em VGA.
  3. Segure Forward olhando o vídeo: o corredor anda na tela junto com as rodas — é a telepresença funcionando. Teste os sliders: Lights muda o brilho do farol na hora, Quality troca nitidez/fluidez, Car_Speed muda a arrancada.
  4. Feche o navegador e desconecte o WiFi: em segundos o robô para sozinho (proteção sem cliente). Reconecte e retome sem precisar regravar.
Ajustes de qualidade de imagem e velocidade do carro na interface Vision Web Correção de orientação da imagem com vflip e hmirror no código da câmera

💡 Dica: vídeo travando em XGA com sinal fraco é normal: o quadro grande entope o WiFi. Baixe para VGA ou QQVGA pelo slider Quality antes de culpar a câmera. Em demonstrações, prefira VGA — equilíbrio entre nitidez e fluidez na maioria dos ambientes.

⚠️ Atenção: a lente OV2640 risca com facilidade e o flat flexível rompe se dobrado. Nunca limpe com camiseta ou papel toalha; use haste seca para óptica. E nunca dirija olhando só o vídeo em área com degraus ou piscina por perto — mantenha um colega como vigia do robô físico enquanto você olha a tela.


Módulo 7 — Carro com Visão e Vídeo no Aplicativo Móvel (Lição 8)

O navegador da Lição 7 já entrega telepresença completa, mas exige digitar IP e usa controles genéricos. O aplicativo oficial Kuongshun encapsula tudo em interface nativa de jogo: joystick analógico de direção, botões de qualidade e marchas, slider de farol e player de vídeo integrado — experiência ideal para feiras, aulas e demonstrações com crianças. Por dentro, o APP fala um protocolo binário próprio sobre TCP na porta 100, enquanto o vídeo continua em HTTP — entender esse protocolo é a aula de engenharia desta lição.

Projeto 5: Instalação, Conexão e Teleoperação pelo APP

ItemAndroidiOS (iPhone/iPad)
Nome do appKuonhShun.apk na pasta 5_Android_Software_Installation_Package da documentaçãokuongshun na App Store
InstalaçãoCopie o APK para o celular (mensageiro, cabo ou gerenciador de arquivos), abra e autorize “instalar de fonte desconhecida” uma vezBusque, toque Obter e instale; o ícone aparece na tela inicial
RedeConecte no hotspot do robô antes de abrir o APPIdem, mantendo sem internet
Modelo no APPVolte à Home, escolha ESP32-CAM Vision Smart Car (AD179)Idem
Busca do aplicativo kuongshun na App Store com ícone oficial Tela inicial do aplicativo com os modelos AD177, AD179 Vision Smart Car e AD118

Passo a Passo de Instalação e Conexão para Iniciantes

  1. Grave o firmware APP: na IDE, abra Video_Car_APP.ino em 4_Code\lesson 8 Video Smart Car - APP\Video_Car_APP (com todos os arquivos da pasta juntos: app_httpd.cpp, CameraWebServer.cpp, camera_index.h, SetMotor.h), selecione ESP32 Dev Module + porta e clique em Carregar. Aguarde Done uploading.
  2. Instale o APP conforme a tabela acima. No Android, se o sistema bloquear, vá em Configurações → Segurança → Permitir esta fonte e repita. Não baixe APK de sites aleatórios — use o da documentação.
  3. Conecte o WiFi primeiro, abra o APP depois: no celular, entre na rede do robô (mesmo SSID/senha dos projetos Web) e mantenha sem internet. Só então abra o Kuongshun.
  4. Configure idioma na primeira abertura, volte à Home e selecione o cartão ESP32-CAM Vision Smart Car (AD179) — não os vizinhos AD177 ou AD118, que são outros kits com protocolo distinto.
  5. Toque o ícone de WiFi/conexão no canto superior direito da tela do modelo. Aguarde a mensagem Connected Successfully: o vídeo ao vivo aparece e o joystick destrava. Se aparecer Connected Fail, confira o WiFi (trocou sozinho para a rede de casa?), reconecte e toque de novo — nunca reinstale o APP antes desse teste simples.
Seleção do idioma e retorno à tela inicial do aplicativo Conexão bem sucedida com vídeo ao vivo e controles destravados no aplicativo

Interface do APP Controle por Controle

Tela de controle do APP com vídeo, joystick direcional, qualidade, marchas e farol
  • Área de vídeo + botão de câmera: mostra o MJPEG da OV2640; o botão de câmera liga/desliga a exibição sem parar o stream (útil para economizar bateria do celular).
  • Qualidade (low/middle/high): troca o framesize (QQVGA/HVGA/XGA conforme o exemplo APP) — low para sinal fraco, high para demonstração perto do roteador/robô.
  • Marchas (1/2/3): velocidades discretas mapeadas para PWM 30/60/100 no firmware — 1 para ambientes apertados, 3 para quadra aberta.
  • Slider de farol: arraste para cima clareia (PWM maior no GPIO12), para baixo escurece — o mesmo ledc da Lição 7, agora com dedo em vez de slider Web.
  • Pad direcional: arraste o disco para a seta desejada e segure para mover; solte para parar. É o controle mais intuitivo para iniciantes.
  • Botão WiFi de status: indica se o socket TCP está vivo; se cair, toque para reconectar sem regravar nada.
Botões de qualidade de imagem low middle high no aplicativo Marchas de velocidade 1 2 3 e slider de brilho do farol no aplicativo
Pad direcional do aplicativo para mover o robô nas setas Botão de status WiFi para reconectar o aplicativo ao robô

Protocolo TCP do APP Desvendado (leitura guiada do firmware)

Diferente do navegador (texto HTTP legível), o APP envia pacotes binários rápidos pelo WiFiServer server(100) com moldura 0xFF 0x55 ... e campos de dispositivo e ação. A função RXpack_func() escuta o TCP com timeout de 3 s, monta o buffer byte a byte, detecta o início pela sequência 0xFF seguido de 0x55, conta o comprimento e chama parseData() quando o pacote completa. Se o silêncio passar do timeout ou o AP ficar sem clientes, chama Car_stop() — a mesma filosofia de segurança das lições Web.

O parseData() lê dois bytes-chave e despacha por switch:

// Lógica preservada do Video_Car_APP.ino (comentários didáticos):
void parseData() {
  int device = readBuffer(10);  // Qual subsistema: 4=câmera, 5=farol,
                                // 13=marcha, 12=movimento.
  int action = readBuffer(12);  // Qual comando dentro do subsistema.
  sensor_t *s = nullptr;
  switch (device) {
    case 4:  // Câmera: troca framesize (qualidade low/middle/high).
      s = esp_camera_sensor_get();
      if (action == 1) s->set_framesize(s, FRAMESIZE_QQVGA);
      else if (action == 2) s->set_framesize(s, FRAMESIZE_HVGA);
      else if (action == 3) s->set_framesize(s, FRAMESIZE_XGA);
      break;
    case 5:  // Farol: action vira duty PWM direto no canal 0.
      ledcWrite(0, action);
      break;
    case 13:  // Marchas: 1->PWM 30, 2->PWM 60, 3->PWM 100.
      if (action == 1) speed = 30;
      else if (action == 2) speed = 60;
      else if (action == 3) speed = 100;
      break;
    case 12:  // Movimento com a marcha atual (speed global):
      switch (action) {
        case 1: Car_forward(speed); break;    // Setas do pad.
        case 2: Car_backwards(speed); break;
        case 3: Car_left(speed); break;
        case 4: Car_right(speed); break;
        case 0: Car_stop(); break;  // Soltou o pad: para.
        default: Serial.println("Unknown action"); break;
      }
      break;
    default:
      Serial.println("Unknown device"); break;
  }
}

O setup() do APP reflete a maturidade do projeto: Serial para debug, Serial2 para a driver, i2c_init() dos motores, CameraWebServer_init() do vídeo, server.begin() do TCP 100 e ledc do farol zerado por segurança. O loop() é minimalista de propósito — RXpack_func() o tempo todo — para latência mínima entre dedo e roda, essencial em teleoperação.

Teste e Validação do Modo APP

  1. Com vídeo aparecendo e marcha 1, arraste o pad para frente por 2 s em área livre: o robô deve partir suave. Solte: para em menos de 1 s. Repita nas 4 setas.
  2. Troque para marcha 3 e repita a frente no mesmo trajeto: a distância percorrida deve ser nitidamente maior — prova das marchas 30/60/100.
  3. Alterne qualidade low → high olhando o vídeo: low flui mesmo longe, high embaça menos de perto mas pode engasgar com parede no meio — escolha conforme o ambiente, como na Lição 7.
  4. Desligue o WiFi do celular por 5 s com o robô em movimento lento e seguro: ele deve parar sozinho (timeout + AP sem cliente). Religar e reconectar retoma sem regravar — a proteção funciona nas duas camadas.

💡 Dica: em sala de aula com vários kits, renomeie o hotspot de cada robô (ESP32-Car-01, -02…) antes da demonstração para os celulares não confundirem redes idênticas. Anote SSID e marcha de cada grupo num quadro — organização vale mais que qualquer ajuste fino de código.

⚠️ Atenção: o APK pede permissões de rede e armazenamento coerentes com streaming e cache de imagem. Negar rede local no iOS ou “dispositivos próximos” no Android impede a descoberta mesmo com WiFi conectado — autorize e tente de novo antes de culpar o firmware.


Guia Diagnóstico de Resolução de Problemas (Troubleshooting)

Tabela de bancada para quando algo não sai como o esperado. Siga na ordem do sintoma, sem pular etapas:

Sintoma ObservadoCausa Mais ProvávelProcedimento de Diagnóstico e Correção
IDE não mostra porta COM do robôCabo de carga (sem dados), driver CH340 ausente ou hub fracoTrocar por cabo de dados testado, instalar USB_Drive_CH341_3_1 (VID 0x1a86 no Mac), ligar direto na USB do PC
Erro de upload Failed to connect / Timed outPlaca ou porta errada, núcleo 3.x ou cabo mexendoSelecionar ESP32 Dev Module + COM certa, reinstalar pacote 2.0.12, imobilizar o robô e regravar
Compila mas câmera dá erro de camera_config_t / ledcSetupNúcleo ESP32 3.0+ instaladoDesinstalar no Gerenciador de Placas e instalar 2.0.12 limpa, fechar e reabrir a IDE
Faróis nunca acendem (nem no pisca)Chave OFF sem pilhas no teste sem USB, LED diferente de 12 ou transistor com solda friaTestar com USB + chave OFF (bancada) e depois pilhas + ON (pista), conferir #define LED 12, inspecionar soldas do S8050
LED sempre no máximo sem respiraranalogWrite em pino errado ou núcleo trocadoConferir GPIO12 e pacote 2.0.12; voltar a +=5 e delay(5) originais
Motores vibram mas não giram / ESP32 reseta ao partirPilhas fracas (soma < 7 V) ou teste só na USBMedir e recarregar as 2x 18650 em carregador externo; nunca tracionar só na USB
Robô anda curvo no comando retoRoda mal encaixada no D, roda boba sem espaçador ou atritoRecolocar rodas na mesma profundidade, confirmar espaçadores M3x6, limpar roda boba
Scanner lista zero redesRádio em local blindado, núcleo errado ou antena obstruídaTestar hotspot 2,4 GHz do celular a 1 m, reinstalar 2.0.12, não cobrir a antena PCB com dedo ou fita metálica
STA não conecta (trava em started)SSID/senha com erro ou rede 5 GHzRedigitar respeitando maiúsculas, confirmar rede 2,4 GHz com SSID visível, aproximar a 2 m
Hotspot ESP32 não aparece no celularSketch STA gravado em vez do AP, VPN ou troca automática ativaRegravar o sketch AP, desligar VPN e troca automática, procurar a menos de 3 m
Página 192.168.4.1 não abre (L6)https em vez de http, :81 indevido ou hotspot erradoUsar http://192.168.4.1 sem porta nesta lição, confirmar ESP32-Car, desligar VPN
Vídeo não inicia em :81 (L7/APP)IP sem :81, outro sketch gravado ou XGA com sinal fracoUsar http://192.168.4.1:81 + Start Screen, regravar o sketch Web/APP, baixar para VGA/QQVGA
Imagem de ponta-cabeça ou espelhadaMontagem da câmera invertidaInverter vflip (1↔0) e hmirror (0↔1) no código e regravar
APP mostra Connected FailWiFi pulou para outra rede ou modelo errado no APPReconectar no hotspot do robô, escolher AD179 Vision Smart Car e tocar o ícone de conexão de novo
Pilha aquece ou incha ao encaixarCurto, polaridade invertida ou célula danificadaRemover com pano seco sem tocar terminais, descartar a célula em ponto de coleta, nunca insistir

Conclusão e Próximos Passos na Engenharia Robótica

Você montou um chassi 2WD com roda boba e câmera nivelada, instalou IDE oficial, driver CH340C e núcleo ESP32 2.0.12, validou porta e upload, piscou faróis com GPIO digital, respirou com PWM, percorreu coreografias com I2C e drivers de potência, escaneou o espectro, entrou em redes e criou a sua, serviu páginas HTTP do próprio robô, transmitiu MJPEG da OV2640 e dirigiu por navegador e aplicativo com segurança anti-fuga. É a pilha completa de um produto IoT com visão: hardware, firmware, redes, backend embarcado e frontend móvel — em miniatura sobre a sua mesa.

Daqui, três trilhas naturais: 1) visão além do streaming — detecção de cores, seguidor de linha por software com a própria câmera e captura para SD; 2) telemetria e autonomia — usar a barra de expansão SVG para pêndulo ultrassônico ou servo pan-tilt e fechar o laço sem dedo humano; 3) engenharia de produto — renomear hotspots, versionar firmwares por lição, medir autonomia das 18650 por missão e documentar cada demonstração com vídeo e IP anotados. Guarde este kit montado e este curso como referência: todo próximo robô com câmera que você tocar repetirá estes mesmos blocos, só que maiores.

Solução de problemas

Olá! Sou o assistente técnico da RoboBuilders. Descreva seu problema com o Kit Robô 2WD ESP32-CAM Vision com Câmera e WiFi RB2686 – Curso Completo e eu ajudarei a encontrar a solução.

O assistente usa IA e pode errar. Confirme informações críticas no datasheet oficial do fabricante.