Kit Robô Avançado 4WD Com Câmera AD176 - Curso Completo

Kit Robô Avançado 4WD Com Câmera AD176 — Curso Completo com Projetos Práticos

Introdução

Este curso apresenta o Kit Robô Avançado 4WD Com Câmera AD176, um robô omnidirecional de quatro rodas Mecanum com ESP32-CAM e sensor de imagem OV2640, Arduino UNO com placa de expansão L293D e registrador 74HC595, ultrassom HC-SR04, seguidor de linha de 3 canais IR e servo pan-tilt SG90 da câmera, com vídeo MJPEG — motion JPEG — via WiFi em modo AP — access point — e comando por UART — universal asynchronous receiver-transmitter — a 115200 bps entre as duas controladoras. É um material educacional para quem está começando em robótica móvel, sistemas embarcados e redes WiFi embarcadas: a sequência parte da montagem mecânica e da preparação do ambiente, passa por ensaios isolados de tração, servo, ultrassom e linha, e chega aos firmwares integrados Web e APP com quatro modos (livre, desvio, seguimento e linha), com o que você deve ver em cada teste. Ao final, o leitor terá o robô montado, calibrado, transmitindo vídeo em 192.168.4.1 e dirigível pelo navegador e pelo aplicativo.

O que você vai aprender:

  • Montar o chassi 4WD Mecanum e o pan-tilt com orientação correta dos roletes
  • Preparar Arduino IDE, núcleo ESP32 2.0.12, driver CH340 e biblioteca Servo
  • Validar tração omnidirecional, servo SG90, HC-SR04 e seguidor de 3 canais
  • Operar o modo Web com MJPEG e comandos UART de 4 bytes
  • Operar o modo APP com protocolo em quadros e streaming dedicado
  • Diagnosticar WiFi, upload, alimentação 18650 e calibração de pista

Material utilizado: Kit Robô Avançado 4WD Com Câmera AD176 disponível na loja RoboBuilders em https://robobuilders.com.br.

Visão Geral do Kit e Arquitetura de Hardware

O AD176 combina dois cérebros: o UNO executa tração, servo, ultrassom e linha em tempo real, enquanto a ESP32-CAM executa câmera, rede AP e ponte serial para a web e o aplicativo. O barramento entre elas é uma UART cruzada TX/RX a 115200 bps, desconectada fisicamente durante cada upload porque os mesmos pinos servem ao conversor USB do PC. A energia vem de duas células 18650 em série (~7,4 V nominal) com chave liga/desliga, regulada na expansão para 5 V da lógica e dos servos e para as pontes dos motores. As rodas Mecanum possuem roletes a 45∘45^{\circ} em torno do cubo. Cada roda gera forca perpendicular ao eixo do rolete, decomponivel em componentes longitudinal FxF_x e lateral FyF_y. Com quatro rodas independentes em configuracao X, a soma vetorial permite translacao omnidirecional sem mudar a orientacao do chassi. O principio formal da cinematica direta do 4WD Mecanum, com semi-distancias LxL_x e LyL_y do centro, raio rr e velocidades angulares ω1…ω4\omega_1 \ldots \omega_4, e:

[vxvyωz]=r4[1111−111−1−1Lx+Ly1Lx+Ly−1Lx+Ly1Lx+Ly][ω1ω2ω3ω4]\begin{bmatrix} v_x \\ v_y \\ \omega_z \end{bmatrix} = \frac{r}{4} \begin{bmatrix} 1 & 1 & 1 & 1 \\ -1 & 1 & 1 & -1 \\ -\frac{1}{L_x+L_y} & \frac{1}{L_x+L_y} & -\frac{1}{L_x+L_y} & \frac{1}{L_x+L_y} \end{bmatrix} \begin{bmatrix} \omega_1 \\ \omega_2 \\ \omega_3 \\ \omega_4 \end{bmatrix}

onde vxv_x e a velocidade longitudinal, vyv_y a lateral e ωz\omega_z a taxa de guinada. A decomposicao por rolete explica os codigos decimais da tabela do fabricante: cada byte de 8 bits mapeia os 8 terminais de ponte H dos quatro motores via 74HC595, de modo que frentes paralelas somam FxF_x (marcha 163/92) e oposicoes simetricas somam FyF_y (translacao 106/149), enquanto diagonais produzem resultante a 45∘45^{\circ} (34/129/72/20) e giros puros cancelam translacao e somam momento (83/172). A velocidade linear de cada roda segue v=ωrv = \omega r, e a forca de tracao disponivel e limitada pelo atrito Fmax=μNF_{max} = \mu N, por isso piso liso reduz derrapagem dos roletes e melhora a lateralidade. O driver usa dois canais PWM (55 e 66) para energia e o registrador de deslocamento para direcao, separando potencia e logica como em toda ponte H dupla.

O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Diagrama de fiação oficial Kuongshun AD176: UNO-Cam-Shield, ESP32-CAM, HC-SR04, seguidor IR, servo, motores e bateriaRobô AD176 montado: chassi 4WD Mecanum, ESP32-CAM no pan-tilt, HC-SR04 e antena WiFi

Inventário do kit

  • Chassi acrílico em dois andares com furação Mecanum e suporte do pan-tilt — base mecânica que separa potência embaixo e sensores em cima, reduzindo interferência e facilitando o acesso à chave e às baterias
  • 4 rodas Mecanum de 60 mm com roletes a 45 graus (2 espelhadas tipo A e 2 tipo B) — conjunto omnidirecional cuja orientação em X determina as resultantes laterais e diagonais da tabela de códigos
  • 4 motores DC com redução e acoplamentos — atuadores de tração independentes comandados em direção pelo 74HC595 e em energia pelo PWM duplo
  • Placa Arduino UNO compatível com USB Tipo-C e CH340 — controladora de tempo real da tração, servo, ultrassom e linha
  • Placa de expansão L293D para UNO com soquetes de ponte H — estágio de potência dos quatro motores com bornes, trilhas de corrente e conector de baterias com chave
  • Módulo ESP32-CAM com câmera OV2640 e LED flash no GPIO 4 — subsistema de visão e rede AP que faz streaming MJPEG e ponte UART com o UNO
  • Servo SG90 para pan-tilt da câmera com braço e parafusos — inclinação vertical da imagem comandada por PPM de 20 ms com centro em 90 graus
  • Sensor ultrassônico HC-SR04 com gatilho e eco — telemetria de distância por tempo de voo para desvio e seguimento
  • Módulo seguidor de linha de 3 canais IR (A0/A1/A2) — leitura reflexiva da pista com limiar calibrável entre 400 e 500 contagens
  • Cabo serial UART entre UNO e ESP32-CAM (RX/TX/GND) — enlace de comandos removível obrigatoriamente durante uploads
  • 2 suportes e fiação para células 18650 com chave — barramento de ~7,4 V que alimenta motores, lógica e câmera simultaneamente
  • Pacote de parafusos, porcas, espaçadores de latão, chave e cabo USB Tipo-C de dados — fixação, empilhamento dos andares e conexão com o PC para gravação
  • Pista de linha preta para ensaios e guia impresso V2.0 — referência de calibração do seguidor e roteiro dos projetos 1 a 6.2
  • Aplicativo KUONGSHUN em APK Android (e variante iOS na loja) — controle remoto com vídeo, D-pad omnidirecional, sliders de servo, farol e velocidade

Somatória: 14 grupos, totalizando dezenas de peças que compõem um robô completo de dois cérebros (UNO + ESP32-CAM), tração omnidirecional de 4 motores, visão WiFi, 2 sensores de navegação e pan-tilt ativo.

Mapa de pinos e protocolos (consolidado dos .ino reais)

SubsistemaPino UNO / ESP32-CAMDireçãoProtocoloObservação
PWM motoresD5, D6 (UNO)SaídaPWM ~980 HzEnergia das pontes; analogWrite(0-255)
Expansor direçãoD2 SHCP, D4 STCP, D7 EN, D8 DATASaídaShift serial MSBFIRSTByte de 8 bits define os 4 motores
Servo pan-tiltD9 (UNO)SaídaPPM 20 msBiblioteca Servo; centro 90 graus
UltrassomD12 TRIG saída, D13 ECHO entradaMistoPulso + pulseIn/58Limiares 15/25/50 cm
Linha IRA0/A1/A2 (A2 esquerda, A1 centro, A0 direita no All)EntradaADC 10 bitsLimiar 400-500
Enlace UNO<>CAMTX/RX cruzados 115200 8N1MistoUARTDesconectar nos uploads
ESP32-CAM UART2RXD2 GPIO14, TXD2 GPIO13MistoUART2 115200Ponte com o UNO
Câmera OV2640Y2-Y9, XCLK0, PCLK22, VSYNC25, HREF23, SCCB 26/27, PWDN32InternaDVP+SCCBSVGA qualidade 10-12
FlashGPIO4 (LEDC canal 7, 5 kHz, 8 bits)SaídaLEDCPisca 5x no boot; slider no app
RedeAP KUONGSHUN-AD176 / 12345678 canal 5RFWiFi 802.11 + HTTP/MJPEGPortal em 192.168.4.1; servidor TCP 100 no APP

Montagem Mecânica (Assembly Guide)

Montagem em 8 passos na ordem do fabricante, com verificação após cada etapa. As rodas Mecanum possuem roletes a 45∘45^{\circ} em torno do cubo. Cada roda gera forca perpendicular ao eixo do rolete, decomponivel em componentes longitudinal FxF_x e lateral FyF_y. Com quatro rodas independentes em configuracao X, a soma vetorial permite translacao omnidirecional sem mudar a orientacao do chassi. O principio formal da cinematica direta do 4WD Mecanum, com semi-distancias LxL_x e LyL_y do centro, raio rr e velocidades angulares ω1…ω4\omega_1 \ldots \omega_4, e: A regra de ouro: roletes formam um X visto de cima — dianteira esquerda e traseira direita com uma diagonal, dianteira direita e traseira esquerda com a outra. Errar o X inverte a lateralidade e nenhum software corrige.

Passo 1 — Chassi inferior, motores e rodas Mecanum

Fixe os 4 motores com suportes, instale as rodas respeitando o X Mecanum e confira giro livre. Validação: empurrando desligado, os roletes deslizam a 45 graus. Teoria de apoio: O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Passo 1 — Chassi inferior, motores e rodas Mecanum

💡 Dica: fotografe cada passo; a foto resolve 80% dos diagnósticos de fiação.

Passo 2 — Expansão L293D, baterias e fiação de potência

Encaixe a expansão no UNO, ligue os 8 fios dos motores nos bornes, o pack 18650 na entrada com chave OFF e confira polaridade. Validação: chave ON acende LEDs da expansão sem fumaça nem aquecimento. Teoria de apoio: O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Passo 2 — Expansão L293D, baterias e fiação de potência

💡 Dica: fotografe cada passo; a foto resolve 80% dos diagnósticos de fiação.

Passo 3 — Andar superior, HC-SR04 e seguidor de linha

Fixe espaçadores, aparafuse o andar superior, monte o HC-SR04 à frente e o trio IR abaixo voltado ao solo. Validação: sensores firmes, sem encostar nas rodas. Teoria de apoio: O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Passo 3 — Andar superior, HC-SR04 e seguidor de linha

💡 Dica: fotografe cada passo; a foto resolve 80% dos diagnósticos de fiação.

Passo 4 — Pan-tilt com SG90 e ESP32-CAM

Centralize o servo em 90 graus antes de aparafusar o braço, fixe a ESP32-CAM no suporte e aponte a lente à frente. Validação: câmera nivelada, curso livre do tilt. Teoria de apoio: O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Passo 4 — Pan-tilt com SG90 e ESP32-CAM

💡 Dica: fotografe cada passo; a foto resolve 80% dos diagnósticos de fiação.

Passo 5 — Enlace UART UNO<>CAM e roteamento de cabos

Ligue TX>RX cruzados mais GND, organize com abraçadeiras longe das rodas. Validação: conector firme porém desplugável para os uploads. Teoria de apoio: O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Passo 5 — Enlace UART UNO<>CAM e roteamento de cabos

💡 Dica: fotografe cada passo; a foto resolve 80% dos diagnósticos de fiação.

Passo 6 — Checklist pré-energia

Confira X das rodas, polaridade 18650, UART, parafusos e lente sem película. Validação: checklist completo antes do primeiro ON. Teoria de apoio: O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Passo 6 — Checklist pré-energia

💡 Dica: fotografe cada passo; a foto resolve 80% dos diagnósticos de fiação.

Passo 7 — Primeira energização sem firmware de tração

Ligue a chave em área livre e observe LEDs das duas placas. Validação: sem movimento brusco nem cheiro; desligue se o servo vibrar. Teoria de apoio: O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Passo 7 — Primeira energização sem firmware de tração

💡 Dica: fotografe cada passo; a foto resolve 80% dos diagnósticos de fiação.

Passo 8 — Pista de testes e área livre

Delimite 2 m x 2 m livres e estenda a pista de linha. Validação: espaço para os 11 estados da Lição 1 sem colisões. Teoria de apoio: O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes.

Passo 8 — Pista de testes e área livre

💡 Dica: fotografe cada passo; a foto resolve 80% dos diagnósticos de fiação.

⚠️ Atenção: nunca ligue a chave com o cabo USB conectado ao PC e o robô sobre a bancada — a primeira tração pode derrubá-lo.

⛔ Perigo: 18650 invertida ou danificada pode incendiar. Confira polaridade, use células íntegras e carregue com a chave OFF.

Preparação do Ambiente (versões pinadas)

Cadeia exata do fabricante: Arduino IDE (versão estável atual) + driver CH340 + pacote ESP32 2.0.12 via esp32_package_2.0.12_arduinome.exe + biblioteca Servo + APK KUONGSHUN.apk. O aviso do PDF é explícito: não usar núcleo 3.x, pois a API de câmera/LEDC mudou e os exemplos falham. A ESP32-CAM opera em modo AP — access point — criando a rede KUONGSHUN-AD176 com senha 12345678 e IP fixo 192.168.4.1192.168.4.1. O video usa MJPEG sobre HTTP — motion JPEG over hypertext transfer protocol — com multipart x-mixed-replace, onde cada frame JPEG e delimitado por boundary e empurrado em chunked encoding. A taxa util aproximada e:

R≈f⋅Setframe=SRef+tcodR \approx f \cdot S \qquad \text{e} \qquad t_{frame} = \frac{S}{R_{ef}} + t_{cod}

onde RR e o bitrate, ff o framerate, SS o tamanho medio do JPEG e tcodt_{cod} o tempo de compressao. SVGA (800×600800 \times 600) a qualidade 1010–1212 equilibra nitidez e latencia; UXGA trava o stream por esgotar PSRAM e banda. O enlace de comando UNO ↔\leftrightarrow ESP32-CAM usa UART a 115200 bps115200\,\text{bps} (8N18N1), com pacotes de 44 bytes (AB modelo valor FF) no modo Web e quadros FF 55 ... no modo APP, ambos com timeout de 10 ms10\,\text{ms}. A potencia de TX em 19,5 dBm19{,}5\,\text{dBm} maximiza alcance indoor a custa de consumo, por isso video so e estavel com bateria cheia. O canal fixo 55 reduz interferencia com roteadores domesticos.

Etapa 1 — Arduino IDE + driver CH340

Instale a IDE, conecte o UNO via cabo Tipo-C de dados e instale o CH340 das pastas Windows/Mac. Validação: menu Ferramentas > Porta lista COMxx além do COM1.

Arduino IDE + driver CH340

Etapa 2 — Núcleo ESP32 2.0.12

Execute o instalador offline do fabricante e selecione ESP32 Dev Module. Validação: exemplos ESP32 aparecem e o CameraWebServer compila sem erro de ledcSetup.

Núcleo ESP32 2.0.12

Etapa 3 — Biblioteca Servo

Adicione o Servo.zip via Sketch > Incluir Biblioteca > .ZIP. Validação: exemplo Sweep compila para UNO.

Biblioteca Servo

Tabela-mestre de bibliotecas do curso

Consolidação única de todas as bibliotecas usadas nos 8 projetos. As duas vias de instalação existem; a via Gerenciador é a recomendada quando disponível, e a via ZIP do fabricante garante a versão testada pelo Kuongshun.

Biblioteca (#include)Buscar no GerenciadorVersão usada no cursoDownload ZIP (espelho oficial)Lições
Servo.h (<Servo.h>)Servo por Michael Margolis, ArduinoA do Servo.zip da pasta 3. Add library files do fabricante (conferir em library.properties após instalar)ZIP do fabricante; espelho oficial em arduino/Servo (Code > Download ZIP)2, 5.1, 6.1
WiFi.h, esp_camera.h, esp_system.h, soc/soc.h, soc/rtc_cntl_reg.hNada a buscar — vêm no núcleo ESP32Pacote ESP32 2.0.12 (instalador esp32_package_2.0.12_arduinome.exe do fabricante; não usar núcleo 3.x)Núcleo via instalador do fabricante5.2, 6.2
Nenhuma (GPIO/PWM/pulseIn/analogRead nativos)Nada a instalarNúcleo Arduino AVR padrão da IDE—1, 3, 4

⚠️ Atenção: cada box > 📦 **Bibliotecas desta lição:** antes dos códigos referencia esta tabela-mestre. Se o erro for No such file or directory ou does not name a type, reinstale pela tabela acima, confira a pasta libraries/Nome/Nome.h e reinicie a IDE.

Etapa 4 — APK KUONGSHUN

Copie o APK da pasta 4_Android_Software_Installation_Package ao celular e instale (iOS: buscar kuongshun na App Store). Validação: ícone instalado antes da Lição 6.

APK KUONGSHUN

Etapa 5 — Ritual de upload (vale para todas as lições)

Desconecte o jumper UART UNO<>CAM, selecione placa e porta corretas, grave, desplugue o USB e só então reconecte o jumper. Validação: mensagem de upload com sucesso na IDE.

Ritual de upload (vale para todas as lições)

⚠️ Atenção: cabo USB só-carga não cria porta COM. Se só aparece COM1, troque o cabo e reinstale o CH340.

Lição 1 — Movimento Automático Omnidirecional (1_Auto_Move)

O UNO comanda a expansão L293D: PWM dita energia e o 74HC595 dita direção dos 4 motores. A sequência de 11 estados (frente, trás, esquerda, direita, 4 diagonais, 2 giros, parada) com 2 s cada demonstra a soma vetorial dos roletes. As rodas Mecanum possuem roletes a 45∘45^{\circ} em torno do cubo. Cada roda gera forca perpendicular ao eixo do rolete, decomponivel em componentes longitudinal FxF_x e lateral FyF_y. Com quatro rodas independentes em configuracao X, a soma vetorial permite translacao omnidirecional sem mudar a orientacao do chassi. O principio formal da cinematica direta do 4WD Mecanum, com semi-distancias LxL_x e LyL_y do centro, raio rr e velocidades angulares ω1…ω4\omega_1 \ldots \omega_4, e:

[vxvyωz]=r4[1111−111−1−1Lx+Ly1Lx+Ly−1Lx+Ly1Lx+Ly][ω1ω2ω3ω4]\begin{bmatrix} v_x \\ v_y \\ \omega_z \end{bmatrix} = \frac{r}{4} \begin{bmatrix} 1 & 1 & 1 & 1 \\ -1 & 1 & 1 & -1 \\ -\frac{1}{L_x+L_y} & \frac{1}{L_x+L_y} & -\frac{1}{L_x+L_y} & \frac{1}{L_x+L_y} \end{bmatrix} \begin{bmatrix} \omega_1 \\ \omega_2 \\ \omega_3 \\ \omega_4 \end{bmatrix}

onde vxv_x e a velocidade longitudinal, vyv_y a lateral e ωz\omega_z a taxa de guinada. A decomposicao por rolete explica os codigos decimais da tabela do fabricante: cada byte de 8 bits mapeia os 8 terminais de ponte H dos quatro motores via 74HC595, de modo que frentes paralelas somam FxF_x (marcha 163/92) e oposicoes simetricas somam FyF_y (translacao 106/149), enquanto diagonais produzem resultante a 45∘45^{\circ} (34/129/72/20) e giros puros cancelam translacao e somam momento (83/172). A velocidade linear de cada roda segue v=ωrv = \omega r, e a forca de tracao disponivel e limitada pelo atrito Fmax=μNF_{max} = \mu N, por isso piso liso reduz derrapagem dos roletes e melhora a lateralidade. O driver usa dois canais PWM (55 e 66) para energia e o registrador de deslocamento para direcao, separando potencia e logica como em toda ponte H dupla.

ItemQtdPapel no ensaio
Chassi 4WD Mecanum1plataforma omnidirecional
UNO + L293D + 74HC5951potência e direção
18650 x22energia de tração
Cabo Tipo-C dados1upload
Movimento Automático Omnidirecional (1_Auto_Move) bancada de teste
SinalPinoObservação
PWMD5/D6Velocidade dos motores
SHCP/EN/DATA/STCPD2/D7/D8/D4Direção via 74HC595
ServoD9Pan-tilt da câmera
TRIG/ECHOD12/D13Ultrassom
LinhaA0/A1/A2Trio IR
UARTTX/RX 115200Enlace com ESP32-CAM (desplugado no upload)

Código real 1_Auto_Move.ino comentado linha a linha

📦 Bibliotecas desta lição: nenhuma — o código usa GPIO/PWM (pinMode, digitalWrite, analogWrite, delay) nativos, sem biblioteca externa.

//www.kuongshun.com
 
 // PWM control pin
#define PWM1_PIN            5  // define constante de pino/mapa de hardware
#define PWM2_PIN            6        // define constante de pino/mapa de hardware
// 74HCT595N Chip pins
#define SHCP_PIN            2                               // The displacement of the clock  // define constante de pino/mapa de hardware
#define EN_PIN              7                               // Can make control  // define constante de pino/mapa de hardware
#define DATA_PIN            8                               // Serial data  // define constante de pino/mapa de hardware
#define STCP_PIN            4                               // Memory register clock                    // define constante de pino/mapa de hardware

const int Forward       = 163;                               // forward  // executa etapa do firmware do robo
const int Backward      = 92;                              // back  // executa etapa do firmware do robo
const int Turn_Left     = 106;                              // left translation  // executa etapa do firmware do robo
const int Turn_Right    = 149;                              // Right translation   // executa etapa do firmware do robo
const int Top_Left      = 34;                               // Upper left mobile  // executa etapa do firmware do robo
const int Bottom_Left   = 72;                              // Lower left mobile  // executa etapa do firmware do robo
const int Top_Right     = 129;                               // Upper right mobile  // executa etapa do firmware do robo
const int Bottom_Right  = 20;                               // The lower right move  // executa etapa do firmware do robo
const int Stop          = 0;                                // stop  // executa etapa do firmware do robo
const int Contrarotate  = 83;                              // Counterclockwise rotation  // executa etapa do firmware do robo
const int Clockwise     = 172;                               // Rotate clockwise  // executa etapa do firmware do robo

void setup()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    pinMode(SHCP_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(EN_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(DATA_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(STCP_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(PWM1_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(PWM2_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
}  // executa etapa do firmware do robo

void loop()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    /* Forward */  // executa etapa do firmware do robo
    Motor(Forward, 250);       // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Backward */  // executa etapa do firmware do robo
    Motor(Backward, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Turn_Left */  // executa etapa do firmware do robo
    Motor(Turn_Left, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Turn_Right */  // executa etapa do firmware do robo
    Motor(Turn_Right, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Top_Left */  // executa etapa do firmware do robo
    Motor(Top_Left, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Bottom_Right */  // executa etapa do firmware do robo
    Motor(Bottom_Right, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Bottom_Left */  // executa etapa do firmware do robo
    Motor(Bottom_Left, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Top_Right */  // executa etapa do firmware do robo
    Motor(Top_Right, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Clockwise */  // executa etapa do firmware do robo
    Motor(Clockwise, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Contrarotate */  // executa etapa do firmware do robo
    Motor(Contrarotate, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
    /* Stop */  // executa etapa do firmware do robo
    Motor(Stop, 250);  // aciona tracao Mecanum no modo/velocidade indicados
    delay(2000);  // aguarda estabilizacao/temporizacao do atuador
}  // executa etapa do firmware do robo

void Motor(int Dir, int Speed)  // aciona tracao Mecanum no modo/velocidade indicados
{  // executa etapa do firmware do robo
    digitalWrite(EN_PIN, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
    analogWrite(PWM1_PIN, Speed);  // gera PWM com duty proporcional a velocidade
    analogWrite(PWM2_PIN, Speed);  // gera PWM com duty proporcional a velocidade
    digitalWrite(STCP_PIN, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
    shiftOut(DATA_PIN, SHCP_PIN, MSBFIRST, Dir);  // desloca 8 bits ao 74HC595 controlando os 4 motores
    digitalWrite(STCP_PIN, HIGH);  // escreve nivel logico ALTO/BAIXO no pino digital
}  // executa etapa do firmware do robo

Gravação e teste (o que você deve ver)

Desconecte a UART, selecione Arduino UNO e a porta COM, grave e observe sucesso na IDE. Desplugue o USB, instale as 18650, coloque em área livre e ligue a chave. Resultado esperado descrito na teoria de cada modo; divergência indica fiação, bateria ou limiar — ver Troubleshooting.

💡 Dica: valide com o Monitor Serial em 9600/115200 bps conforme o sketch antes de culpar o hardware.

⚠️ Atenção: uploads com a UART conectada falham por contenção do RX/TX; desplugue sempre.

⛔ Perigo: robô em movimento sobre a bancada cai e quebra a câmera; teste sempre no chão.

Lição 2 — Ângulo do Servo Pan-Tilt (2_Servo_Angle)

O SG90 posiciona a câmera; o exemplo varre 0→180→0 para revelar o centro mecânico de 90 graus e permitir calçar o braço corretamente. O servo SG90 e comandado por PPM com periodo de 20 ms20\,\text{ms}. A largura do pulso codifica o angulo:

θ=tp−1,0 ms1,0 ms⋅90∘1,0≤tp≤2,0 ms\theta = \frac{t_p - 1{,}0\,\text{ms}}{1{,}0\,\text{ms}} \cdot 90^{\circ} \qquad 1{,}0 \leq t_p \leq 2{,}0\,\text{ms}

onde θ\theta varia de 0∘0^{\circ} a 180∘180^{\circ} e tpt_p e a largura em milissegundos. A biblioteca Servo.h abstrai o timer em write(graus), com 90∘90^{\circ} como frente mecanica da camera. O torque τ∼1,8 kgf.cm\tau \sim 1{,}8\,\text{kgf.cm} exige alimentacao 5 V5\,\text{V} estavel; jitter indica queda de tensao sob carga dos motores. A varredura 0→180→00 \rightarrow 180 \rightarrow 0 com passo de 10 ms10\,\text{ms} do exemplo produz velocidade angular ω≈100∘/s\omega \approx 100^{\circ}/\text{s}, suave para calibrar o braco do pan-tilt sem forcar engrenagens. O reset ao 90∘90^{\circ} antes do ajuste mecanico garanteDatum repetivel.

ItemQtdPapel no ensaio
Servo SG90 no D91tilt da câmera
Suporte pan-tilt + ESP32-CAM1carga do servo
UNO + USB1comando PPM
Ângulo do Servo Pan-Tilt (2_Servo_Angle) bancada de teste
SinalPinoObservação
PWMD5/D6Velocidade dos motores
SHCP/EN/DATA/STCPD2/D7/D8/D4Direção via 74HC595
ServoD9Pan-tilt da câmera
TRIG/ECHOD12/D13Ultrassom
LinhaA0/A1/A2Trio IR
UARTTX/RX 115200Enlace com ESP32-CAM (desplugado no upload)

Código real 2_Servo_Angle.ino comentado linha a linha

📦 Bibliotecas desta lição: Servo (#include <Servo.h>, instalada pelo quadro abaixo).

  • Via ZIP do fabricante (recomendado): pasta 3. Add library files → Sketch > Incluir Biblioteca > Adicionar Biblioteca .ZIP… → selecionar o Servo.zip → reiniciar a IDE.
  • Via Gerenciador (alternativa): Sketch > Incluir Biblioteca > Gerenciar Bibliotecas… → buscar Servo (Michael Margolis, Arduino) → Instalar → reiniciar a IDE.
  • Conferência: Arquivo > Exemplos > Servo > Sweep deve abrir e compilar para Arduino UNO sem No such file or directory. Ver tabela-mestre na Preparação de ambiente.
//www.kuongshun.com

#include    <Servo.h>  // instalada pelo quadro "Bibliotecas desta lição" (Servo.zip do fabricante)
#define servo_PIN    9  // define constante de pino/mapa de hardware
Servo myservo;  // comanda o servo pan-tilt da camera
void setup()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    myservo.attach(servo_PIN);  // comanda o servo pan-tilt da camera
    myservo.write(90);  // comanda o servo pan-tilt da camera
    delay(1000);  // aguarda estabilizacao/temporizacao do atuador
}  // executa etapa do firmware do robo

void loop()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  for(int i=0;i<180;i++){  // laco de varredura incremental do ensaio
    myservo.write(i);  // comanda o servo pan-tilt da camera
    delay(10);  // aguarda estabilizacao/temporizacao do atuador
  }  // executa etapa do firmware do robo
  delay(1000);  // aguarda estabilizacao/temporizacao do atuador
  for(int i=180;i>0;i--){  // laco de varredura incremental do ensaio
    myservo.write(i);  // comanda o servo pan-tilt da camera
    delay(10);  // aguarda estabilizacao/temporizacao do atuador
  }  // executa etapa do firmware do robo
  delay(1000);  // aguarda estabilizacao/temporizacao do atuador
}  // executa etapa do firmware do robo

Gravação e teste (o que você deve ver)

Desconecte a UART, selecione Arduino UNO e a porta COM, grave e observe sucesso na IDE. Desplugue o USB, instale as 18650, coloque em área livre e ligue a chave. Resultado esperado descrito na teoria de cada modo; divergência indica fiação, bateria ou limiar — ver Troubleshooting.

💡 Dica: valide com o Monitor Serial em 9600/115200 bps conforme o sketch antes de culpar o hardware.

⚠️ Atenção: uploads com a UART conectada falham por contenção do RX/TX; desplugue sempre.

⛔ Perigo: robô em movimento sobre a bancada cai e quebra a câmera; teste sempre no chão.

Lição 3 — Sensor Ultrassônico HC-SR04 (3_Ultrasonic)

Telemetria por tempo de voo com saída no Monitor Serial a 9600 bps, base de todos os modos de desvio e seguimento. O HC-SR04 mede distancia por tempo de voo do ultrassom. O gatilho de 10 μs10\,\mu\text{s} emite 8 ciclos a 40 kHz40\,\text{kHz}; o eco retorna apos tt microssegundos de ida e volta. Com vsom≈343 m/sv_{som} \approx 343\,\text{m/s}:

d=vsom⋅t2=t58  cm(t  em  μs)d = \frac{v_{som} \cdot t}{2} = \frac{t}{58} \; \text{cm} \qquad (t \; \text{em} \; \mu\text{s})

onde dd e a distancia ao obstaculo. O divisor 5858 usado em pulseIn(ECHO, HIGH)/58.00 deriva de 104/172≈58,110^4/172 \approx 58{,}1. A zona cega abaixo de ∼2 cm\sim 2\,\text{cm} e o cone de ∼15∘\sim 15^{\circ} exigem servo centralizado a 90∘90^{\circ} nas leituras de desvio, e superficies absorventes inclinadas subestimam dd. O firmware filtra com delay(10) entre disparos para dissipar ecos multiplos, e os limiares 15/25/50 cm15/25/50\,\text{cm} dos modos seguimento e desvio derivam diretamente dessa resolucao centimetrica.

ItemQtdPapel no ensaio
HC-SR04 (D12/D13)1distância em cm
UNO + USB1leitura serial
Anteparo de teste1alvo a 10-100 cm
Sensor Ultrassônico HC-SR04 (3_Ultrasonic) bancada de teste
SinalPinoObservação
PWMD5/D6Velocidade dos motores
SHCP/EN/DATA/STCPD2/D7/D8/D4Direção via 74HC595
ServoD9Pan-tilt da câmera
TRIG/ECHOD12/D13Ultrassom
LinhaA0/A1/A2Trio IR
UARTTX/RX 115200Enlace com ESP32-CAM (desplugado no upload)

Código real 3_Ultrasonic.ino comentado linha a linha

📦 Bibliotecas desta lição: nenhuma — o código usa pulseIn() nativo, sem biblioteca externa.

//www.kuongshun.com

float checkdistance()  // executa etapa do firmware do robo
{  // executa etapa do firmware do robo
    digitalWrite(12, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
    delayMicroseconds(2);  // aguarda estabilizacao/temporizacao do atuador
    digitalWrite(12, HIGH);  // escreve nivel logico ALTO/BAIXO no pino digital
    delayMicroseconds(10);  // aguarda estabilizacao/temporizacao do atuador
    digitalWrite(12, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
    float distance = pulseIn(13, HIGH) / 58.00;  // mede largura do eco ultrassonico para calcular distancia
    delay(10);  // aguarda estabilizacao/temporizacao do atuador
    return distance;  // retorna valor calculado ao chamador
}  // executa etapa do firmware do robo

void Ultrasonic_Sensor_Module()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    int Distance = 0;  // executa etapa do firmware do robo
    Distance = checkdistance();  // executa etapa do firmware do robo
    Serial.print("Distance:");  // envia telemetria ao Monitor Serial
    Serial.print(Distance);  // envia telemetria ao Monitor Serial
    Serial.println("CM");  // envia telemetria ao Monitor Serial
    delay(100);  // aguarda estabilizacao/temporizacao do atuador
}  // executa etapa do firmware do robo

void setup()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    Serial.begin(9600);  // inicializa UART para debug e enlace com ESP32-CAM
    pinMode(12, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(13, INPUT);  // configura o pino como entrada ou saida digital
}  // executa etapa do firmware do robo
void loop()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    Ultrasonic_Sensor_Module();  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

Gravação e teste (o que você deve ver)

Desconecte a UART, selecione Arduino UNO e a porta COM, grave e observe sucesso na IDE. Desplugue o USB, instale as 18650, coloque em área livre e ligue a chave. Resultado esperado descrito na teoria de cada modo; divergência indica fiação, bateria ou limiar — ver Troubleshooting.

💡 Dica: valide com o Monitor Serial em 9600/115200 bps conforme o sketch antes de culpar o hardware.

⚠️ Atenção: uploads com a UART conectada falham por contenção do RX/TX; desplugue sempre.

⛔ Perigo: robô em movimento sobre a bancada cai e quebra a câmera; teste sempre no chão.

Lição 4 — Seguidor de Linha com 3 IR (4_Line_Tracing)

Máquina de estados sobre o trio IR com 7 ramos ativos: cruzeiro, correções suaves e fortes e recuperação total. O seguidor de linha usa tres sensores reflexivos IR com comparacao analogica. Cada canal retorna 0…10230 \ldots 1023 via ADC de 10 bits, onde preto absorve IR (valor baixo) e branco reflete (valor alto). O limiar Black_LineBlack\_Line particiona o espaco de observacao, e a maquina de estados mapeia as 23=82^3 = 8 combinacoes em correcoes diferenciais. A lei de controle e proporcional por zona: erro lateral estimado e∈{−2,−1,0,+1,+2}e \in \{-2,-1,0,+1,+2\} gera correcao de guinada Δω=Kp⋅e\Delta \omega = K_p \cdot e implementada como giros Clockwise/ContrarotateClockwise/Contrarotate com PWM 160/220160/220 contra cruzeiro 120/180120/180. A tensao lida em cada canal e:

Vin=ADC1023⋅VrefcomVref=5,0 VV_{in} = \frac{ADC}{1023} \cdot V_{ref} \qquad \text{com} \qquad V_{ref} = 5{,}0\,\text{V}

onde ADCADC e a contagem e VrefV_{ref} a referencia do UNO. Calibracao com Serial.println dos tres canais sobre preto e branco define o limiar real da pista (400400 a 500500 conforme o lote), pois luz ambiente desloca o ponto otimo. Faixa estreita demais causa oscilacao; larga demais corta curvas. A geometria dos tres pontos a frente do eixo motor cria antecipacao natural da curva, equivalente a acao derivativa mecanica.

ItemQtdPapel no ensaio
Trio IR A0/A1/A21leitura da pista
Pista de linha1circuito de teste
UNO + L293D1correção diferencial
Seguidor de Linha com 3 IR (4_Line_Tracing) bancada de teste
SinalPinoObservação
PWMD5/D6Velocidade dos motores
SHCP/EN/DATA/STCPD2/D7/D8/D4Direção via 74HC595
ServoD9Pan-tilt da câmera
TRIG/ECHOD12/D13Ultrassom
LinhaA0/A1/A2Trio IR
UARTTX/RX 115200Enlace com ESP32-CAM (desplugado no upload)

Código real 4_Line_Tracing.ino comentado linha a linha

📦 Bibliotecas desta lição: nenhuma — o código usa analogRead()/digitalWrite() nativos do núcleo AVR, sem biblioteca externa.

//www.kuongshun.com

// PWM control pin
#define PWM1_PIN            5  // define constante de pino/mapa de hardware
#define PWM2_PIN            6        // define constante de pino/mapa de hardware
// 74HCT595N chip pin
#define SHCP_PIN            2                               // The displacement of the clock  // define constante de pino/mapa de hardware
#define EN_PIN              7                               // Can make control  // define constante de pino/mapa de hardware
#define DATA_PIN            8                               // Serial data  // define constante de pino/mapa de hardware
#define STCP_PIN            4                               // Memory register clock            // define constante de pino/mapa de hardware

#define LEFT_LINE_TRACJING          A0  // define constante de pino/mapa de hardware
#define CENTER_LINE_TRACJING        A1  // define constante de pino/mapa de hardware
#define right_LINE_TRACJING         A2  // define constante de pino/mapa de hardware

const int Forward       = 163;                               // forward  // executa etapa do firmware do robo
const int Backward      = 92;                              // back  // executa etapa do firmware do robo
const int Turn_Left     = 106;                              // left translation  // executa etapa do firmware do robo
const int Turn_Right    = 149;                              // Right translation   // executa etapa do firmware do robo
const int Top_Left      = 34;                               // Upper left mobile  // executa etapa do firmware do robo
const int Bottom_Left   = 72;                              // Lower left mobile  // executa etapa do firmware do robo
const int Top_Right     = 129;                               // Upper right mobile  // executa etapa do firmware do robo
const int Bottom_Right  = 20;                               // The lower right move  // executa etapa do firmware do robo
const int Stop          = 0;                                // stop  // executa etapa do firmware do robo
const int Contrarotate  = 83;                              // Counterclockwise rotation  // executa etapa do firmware do robo
const int Clockwise     = 172;                               // Rotate clockwise  // executa etapa do firmware do robo

int Left_Tra_Value;  // executa etapa do firmware do robo
int Center_Tra_Value;  // executa etapa do firmware do robo
int Right_Tra_Value;  // executa etapa do firmware do robo
int Black_Line = 500;//small is black  // executa etapa do firmware do robo


void setup()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    pinMode(SHCP_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(EN_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(DATA_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(STCP_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(PWM1_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
    pinMode(PWM2_PIN, OUTPUT);  // configura o pino como entrada ou saida digital

    pinMode(LEFT_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital
    pinMode(CENTER_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital
    pinMode(right_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital
    Serial.begin(9600);  // inicializa UART para debug e enlace com ESP32-CAM
}  // executa etapa do firmware do robo

void loop()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    Left_Tra_Value = analogRead(LEFT_LINE_TRACJING);  // le o sensor reflexivo IR da pista (linha)
    Center_Tra_Value = analogRead(CENTER_LINE_TRACJING);  // le o sensor reflexivo IR da pista (linha)
    Right_Tra_Value = analogRead(right_LINE_TRACJING);      // le o sensor reflexivo IR da pista (linha)
    Serial.println("l,c ,r:");  // envia telemetria ao Monitor Serial
    Serial.println(analogRead(LEFT_LINE_TRACJING));  // envia telemetria ao Monitor Serial
    Serial.println(analogRead(CENTER_LINE_TRACJING));  // envia telemetria ao Monitor Serial
    Serial.println(analogRead(right_LINE_TRACJING));  // envia telemetria ao Monitor Serial
    if (Left_Tra_Value > Black_Line && Center_Tra_Value <= Black_Line && Right_Tra_Value > Black_Line)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
        Motor(Forward, 180);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
    else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
        Motor(Forward, 120);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
    else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value < Black_Line)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
        Motor(Clockwise, 220);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
    else if (Left_Tra_Value >= Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
        Motor(Clockwise, 160);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
    else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value >= Black_Line)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
        Motor(Contrarotate, 160);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
    else if (Left_Tra_Value < Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
        Motor(Contrarotate, 220);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
    else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
        Motor(Forward, 120);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void Motor(int Dir, int Speed)  // aciona tracao Mecanum no modo/velocidade indicados
{  // executa etapa do firmware do robo
    digitalWrite(EN_PIN, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
    analogWrite(PWM1_PIN, Speed);  // gera PWM com duty proporcional a velocidade
    analogWrite(PWM2_PIN, Speed);  // gera PWM com duty proporcional a velocidade

    digitalWrite(STCP_PIN, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
    shiftOut(DATA_PIN, SHCP_PIN, MSBFIRST, Dir);  // desloca 8 bits ao 74HC595 controlando os 4 motores
    digitalWrite(STCP_PIN, HIGH);  // escreve nivel logico ALTO/BAIXO no pino digital
}  // executa etapa do firmware do robo

Gravação e teste (o que você deve ver)

Desconecte a UART, selecione Arduino UNO e a porta COM, grave e observe sucesso na IDE. Desplugue o USB, instale as 18650, coloque em área livre e ligue a chave. Resultado esperado descrito na teoria de cada modo; divergência indica fiação, bateria ou limiar — ver Troubleshooting.

💡 Dica: valide com o Monitor Serial em 9600/115200 bps conforme o sketch antes de culpar o hardware.

⚠️ Atenção: uploads com a UART conectada falham por contenção do RX/TX; desplugue sempre.

⛔ Perigo: robô em movimento sobre a bancada cai e quebra a câmera; teste sempre no chão.

Lição 5.1 — Multifunção Web lado Arduino (5.1_Arduino_All_Web)

O UNO vira executor serial: pacote de 4 bytes AB modelo valor FF seleciona modo livre/desvio/seguimento/linha, velocidade, servo e farol, com máquinas de desvio por varredura, seguimento por faixas e linha por zonas. O HC-SR04 mede distancia por tempo de voo do ultrassom. O gatilho de 10 μs10\,\mu\text{s} emite 8 ciclos a 40 kHz40\,\text{kHz}; o eco retorna apos tt microssegundos de ida e volta. Com vsom≈343 m/sv_{som} \approx 343\,\text{m/s}: O seguidor de linha usa tres sensores reflexivos IR com comparacao analogica. Cada canal retorna 0…10230 \ldots 1023 via ADC de 10 bits, onde preto absorve IR (valor baixo) e branco reflete (valor alto). O limiar Black_LineBlack\_Line particiona o espaco de observacao, e a maquina de estados mapeia as 23=82^3 = 8 combinacoes em correcoes diferenciais. A lei de controle e proporcional por zona: erro lateral estimado e∈{−2,−1,0,+1,+2}e \in \{-2,-1,0,+1,+2\} gera correcao de guinada Δω=Kp⋅e\Delta \omega = K_p \cdot e implementada como giros Clockwise/ContrarotateClockwise/Contrarotate com PWM 160/220160/220 contra cruzeiro 120/180120/180. A tensao lida em cada canal e:

d=vsom⋅t2=t58  cm(t  em  μs)d = \frac{v_{som} \cdot t}{2} = \frac{t}{58} \; \text{cm} \qquad (t \; \text{em} \; \mu\text{s})

onde dd e a distancia ao obstaculo. O divisor 5858 usado em pulseIn(ECHO, HIGH)/58.00 deriva de 104/172≈58,110^4/172 \approx 58{,}1. A zona cega abaixo de ∼2 cm\sim 2\,\text{cm} e o cone de ∼15∘\sim 15^{\circ} exigem servo centralizado a 90∘90^{\circ} nas leituras de desvio, e superficies absorventes inclinadas subestimam dd. O firmware filtra com delay(10) entre disparos para dissipar ecos multiplos, e os limiares 15/25/50 cm15/25/50\,\text{cm} dos modos seguimento e desvio derivam diretamente dessa resolucao centimetrica.

ItemQtdPapel no ensaio
UNO + todos sensores/atuadores1execução dos 4 modos
ESP32-CAM (ponte Web)1origem dos pacotes UART
Baterias 186502autonomia dos modos
Multifunção Web lado Arduino (5.1_Arduino_All_Web) bancada de teste
SinalPinoObservação
PWMD5/D6Velocidade dos motores
SHCP/EN/DATA/STCPD2/D7/D8/D4Direção via 74HC595
ServoD9Pan-tilt da câmera
TRIG/ECHOD12/D13Ultrassom
LinhaA0/A1/A2Trio IR
UARTTX/RX 115200Enlace com ESP32-CAM (desplugado no upload)

Código real 5.1_Arduino_All_Web.ino comentado linha a linha

📦 Bibliotecas desta lição: Servo — a mesma da Lição 2, nada a baixar. Se Arquivo > Exemplos > Servo > Sweep compila, siga direto ao código.

//www.kuongshun.com

#include    <Servo.h>  // instalada pelo quadro "Bibliotecas desta lição" (Servo.zip do fabricante)

#define MOTOR_PIN           9  // define constante de pino/mapa de hardware
#define PWM1_PIN            5  // define constante de pino/mapa de hardware
#define PWM2_PIN            6  // define constante de pino/mapa de hardware
#define SHCP_PIN            2                  // The displacement of the clock  // define constante de pino/mapa de hardware
#define EN_PIN              7                  // Can make control  // define constante de pino/mapa de hardware
#define DATA_PIN            8                  // Serial data  // define constante de pino/mapa de hardware
#define STCP_PIN            4                  // Memory register clock              // define constante de pino/mapa de hardware
#define Trig_PIN            12  // define constante de pino/mapa de hardware
#define Echo_PIN            13  // define constante de pino/mapa de hardware
#define LEFT_LINE_TRACJING      A2  // define constante de pino/mapa de hardware
#define CENTER_LINE_TRACJING    A1  // define constante de pino/mapa de hardware
#define right_LINE_TRACJING     A0  // define constante de pino/mapa de hardware

Servo MOTORservo;  // comanda o servo pan-tilt da camera

const int Forward       = 163;                 // forward  // executa etapa do firmware do robo
const int Backward      = 92;                  // back  // executa etapa do firmware do robo
const int Turn_Left     = 106;                 // left translation  // executa etapa do firmware do robo
const int Turn_Right    = 149;                 // Right translation  // executa etapa do firmware do robo
const int Top_Left      = 34;                  // Upper left mobile  // executa etapa do firmware do robo
const int Bottom_Left   = 72;                  // Lower left mobile  // executa etapa do firmware do robo
const int Top_Right     = 129;                 // Upper right mobile  // executa etapa do firmware do robo
const int Bottom_Right  = 20;                  // The lower right move  // executa etapa do firmware do robo
const int Stop          = 0;                   // stop  // executa etapa do firmware do robo
const int Contrarotate  = 83;                  // Counterclockwise rotation  // executa etapa do firmware do robo
const int Clockwise     = 172;                 // Rotate clockwise  // executa etapa do firmware do robo
const int Model1        = 25;                  // model1  // executa etapa do firmware do robo
const int Model2        = 26;                  // model2  // executa etapa do firmware do robo
const int Model3        = 27;                  // model3  // executa etapa do firmware do robo
const int Model4        = 28;                  // model4  // executa etapa do firmware do robo
const int Speed         = 29;  // executa etapa do firmware do robo
const int Servo         = 30;   // executa etapa do firmware do robo
const int MotorLeft     = 230;                 // servo turn left  // executa etapa do firmware do robo
const int MotorRight    = 231;                 // servo turn right  // executa etapa do firmware do robo

int Left_Tra_Value;  // executa etapa do firmware do robo
int Center_Tra_Value;  // executa etapa do firmware do robo
int Right_Tra_Value;  // executa etapa do firmware do robo
int Black_Line = 400;  // executa etapa do firmware do robo
int speeds = 250;  // executa etapa do firmware do robo
int leftDistance = 0;  // executa etapa do firmware do robo
int middleDistance = 0;  // executa etapa do firmware do robo
int rightDistance = 0;  // executa etapa do firmware do robo

byte RX_package[4] = {0};  // executa etapa do firmware do robo
uint16_t angle = 90;  // executa etapa do firmware do robo
byte Model = Stop;  // executa etapa do firmware do robo
byte val = 0;  // executa etapa do firmware do robo
char model_var = 0;  // executa etapa do firmware do robo
int UT_distance = 0;  // executa etapa do firmware do robo
int OA_mark=0;  // executa etapa do firmware do robo
void setup()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  Serial.setTimeout(10);  // executa etapa do firmware do robo
  Serial.begin(115200);  // inicializa UART para debug e enlace com ESP32-CAM

  MOTORservo.attach(MOTOR_PIN);  // comanda o servo pan-tilt da camera

  pinMode(SHCP_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(EN_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(DATA_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(STCP_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(PWM1_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(PWM2_PIN, OUTPUT);  // configura o pino como entrada ou saida digital

  pinMode(Trig_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(Echo_PIN, INPUT);  // configura o pino como entrada ou saida digital

  pinMode(LEFT_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital
  pinMode(CENTER_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital
  pinMode(right_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital

  MOTORservo.write(angle);  // comanda o servo pan-tilt da camera

  Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
}  // executa etapa do firmware do robo

void loop()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  RXpack_func();  // executa etapa do firmware do robo
  switch (model_var)  // seleciona modo/comando recebido via serial/rede
  {  // executa etapa do firmware do robo
    case 0:  // seleciona modo/comando recebido via serial/rede
      model1_func(val);  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
    case 1:  // seleciona modo/comando recebido via serial/rede
      model2_func();      // OA model  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
    case 2:  // seleciona modo/comando recebido via serial/rede
      model3_func();      // follow model  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
    case 3:  // seleciona modo/comando recebido via serial/rede
      model4_func();      // Tracking model  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
    case 4:  // seleciona modo/comando recebido via serial/rede
      Servo_Move();  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo

}  // executa etapa do firmware do robo

void model1_func(byte values)  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  switch (values)  // seleciona modo/comando recebido via serial/rede
  {  // executa etapa do firmware do robo
    case Stop:  // seleciona modo/comando recebido via serial/rede
      Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Forward:  // seleciona modo/comando recebido via serial/rede
      Motor(Forward, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Backward:  // seleciona modo/comando recebido via serial/rede
      Motor(Backward, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Turn_Left:  // seleciona modo/comando recebido via serial/rede
      Motor(Turn_Left, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Turn_Right:  // seleciona modo/comando recebido via serial/rede
      Motor(Turn_Right, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Top_Left:  // seleciona modo/comando recebido via serial/rede
      Motor(Top_Left, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Top_Right:  // seleciona modo/comando recebido via serial/rede
      Motor(Top_Right, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Bottom_Left:  // seleciona modo/comando recebido via serial/rede
      Motor(Bottom_Left, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Bottom_Right:  // seleciona modo/comando recebido via serial/rede
      Motor(Bottom_Right, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Clockwise:  // seleciona modo/comando recebido via serial/rede
      Motor(Clockwise, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    case Contrarotate:  // seleciona modo/comando recebido via serial/rede
      Motor(Contrarotate, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
    default:  // executa etapa do firmware do robo
      // Serial.println(".");
      Model = 0;  // executa etapa do firmware do robo
      Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
      break;  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void model2_func()      // OA  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  while (model_var == 1) {  // mantem o modo autonomo ate trocar de modo
    RXpack_func();  // executa etapa do firmware do robo
    middleDistance = SR04(Trig_PIN, Echo_PIN);  // executa etapa do firmware do robo
    if (middleDistance <= 15)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
      Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(100);  // aguarda estabilizacao/temporizacao do atuador
      Motor(Backward, speeds-70);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(100);  // aguarda estabilizacao/temporizacao do atuador
      Motor(Clockwise, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(200);  // aguarda estabilizacao/temporizacao do atuador
      Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(200);  // aguarda estabilizacao/temporizacao do atuador
      rightDistance = SR04(Trig_PIN, Echo_PIN);//SR04();  // executa etapa do firmware do robo
      delay(200);  // aguarda estabilizacao/temporizacao do atuador
      if (rightDistance > 15)  // decisao condicional do comportamento autonomo
      {  // executa etapa do firmware do robo
        continue;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
      else if(OA_mark==0)  // decisao condicional do comportamento autonomo
      {  // executa etapa do firmware do robo
        OA_mark++;  // executa etapa do firmware do robo
        continue;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
      Motor(Contrarotate, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(600);  // aguarda estabilizacao/temporizacao do atuador
      Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(200);  // aguarda estabilizacao/temporizacao do atuador
      leftDistance = SR04(Trig_PIN, Echo_PIN);//SR04();  // executa etapa do firmware do robo
      delay(200);  // aguarda estabilizacao/temporizacao do atuador

      if (rightDistance > leftDistance) {  // decisao condicional do comportamento autonomo
        Motor(Backward, speeds-70);  // aciona tracao Mecanum no modo/velocidade indicados
        delay(500);  // aguarda estabilizacao/temporizacao do atuador
        Motor(Clockwise, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
        delay(500);  // aguarda estabilizacao/temporizacao do atuador
        OA_mark=0;  // executa etapa do firmware do robo
        continue;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
      else if (rightDistance < leftDistance) {  // decisao condicional do comportamento autonomo
        while (leftDistance < 25) {  // mantem o modo autonomo ate trocar de modo
          Motor(Contrarotate, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          delay(200);  // aguarda estabilizacao/temporizacao do atuador
          Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
          delay(200);  // aguarda estabilizacao/temporizacao do atuador
          leftDistance = SR04(Trig_PIN, Echo_PIN);//SR04();  // executa etapa do firmware do robo
          delay(200);  // aguarda estabilizacao/temporizacao do atuador
          
        }  // executa etapa do firmware do robo
        Motor(Contrarotate, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
        delay(100);  // aguarda estabilizacao/temporizacao do atuador
        OA_mark=0;  // executa etapa do firmware do robo
        
        continue;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
    }  // executa etapa do firmware do robo
    else  // executa etapa do firmware do robo
    {  // executa etapa do firmware do robo
      Motor(Forward, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void model3_func()      // follow model  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  MOTORservo.write(90);  // comanda o servo pan-tilt da camera
  UT_distance = SR04(Trig_PIN, Echo_PIN);  // executa etapa do firmware do robo
  Serial.println(UT_distance);  // envia telemetria ao Monitor Serial
  if (UT_distance < 15)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Backward, speeds-50);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
  else if (15 <= UT_distance && UT_distance <= 20)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
  else if (20 <= UT_distance && UT_distance <= 25)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, speeds-70);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
  else if (25 <= UT_distance && UT_distance <= 50)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, speeds-30);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
  else  // executa etapa do firmware do robo
  {  // executa etapa do firmware do robo
    Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void model4_func()      // tracking model  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  MOTORservo.write(90);  // comanda o servo pan-tilt da camera
  Left_Tra_Value = analogRead(LEFT_LINE_TRACJING);  // le o sensor reflexivo IR da pista (linha)
  Center_Tra_Value = analogRead(CENTER_LINE_TRACJING);  // le o sensor reflexivo IR da pista (linha)
  Right_Tra_Value = analogRead(right_LINE_TRACJING);  // le o sensor reflexivo IR da pista (linha)
  if (Left_Tra_Value > Black_Line && Center_Tra_Value <= Black_Line && Right_Tra_Value > Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, 180);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, 130);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value < Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Clockwise, 220);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Clockwise, 160);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value >= Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Contrarotate, 160);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Contrarotate, 220);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, 130);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void Servo_Move()  //servo  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  MOTORservo.write(angle);  // comanda o servo pan-tilt da camera
  if (angle >= 180) angle = 180;  // decisao condicional do comportamento autonomo
  if (angle <= 1) angle = 1;  // decisao condicional do comportamento autonomo
  delay(10);  // aguarda estabilizacao/temporizacao do atuador
}  // executa etapa do firmware do robo

void Motor(int Dir, int Speed)      // motor drive  // aciona tracao Mecanum no modo/velocidade indicados
{  // executa etapa do firmware do robo
  digitalWrite(EN_PIN, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
  analogWrite(PWM1_PIN, Speed);  // gera PWM com duty proporcional a velocidade
  analogWrite(PWM2_PIN, Speed);  // gera PWM com duty proporcional a velocidade

  digitalWrite(STCP_PIN, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
  shiftOut(DATA_PIN, SHCP_PIN, MSBFIRST, Dir);  // desloca 8 bits ao 74HC595 controlando os 4 motores
  digitalWrite(STCP_PIN, HIGH);  // escreve nivel logico ALTO/BAIXO no pino digital
}  // executa etapa do firmware do robo

float SR04(int Trig, int Echo)      // ultrasonic measured distance  // executa etapa do firmware do robo
{  // executa etapa do firmware do robo
  digitalWrite(Trig, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
  delayMicroseconds(2);  // aguarda estabilizacao/temporizacao do atuador
  digitalWrite(Trig, HIGH);  // escreve nivel logico ALTO/BAIXO no pino digital
  delayMicroseconds(10);  // aguarda estabilizacao/temporizacao do atuador
  digitalWrite(Trig, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
  float distance = pulseIn(Echo, HIGH) / 58.00;  // mede largura do eco ultrassonico para calcular distancia
  delay(10);  // aguarda estabilizacao/temporizacao do atuador

  return distance;  // retorna valor calculado ao chamador
}  // executa etapa do firmware do robo

void RXpack_func()  //Receive data  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  if (Serial.available() > 0)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    delay(1);                                           // delay 1MS  // aguarda estabilizacao/temporizacao do atuador
    if (Serial.readBytes(RX_package, 4))  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
      if (RX_package[0] == 0xAB && RX_package[3] == 0xFF)     // The header and tail of the packet are verified  // decisao condicional do comportamento autonomo
      {  // executa etapa do firmware do robo
        //Serial.write(RX_package, 4);
        Model = RX_package[1];  // executa etapa do firmware do robo
        val = RX_package[2];  // executa etapa do firmware do robo
        if (Model == Speed)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          speeds = val;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        else if (Model == Model1)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          model_var = 0;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        else if (Model == Model2)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          model_var = 1;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        else if (Model == Model3)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          model_var = 2;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        else if (Model == Model4)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          model_var = 3;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        else if (Model == Servo)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          angle = val;  // executa etapa do firmware do robo
          model_var = 4;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
    }  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

Gravação e teste (o que você deve ver)

Desconecte a UART, selecione Arduino UNO e a porta COM, grave e observe sucesso na IDE. Desplugue o USB, instale as 18650, coloque em área livre e ligue a chave. Resultado esperado descrito na teoria de cada modo; divergência indica fiação, bateria ou limiar — ver Troubleshooting.

💡 Dica: valide com o Monitor Serial em 9600/115200 bps conforme o sketch antes de culpar o hardware.

⚠️ Atenção: uploads com a UART conectada falham por contenção do RX/TX; desplugue sempre.

⛔ Perigo: robô em movimento sobre a bancada cai e quebra a câmera; teste sempre no chão.

Lição 5.2 — Câmera WiFi Web lado ESP32-CAM (5.2_ESP32Cam_WIFI_Web)

A ESP32-CAM cria o AP KUONGSHUN-AD176, inicializa a OV2640 em SVGA com qualidade 10–12, corrige orientação com set_vflip/hmirror e sobe o servidor de streaming mais a ponte UART2 (GPIO14/13) com o UNO. A ESP32-CAM opera em modo AP — access point — criando a rede KUONGSHUN-AD176 com senha 12345678 e IP fixo 192.168.4.1192.168.4.1. O video usa MJPEG sobre HTTP — motion JPEG over hypertext transfer protocol — com multipart x-mixed-replace, onde cada frame JPEG e delimitado por boundary e empurrado em chunked encoding. A taxa util aproximada e:

R≈f⋅Setframe=SRef+tcodR \approx f \cdot S \qquad \text{e} \qquad t_{frame} = \frac{S}{R_{ef}} + t_{cod}

onde RR e o bitrate, ff o framerate, SS o tamanho medio do JPEG e tcodt_{cod} o tempo de compressao. SVGA (800×600800 \times 600) a qualidade 1010–1212 equilibra nitidez e latencia; UXGA trava o stream por esgotar PSRAM e banda. O enlace de comando UNO ↔\leftrightarrow ESP32-CAM usa UART a 115200 bps115200\,\text{bps} (8N18N1), com pacotes de 44 bytes (AB modelo valor FF) no modo Web e quadros FF 55 ... no modo APP, ambos com timeout de 10 ms10\,\text{ms}. A potencia de TX em 19,5 dBm19{,}5\,\text{dBm} maximiza alcance indoor a custa de consumo, por isso video so e estavel com bateria cheia. O canal fixo 55 reduz interferencia com roteadores domesticos.

ItemQtdPapel no ensaio
ESP32-CAM + OV26401AP, câmera e ponte serial
UNO com firmware 5.11executor dos comandos
Celular/PC no AP1navegador em 192.168.4.1
Interface web do AD176 em 192.168.4.1

Código real 5.2_ESP32Cam_WIFI_Web.ino comentado linha a linha

📦 Bibliotecas desta lição: WiFi, esp_camera, esp_system, soc/soc.h, soc/rtc_cntl_reg.h — todas embutidas no pacote ESP32 2.0.12, nada a baixar.

  • Instalação: nenhuma. Exige o instalador esp32_package_2.0.12_arduinome.exe do fabricante aplicado (Etapa 2 da Preparação) com a placa ESP32 Dev Module selecionada.
  • Conferência: Arquivo > Exemplos > ESP32 > Camera > CameraWebServer deve abrir e compilar sem No such file or directory. Com núcleo 3.x a compilação quebra (ledcSetup removido) — volte ao 2.0.12.
#include "esp_camera.h"  // embutida no núcleo ESP32 2.0.12, nada a baixar
#include <WiFi.h>  // embutida no núcleo ESP32 2.0.12, nada a baixar
#include "soc/soc.h"  // embutida no núcleo ESP32 2.0.12, nada a baixar
#include "soc/rtc_cntl_reg.h"  // embutida no núcleo ESP32 2.0.12, nada a baixar

#define CAMERA_MODEL_AI_THINKER  // define constante de pino/mapa de hardware

#define LED   4  // define constante de pino/mapa de hardware
#define RXD2 14  // define constante de pino/mapa de hardware
#define TXD2 13  // define constante de pino/mapa de hardware

void CameraWebServer_init();  // configura/inicializa a camera OV2640

WiFiServer server(100);  // configura rede WiFi AP do robo para video e comando


extern int gpLed =  4; // Light  // executa etapa do firmware do robo

void setup()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // prevent brownouts by silencing them  // executa etapa do firmware do robo

  Serial.begin(115200);  // inicializa UART para debug e enlace com ESP32-CAM
  Serial2.begin(115200, SERIAL_8N1, RXD2, TXD2);  // executa etapa do firmware do robo
  Serial.setDebugOutput(true);  // executa etapa do firmware do robo
  Serial.println();  // envia telemetria ao Monitor Serial

  CameraWebServer_init();  // configura/inicializa a camera OV2640

  pinMode(gpLed, OUTPUT); //Light  // configura o pino como entrada ou saida digital
  ledcSetup(7, 5000, 8);  // configura PWM do LED/flash da ESP32-CAM
  ledcAttachPin(gpLed, 7);  //pin4 is LED  // configura PWM do LED/flash da ESP32-CAM

  server.begin();  // gerencia servidor HTTP/TCP de video e comandos

  for (int i = 0; i < 5; i++)   // laco de varredura incremental do ensaio
  {  // executa etapa do firmware do robo
    ledcWrite(7, 10); // flash led  // configura PWM do LED/flash da ESP32-CAM
    delay(50);  // aguarda estabilizacao/temporizacao do atuador
    ledcWrite(7, 0);  // configura PWM do LED/flash da ESP32-CAM
    delay(50);  // aguarda estabilizacao/temporizacao do atuador
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void loop()   // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  //delay(1000);
  //Serial.printf("RSSi: %ld dBm\n", WiFi.RSSI());
}  // executa etapa do firmware do robo

Código real CameraWebServer.cpp (Web) comentado

📦 Bibliotecas desta lição: as mesmas do sketch 5.2 (núcleo ESP32 2.0.12), nada a baixar — este .cpp compila junto ao .ino na mesma pasta.

#include "esp_system.h"  // embutida no núcleo ESP32 2.0.12, nada a baixar
#include "esp_camera.h"  // embutida no núcleo ESP32 2.0.12, nada a baixar
#include <WiFi.h>  // embutida no núcleo ESP32 2.0.12, nada a baixar

const char *ssid = "KUONGSHUN-AD176";  // executa etapa do firmware do robo
const char *password = "12345678";  // executa etapa do firmware do robo


String wifi_name;  // executa etapa do firmware do robo

#define PWDN_GPIO_NUM     32  // define constante de pino/mapa de hardware
#define RESET_GPIO_NUM    -1  // define constante de pino/mapa de hardware
#define XCLK_GPIO_NUM      0  // define constante de pino/mapa de hardware
#define SIOD_GPIO_NUM     26  // define constante de pino/mapa de hardware
#define SIOC_GPIO_NUM     27  // define constante de pino/mapa de hardware
#define Y9_GPIO_NUM       35  // define constante de pino/mapa de hardware
#define Y8_GPIO_NUM       34  // define constante de pino/mapa de hardware
#define Y7_GPIO_NUM       39  // define constante de pino/mapa de hardware
#define Y6_GPIO_NUM       36  // define constante de pino/mapa de hardware
#define Y5_GPIO_NUM       21  // define constante de pino/mapa de hardware
#define Y4_GPIO_NUM       19  // define constante de pino/mapa de hardware
#define Y3_GPIO_NUM       18  // define constante de pino/mapa de hardware
#define Y2_GPIO_NUM        5  // define constante de pino/mapa de hardware
#define VSYNC_GPIO_NUM    25  // define constante de pino/mapa de hardware
#define HREF_GPIO_NUM     23  // define constante de pino/mapa de hardware
#define PCLK_GPIO_NUM     22  // define constante de pino/mapa de hardware

void startCameraServer();  // configura/inicializa a camera OV2640
void CameraWebServer_init()  // configura/inicializa a camera OV2640
{  // executa etapa do firmware do robo
  camera_config_t config;  // configura/inicializa a camera OV2640
  config.ledc_channel = LEDC_CHANNEL_0;  // configura PWM do LED/flash da ESP32-CAM
  config.ledc_timer = LEDC_TIMER_0;  // configura PWM do LED/flash da ESP32-CAM
  config.pin_d0 = Y2_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d1 = Y3_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d2 = Y4_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d3 = Y5_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d4 = Y6_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d5 = Y7_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d6 = Y8_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d7 = Y9_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_xclk = XCLK_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_pclk = PCLK_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_vsync = VSYNC_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_href = HREF_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_sccb_sda = SIOD_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_sccb_scl = SIOC_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_pwdn = PWDN_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_reset = RESET_GPIO_NUM;  // executa etapa do firmware do robo
  config.xclk_freq_hz = 20000000;  // executa etapa do firmware do robo
  config.frame_size = FRAMESIZE_UXGA;  // executa etapa do firmware do robo
  config.pixel_format = PIXFORMAT_JPEG; // for streaming  // executa etapa do firmware do robo
  //config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;  // configura/inicializa a camera OV2640
  config.fb_location = CAMERA_FB_IN_PSRAM;  // configura/inicializa a camera OV2640
  config.jpeg_quality = 12;  // executa etapa do firmware do robo
  config.fb_count = 1;  // executa etapa do firmware do robo
  
  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  //                      for larger pre-allocated frame buffer.
  if(config.pixel_format == PIXFORMAT_JPEG){  // decisao condicional do comportamento autonomo
    if(psramFound()){  // decisao condicional do comportamento autonomo
      config.jpeg_quality = 10;  // executa etapa do firmware do robo
      config.fb_count = 2;  // executa etapa do firmware do robo
      config.grab_mode = CAMERA_GRAB_LATEST;  // configura/inicializa a camera OV2640
    } else {  // executa etapa do firmware do robo
      // Limit the frame size when PSRAM is not available
      config.frame_size = FRAMESIZE_SVGA;  // executa etapa do firmware do robo
      config.fb_location = CAMERA_FB_IN_DRAM;  // configura/inicializa a camera OV2640
    }  // executa etapa do firmware do robo
  } else {  // executa etapa do firmware do robo
    // Best option for face detection/recognition
    config.frame_size = FRAMESIZE_240X240;  // executa etapa do firmware do robo
#if CONFIG_IDF_TARGET_ESP32S3  // executa etapa do firmware do robo
    config.fb_count = 2;  // executa etapa do firmware do robo
#endif  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo
  // camera init
  esp_err_t err = esp_camera_init(&config);  // configura/inicializa a camera OV2640
  if (err != ESP_OK)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Serial.printf("Camera init failed with error 0x%x", err);  // envia telemetria ao Monitor Serial
    return;  // retorna valor calculado ao chamador
  }  // executa etapa do firmware do robo
  sensor_t *s = esp_camera_sensor_get();  // configura/inicializa a camera OV2640
  //drop down frame size for higher initial frame rate
  //s->set_framesize(s, FRAMESIZE_SXGA); //Video sample rate:60000                 #9 (High image quality)  1280x1024
  s->set_framesize(s, FRAMESIZE_SVGA); //Video sample rate:40000                   #7 (Medium image quality)  800x600  // executa etapa do firmware do robo
  //s->set_framesize(s, FRAMESIZE_QVGA); //Video sample rate:10000                #4 (Low image quality)  320x240

  s->set_vflip(s, 1);   //Image Direction Settings(Up/Down)  // executa etapa do firmware do robo
  s->set_hmirror(s, 0); //Image Direction Setting(Left/Right)  // executa etapa do firmware do robo

  WiFi.setTxPower(WIFI_POWER_19_5dBm);  // configura rede WiFi AP do robo para video e comando
  WiFi.mode(WIFI_AP);  // configura rede WiFi AP do robo para video e comando
  WiFi.softAP(ssid, password, 5);  // configura rede WiFi AP do robo para video e comando
  startCameraServer();  // configura/inicializa a camera OV2640
  // WiFi.softAP(ssid, password);
  IPAddress miIP = WiFi.softAPIP();  // configura rede WiFi AP do robo para video e comando
  Serial.print("AP IP address: ");  // envia telemetria ao Monitor Serial
  Serial.println(miIP); //probar 192.168.4.1  // envia telemetria ao Monitor Serial



}  // executa etapa do firmware do robo

Gravação e teste (o que você deve ver)

Com a UART desplugada, grave o 5.1 no UNO (Arduino UNO) e o 5.2 na CAM (ESP32 Dev Module). Reconecte a UART, ligue com baterias, conecte-se ao AP KUONGSHUN-AD176 com 12345678, abra 192.168.4.1 e opere os 11 botões de direção, 4 modos, sliders de servo/velocidade/farol e o stream MJPEG. SSID, senha, qualidade (SVGA/SXGA/QVGA) e vflip/hmirror são ajustáveis no CameraWebServer.cpp.

💡 Dica: vídeo travando indica bateria fraca ou qualidade alta demais; volte a SVGA/qualidade 12.

⚠️ Atenção: núcleo ESP32 diferente de 2.0.12 quebra ledcSetup e a câmera; repita a instalação pinada.

⛔ Perigo: não alimente a tração pelo USB do PC; a corrente de estol queima porta e cabo.

Lição 6.1 — Multifunção APP lado Arduino (6.1_Arduino_All_APP)

O UNO interpreta quadros FF 55 ... do aplicativo com campos de ação, dispositivo e valor, roteando D-pad omnidirecional, servo, farol e velocidade para os mesmos atuadores do modo Web, com timeout que para o robô ao perder o cliente. As rodas Mecanum possuem roletes a 45∘45^{\circ} em torno do cubo. Cada roda gera forca perpendicular ao eixo do rolete, decomponivel em componentes longitudinal FxF_x e lateral FyF_y. Com quatro rodas independentes em configuracao X, a soma vetorial permite translacao omnidirecional sem mudar a orientacao do chassi. O principio formal da cinematica direta do 4WD Mecanum, com semi-distancias LxL_x e LyL_y do centro, raio rr e velocidades angulares ω1…ω4\omega_1 \ldots \omega_4, e: O servo SG90 e comandado por PPM com periodo de 20 ms20\,\text{ms}. A largura do pulso codifica o angulo:

[vxvyωz]=r4[1111−111−1−1Lx+Ly1Lx+Ly−1Lx+Ly1Lx+Ly][ω1ω2ω3ω4]\begin{bmatrix} v_x \\ v_y \\ \omega_z \end{bmatrix} = \frac{r}{4} \begin{bmatrix} 1 & 1 & 1 & 1 \\ -1 & 1 & 1 & -1 \\ -\frac{1}{L_x+L_y} & \frac{1}{L_x+L_y} & -\frac{1}{L_x+L_y} & \frac{1}{L_x+L_y} \end{bmatrix} \begin{bmatrix} \omega_1 \\ \omega_2 \\ \omega_3 \\ \omega_4 \end{bmatrix}

onde vxv_x e a velocidade longitudinal, vyv_y a lateral e ωz\omega_z a taxa de guinada. A decomposicao por rolete explica os codigos decimais da tabela do fabricante: cada byte de 8 bits mapeia os 8 terminais de ponte H dos quatro motores via 74HC595, de modo que frentes paralelas somam FxF_x (marcha 163/92) e oposicoes simetricas somam FyF_y (translacao 106/149), enquanto diagonais produzem resultante a 45∘45^{\circ} (34/129/72/20) e giros puros cancelam translacao e somam momento (83/172). A velocidade linear de cada roda segue v=ωrv = \omega r, e a forca de tracao disponivel e limitada pelo atrito Fmax=μNF_{max} = \mu N, por isso piso liso reduz derrapagem dos roletes e melhora a lateralidade. O driver usa dois canais PWM (55 e 66) para energia e o registrador de deslocamento para direcao, separando potencia e logica como em toda ponte H dupla.

ItemQtdPapel no ensaio
UNO + atuadores/sensores1execução dos comandos APP
ESP32-CAM com 6.21ponte TCP>UART
App KUONGSHUN1D-pad, sliders e modos
Multifunção APP lado Arduino (6.1_Arduino_All_APP) bancada de teste
SinalPinoObservação
PWMD5/D6Velocidade dos motores
SHCP/EN/DATA/STCPD2/D7/D8/D4Direção via 74HC595
ServoD9Pan-tilt da câmera
TRIG/ECHOD12/D13Ultrassom
LinhaA0/A1/A2Trio IR
UARTTX/RX 115200Enlace com ESP32-CAM (desplugado no upload)

Código real 6.1_Arduino_All_APP.ino comentado linha a linha

📦 Bibliotecas desta lição: Servo — a mesma da Lição 2, nada a baixar. Se Arquivo > Exemplos > Servo > Sweep compila, siga direto ao código.

//www.kuongshun.com

#include    <Servo.h>  // instalada pelo quadro "Bibliotecas desta lição" (Servo.zip do fabricante)

#define MOTOR_PIN           9  // define constante de pino/mapa de hardware
#define PWM1_PIN            5  // define constante de pino/mapa de hardware
#define PWM2_PIN            6  // define constante de pino/mapa de hardware
#define SHCP_PIN            2                  // The displacement of the clock  // define constante de pino/mapa de hardware
#define EN_PIN              7                  // Can make control  // define constante de pino/mapa de hardware
#define DATA_PIN            8                  // Serial data  // define constante de pino/mapa de hardware
#define STCP_PIN            4                  // Memory register clock              // define constante de pino/mapa de hardware
#define Trig_PIN            12  // define constante de pino/mapa de hardware
#define Echo_PIN            13  // define constante de pino/mapa de hardware
#define LEFT_LINE_TRACJING      A2  // define constante de pino/mapa de hardware
#define CENTER_LINE_TRACJING    A1  // define constante de pino/mapa de hardware
#define right_LINE_TRACJING     A0  // define constante de pino/mapa de hardware

Servo MOTORservo;  // comanda o servo pan-tilt da camera

const int Forward       = 163;                 // forward  // executa etapa do firmware do robo
const int Backward      = 92;                  // back  // executa etapa do firmware do robo
const int Turn_Left     = 106;                 // left translation  // executa etapa do firmware do robo
const int Turn_Right    = 149;                 // Right translation  // executa etapa do firmware do robo
const int Top_Left      = 34;                  // Upper left mobile  // executa etapa do firmware do robo
const int Bottom_Left   = 72;                  // Lower left mobile  // executa etapa do firmware do robo
const int Top_Right     = 129;                 // Upper right mobile  // executa etapa do firmware do robo
const int Bottom_Right  = 20;                  // The lower right move  // executa etapa do firmware do robo
const int Stop          = 0;                   // stop  // executa etapa do firmware do robo
const int Contrarotate  = 83;                  // Counterclockwise rotation  // executa etapa do firmware do robo
const int Clockwise     = 172;                 // Rotate clockwise  // executa etapa do firmware do robo
const int Model1        = 3;                  // model1  // executa etapa do firmware do robo
const int Model2        = 6;                  // model2  // executa etapa do firmware do robo
const int Model3        = 7;                  // model3  // executa etapa do firmware do robo
const int Model4        = 4;                  // model4  // executa etapa do firmware do robo
const int Model1_Ctrl   = 1;  // executa etapa do firmware do robo

const int Speed         = 13;  // executa etapa do firmware do robo
const int Servo         = 2;  // executa etapa do firmware do robo
const int Motor_Move    = 12;                 // servo turn left  // executa etapa do firmware do robo
const int LED           = 5;                 // servo turn right  // executa etapa do firmware do robo

byte dataLen, index_a = 0;  // executa etapa do firmware do robo
char buffer[52];  // executa etapa do firmware do robo
unsigned char prevc=0;  // executa etapa do firmware do robo
bool isStart = false;  // executa etapa do firmware do robo
bool ED_client = true;  // executa etapa do firmware do robo
bool WA_en = false;  // executa etapa do firmware do robo

int Left_Tra_Value;  // executa etapa do firmware do robo
int Center_Tra_Value;  // executa etapa do firmware do robo
int Right_Tra_Value;  // executa etapa do firmware do robo
int Black_Line = 400;  // executa etapa do firmware do robo
int speeds = 250;  // executa etapa do firmware do robo
int leftDistance = 0;  // executa etapa do firmware do robo
int middleDistance = 0;  // executa etapa do firmware do robo
int rightDistance = 0;  // executa etapa do firmware do robo
int action = 0;  // executa etapa do firmware do robo



byte RX_package[17] = {0};  // executa etapa do firmware do robo
uint16_t angle = 90;  // executa etapa do firmware do robo
byte Model = Stop;  // executa etapa do firmware do robo
byte val = 0;  // executa etapa do firmware do robo
int model_var = 0;  // executa etapa do firmware do robo
char device = 0;  // executa etapa do firmware do robo
int UT_distance = 0;  // executa etapa do firmware do robo
int OA_mark=0;  // executa etapa do firmware do robo
void setup()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  Serial.setTimeout(10);  // executa etapa do firmware do robo
  Serial.begin(115200);  // inicializa UART para debug e enlace com ESP32-CAM

  MOTORservo.attach(MOTOR_PIN);  // comanda o servo pan-tilt da camera

  pinMode(SHCP_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(EN_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(DATA_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(STCP_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(PWM1_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(PWM2_PIN, OUTPUT);  // configura o pino como entrada ou saida digital

  pinMode(Trig_PIN, OUTPUT);  // configura o pino como entrada ou saida digital
  pinMode(Echo_PIN, INPUT);  // configura o pino como entrada ou saida digital

  pinMode(LEFT_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital
  pinMode(CENTER_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital
  pinMode(right_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital

  MOTORservo.write(angle);  // comanda o servo pan-tilt da camera

  Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
}  // executa etapa do firmware do robo

unsigned char readBuffer(int index_r)  // executa etapa do firmware do robo
{  // executa etapa do firmware do robo
  return buffer[index_r];   // retorna valor calculado ao chamador
}  // executa etapa do firmware do robo

void writeBuffer(int index_w,unsigned char c)  // atualiza atuador/saida com o valor indicado
{  // executa etapa do firmware do robo
  buffer[index_w]=c;  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void loop()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  RXpack_func();  // executa etapa do firmware do robo
  switch (model_var)  // seleciona modo/comando recebido via serial/rede
  {  // executa etapa do firmware do robo
    case 0:  // seleciona modo/comando recebido via serial/rede
      model1_func(device,val);  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
    case 1:  // seleciona modo/comando recebido via serial/rede
      model2_func();      // OA model  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
    case 2:  // seleciona modo/comando recebido via serial/rede
      model3_func();      // follow model  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
    case 3:  // seleciona modo/comando recebido via serial/rede
      model4_func();      // Tracking model  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo

}  // executa etapa do firmware do robo



void model1_func(byte device, byte values)   // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  switch (device) {  // seleciona modo/comando recebido via serial/rede
    case Motor_Move:  // seleciona modo/comando recebido via serial/rede
      switch (values) {  // seleciona modo/comando recebido via serial/rede
        case 0x00:  // seleciona modo/comando recebido via serial/rede
          Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x01:  // seleciona modo/comando recebido via serial/rede
          Motor(Forward, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x02:  // seleciona modo/comando recebido via serial/rede
          Motor(Backward, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x03:  // seleciona modo/comando recebido via serial/rede
          Motor(Turn_Left, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x04:  // seleciona modo/comando recebido via serial/rede
          Motor(Turn_Right, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x05:  // seleciona modo/comando recebido via serial/rede
          Motor(Top_Left, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x07:  // seleciona modo/comando recebido via serial/rede
          Motor(Top_Right, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x06:  // seleciona modo/comando recebido via serial/rede
          Motor(Bottom_Left, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x08:  // seleciona modo/comando recebido via serial/rede
          Motor(Bottom_Right, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x0A:  // seleciona modo/comando recebido via serial/rede
          Motor(Clockwise, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
        case 0x09:  // seleciona modo/comando recebido via serial/rede
          Motor(Contrarotate, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          break;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
    case Servo:  // seleciona modo/comando recebido via serial/rede
      angle=values;  // executa etapa do firmware do robo
      if (angle >= 180) angle = 180;  // decisao condicional do comportamento autonomo
      if (angle <= 1) angle = 1;  // decisao condicional do comportamento autonomo
      MOTORservo.write(angle);  // comanda o servo pan-tilt da camera
      //delay(5);
      break;  // executa etapa do firmware do robo
    case LED:  // seleciona modo/comando recebido via serial/rede
      //Serial.write(RX_package, 17);
      break;  // executa etapa do firmware do robo
    case Speed:  // seleciona modo/comando recebido via serial/rede
      speeds=values;  // executa etapa do firmware do robo
      break;  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void model2_func()      // OA  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  while (model_var == 1) {  // mantem o modo autonomo ate trocar de modo
    RXpack_func();  // executa etapa do firmware do robo
    middleDistance = SR04(Trig_PIN, Echo_PIN);  // executa etapa do firmware do robo
    if (middleDistance <= 15)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
      Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(100);  // aguarda estabilizacao/temporizacao do atuador
      Motor(Backward, speeds-70);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(100);  // aguarda estabilizacao/temporizacao do atuador
      Motor(Clockwise, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(200);  // aguarda estabilizacao/temporizacao do atuador
      Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(200);  // aguarda estabilizacao/temporizacao do atuador
      rightDistance = SR04(Trig_PIN, Echo_PIN);//SR04();  // executa etapa do firmware do robo
      delay(200);  // aguarda estabilizacao/temporizacao do atuador
      if (rightDistance > 15)  // decisao condicional do comportamento autonomo
      {  // executa etapa do firmware do robo
        continue;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
      else if(OA_mark==0)  // decisao condicional do comportamento autonomo
      {  // executa etapa do firmware do robo
        OA_mark++;  // executa etapa do firmware do robo
        continue;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
      Motor(Contrarotate, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(600);  // aguarda estabilizacao/temporizacao do atuador
      Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
      delay(200);  // aguarda estabilizacao/temporizacao do atuador
      leftDistance = SR04(Trig_PIN, Echo_PIN);//SR04();  // executa etapa do firmware do robo
      delay(200);  // aguarda estabilizacao/temporizacao do atuador

      if (rightDistance > leftDistance) {  // decisao condicional do comportamento autonomo
        Motor(Backward, speeds-70);  // aciona tracao Mecanum no modo/velocidade indicados
        delay(500);  // aguarda estabilizacao/temporizacao do atuador
        Motor(Clockwise, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
        delay(500);  // aguarda estabilizacao/temporizacao do atuador
        OA_mark=0;  // executa etapa do firmware do robo
        continue;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
      else if (rightDistance < leftDistance) {  // decisao condicional do comportamento autonomo
        while (leftDistance < 25) {  // mantem o modo autonomo ate trocar de modo
          Motor(Contrarotate, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
          delay(200);  // aguarda estabilizacao/temporizacao do atuador
          Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
          delay(200);  // aguarda estabilizacao/temporizacao do atuador
          leftDistance = SR04(Trig_PIN, Echo_PIN);//SR04();  // executa etapa do firmware do robo
          delay(200);  // aguarda estabilizacao/temporizacao do atuador
          
        }  // executa etapa do firmware do robo
        Motor(Contrarotate, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
        delay(100);  // aguarda estabilizacao/temporizacao do atuador
        OA_mark=0;  // executa etapa do firmware do robo
        
        continue;  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
    }  // executa etapa do firmware do robo
    else  // executa etapa do firmware do robo
    {  // executa etapa do firmware do robo
      Motor(Forward, speeds);  // aciona tracao Mecanum no modo/velocidade indicados
    }  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void model3_func()      // follow model  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  MOTORservo.write(90);  // comanda o servo pan-tilt da camera
  UT_distance = SR04(Trig_PIN, Echo_PIN);  // executa etapa do firmware do robo
  if (UT_distance < 15)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Backward, speeds-50);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
  else if (15 <= UT_distance && UT_distance <= 20)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
  else if (20 <= UT_distance && UT_distance <= 25)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, speeds-70);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
  else if (25 <= UT_distance && UT_distance <= 50)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, speeds-30);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
  else  // executa etapa do firmware do robo
  {  // executa etapa do firmware do robo
    Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void model4_func()      // tracking model  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  MOTORservo.write(90);  // comanda o servo pan-tilt da camera
  Left_Tra_Value = analogRead(LEFT_LINE_TRACJING);  // le o sensor reflexivo IR da pista (linha)
  Center_Tra_Value = analogRead(CENTER_LINE_TRACJING);  // le o sensor reflexivo IR da pista (linha)
  Right_Tra_Value = analogRead(right_LINE_TRACJING);  // le o sensor reflexivo IR da pista (linha)
  if (Left_Tra_Value > Black_Line && Center_Tra_Value <= Black_Line && Right_Tra_Value > Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, 180);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, 130);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value < Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Clockwise, 220);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Clockwise, 160);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value >= Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Contrarotate, 160);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Contrarotate, 220);  // aciona tracao Mecanum no modo/velocidade indicados
  }   // executa etapa do firmware do robo
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line)   // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Motor(Forward, 130);  // aciona tracao Mecanum no modo/velocidade indicados
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo



void Motor(int Dir, int Speed)      // motor drive  // aciona tracao Mecanum no modo/velocidade indicados
{  // executa etapa do firmware do robo
  digitalWrite(EN_PIN, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
  analogWrite(PWM1_PIN, Speed);  // gera PWM com duty proporcional a velocidade
  analogWrite(PWM2_PIN, Speed);  // gera PWM com duty proporcional a velocidade

  digitalWrite(STCP_PIN, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
  shiftOut(DATA_PIN, SHCP_PIN, MSBFIRST, Dir);  // desloca 8 bits ao 74HC595 controlando os 4 motores
  digitalWrite(STCP_PIN, HIGH);  // escreve nivel logico ALTO/BAIXO no pino digital
}  // executa etapa do firmware do robo

float SR04(int Trig, int Echo)      // ultrasonic measured distance  // executa etapa do firmware do robo
{  // executa etapa do firmware do robo
  digitalWrite(Trig, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
  delayMicroseconds(2);  // aguarda estabilizacao/temporizacao do atuador
  digitalWrite(Trig, HIGH);  // escreve nivel logico ALTO/BAIXO no pino digital
  delayMicroseconds(10);  // aguarda estabilizacao/temporizacao do atuador
  digitalWrite(Trig, LOW);  // escreve nivel logico ALTO/BAIXO no pino digital
  float distance = pulseIn(Echo, HIGH) / 58.00;  // mede largura do eco ultrassonico para calcular distancia
  delay(10);  // aguarda estabilizacao/temporizacao do atuador

  return distance;  // retorna valor calculado ao chamador
}  // executa etapa do firmware do robo

void parseData()  // define rotina de atuacao/leitura do robo
{   // executa etapa do firmware do robo
    isStart = false;  // executa etapa do firmware do robo
    action = readBuffer(9);  // executa etapa do firmware do robo
    device = readBuffer(10);  // executa etapa do firmware do robo
    val = readBuffer(12);  // executa etapa do firmware do robo
    switch (action)  // seleciona modo/comando recebido via serial/rede
    {  // executa etapa do firmware do robo
        case Model1_Ctrl:  // seleciona modo/comando recebido via serial/rede
            //callOK_Len01();
            model_var = 0;  // executa etapa do firmware do robo
            break;  // executa etapa do firmware do robo
        case Model1:  // seleciona modo/comando recebido via serial/rede
            //callOK_Len01();
            model_var = 0;  // executa etapa do firmware do robo
            Motor(Stop, 0);  // aciona tracao Mecanum no modo/velocidade indicados
            break;  // executa etapa do firmware do robo
        case Model2:  // seleciona modo/comando recebido via serial/rede
            //callOK_Len01();
            model_var = 1;  // executa etapa do firmware do robo
            break;  // executa etapa do firmware do robo
        case Model3:  // seleciona modo/comando recebido via serial/rede
            //callOK_Len01();
            model_var = 2;  // executa etapa do firmware do robo
            break;  // executa etapa do firmware do robo
        case Model4:  // seleciona modo/comando recebido via serial/rede
            //callOK_Len01();
            model_var = 3;  // executa etapa do firmware do robo
            break;  // executa etapa do firmware do robo
        default:break;  // executa etapa do firmware do robo
    }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

void RXpack_func()  //Receive data  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
    if(Serial.available() > 0)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
      unsigned char c = Serial.read()&0xff;  // executa etapa do firmware do robo
      Serial.write(c);  // atualiza atuador/saida com o valor indicado
      if(c==0x55&&isStart==false)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          if(prevc==0xff)  // decisao condicional do comportamento autonomo
          {  // executa etapa do firmware do robo
            index_a=1;  // executa etapa do firmware do robo
            isStart = true;  // executa etapa do firmware do robo
          }  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        else  // executa etapa do firmware do robo
        {  // executa etapa do firmware do robo
          prevc = c;  // executa etapa do firmware do robo
          if(isStart)  // decisao condicional do comportamento autonomo
          {  // executa etapa do firmware do robo
            if(index_a==2)  // decisao condicional do comportamento autonomo
            {  // executa etapa do firmware do robo
            dataLen = c;   // executa etapa do firmware do robo
            }  // executa etapa do firmware do robo
            else if(index_a>2)  // decisao condicional do comportamento autonomo
            {  // executa etapa do firmware do robo
              dataLen--;  // executa etapa do firmware do robo
            }  // executa etapa do firmware do robo
            writeBuffer(index_a,c);  // atualiza atuador/saida com o valor indicado
          }  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        index_a++;  // executa etapa do firmware do robo
        if(index_a>120)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          index_a=0;   // executa etapa do firmware do robo
          isStart=false;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        if(isStart&&dataLen==0&&index_a>3)  // decisao condicional do comportamento autonomo
        {   // executa etapa do firmware do robo
          isStart = false;  // executa etapa do firmware do robo
          parseData();  // executa etapa do firmware do robo
          index_a=0;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
    }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

Gravação e teste (o que você deve ver)

Desconecte a UART, selecione Arduino UNO e a porta COM, grave e observe sucesso na IDE. Desplugue o USB, instale as 18650, coloque em área livre e ligue a chave. Resultado esperado descrito na teoria de cada modo; divergência indica fiação, bateria ou limiar — ver Troubleshooting.

💡 Dica: valide com o Monitor Serial em 9600/115200 bps conforme o sketch antes de culpar o hardware.

⚠️ Atenção: uploads com a UART conectada falham por contenção do RX/TX; desplugue sempre.

⛔ Perigo: robô em movimento sobre a bancada cai e quebra a câmera; teste sempre no chão.

Lição 6.2 — Câmera WiFi APP lado ESP32-CAM (6.2_ESP32Cam_WIFI_APP)

A CAM mantém AP, câmera e streaming, mas troca o protocolo Web pelo servidor TCP na porta 100 com parser FF 55, repasse byte a byte à UART, watchdog de 3 s que injeta parada e controle do flash via dispositivo 0x05. A ESP32-CAM opera em modo AP — access point — criando a rede KUONGSHUN-AD176 com senha 12345678 e IP fixo 192.168.4.1192.168.4.1. O video usa MJPEG sobre HTTP — motion JPEG over hypertext transfer protocol — com multipart x-mixed-replace, onde cada frame JPEG e delimitado por boundary e empurrado em chunked encoding. A taxa util aproximada e:

R≈f⋅Setframe=SRef+tcodR \approx f \cdot S \qquad \text{e} \qquad t_{frame} = \frac{S}{R_{ef}} + t_{cod}

onde RR e o bitrate, ff o framerate, SS o tamanho medio do JPEG e tcodt_{cod} o tempo de compressao. SVGA (800×600800 \times 600) a qualidade 1010–1212 equilibra nitidez e latencia; UXGA trava o stream por esgotar PSRAM e banda. O enlace de comando UNO ↔\leftrightarrow ESP32-CAM usa UART a 115200 bps115200\,\text{bps} (8N18N1), com pacotes de 44 bytes (AB modelo valor FF) no modo Web e quadros FF 55 ... no modo APP, ambos com timeout de 10 ms10\,\text{ms}. A potencia de TX em 19,5 dBm19{,}5\,\text{dBm} maximiza alcance indoor a custa de consumo, por isso video so e estavel com bateria cheia. O canal fixo 55 reduz interferencia com roteadores domesticos.

ItemQtdPapel no ensaio
ESP32-CAM + OV26401AP, vídeo e ponte APP
UNO com firmware 6.11executor do protocolo APP
App KUONGSHUN instalado1cliente de vídeo e comando
Aplicativo KUONGSHUN conectado ao AD176

Código real 6.2_ESP32Cam_WIFI_APP.ino comentado linha a linha

📦 Bibliotecas desta lição: WiFi, esp_camera, esp_system — as mesmas do núcleo ESP32 2.0.12 da Lição 5.2, nada a baixar.

#include <WiFi.h>  // embutida no núcleo ESP32 2.0.12, nada a baixar
#include "esp_camera.h"  // embutida no núcleo ESP32 2.0.12, nada a baixar

WiFiServer server(100);  // configura rede WiFi AP do robo para video e comando

byte Stop[17]={0xff,0x55,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0C,0x00,0x00};  // executa etapa do firmware do robo
byte RX_package[17] = {0};  // executa etapa do firmware do robo
byte dataLen, index_a = 0;  // executa etapa do firmware do robo
char buffer[52];  // executa etapa do firmware do robo
unsigned char prevc=0;  // executa etapa do firmware do robo
bool isStart = false;  // executa etapa do firmware do robo
bool ED_client = true;  // executa etapa do firmware do robo
bool WA_en = false;  // executa etapa do firmware do robo
String sendBuff;  // executa etapa do firmware do robo
String Version = "Firmware Version is 0.12.21";  // executa etapa do firmware do robo
int action = 0;  // executa etapa do firmware do robo
char device = 0;  // executa etapa do firmware do robo
byte val = 0;  // executa etapa do firmware do robo

bool st = false;  // executa etapa do firmware do robo
unsigned long lastDataTimes = 0;  // executa etapa do firmware do robo

#define gpLED  4      // Light  // define constante de pino/mapa de hardware
void CameraWebServer_init();  // configura/inicializa a camera OV2640

void setup()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  Serial.begin(115200);  // inicializa UART para debug e enlace com ESP32-CAM
  //http://192.168.4.1/control?var=framesize&val=3
  //http://192.168.4.1/Test?var=
  CameraWebServer_init();  // configura/inicializa a camera OV2640
  server.begin();  // gerencia servidor HTTP/TCP de video e comandos
  delay(100);  // aguarda estabilizacao/temporizacao do atuador
  pinMode(gpLED, OUTPUT); //Light  // configura o pino como entrada ou saida digital
  ledcSetup(7, 5000, 8);  // configura PWM do LED/flash da ESP32-CAM
  ledcAttachPin(gpLED, 7);  //pin4 is LED  // configura PWM do LED/flash da ESP32-CAM

  for (int i = 0; i < 5; i++)   // laco de varredura incremental do ensaio
  {  // executa etapa do firmware do robo
    ledcWrite(7, 20); // flash led  // configura PWM do LED/flash da ESP32-CAM
    delay(50);  // aguarda estabilizacao/temporizacao do atuador
    ledcWrite(7, 0);  // configura PWM do LED/flash da ESP32-CAM
    delay(50);  // aguarda estabilizacao/temporizacao do atuador
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

unsigned char readBuffer(int index_r)  // executa etapa do firmware do robo
{  // executa etapa do firmware do robo
  return buffer[index_r];   // retorna valor calculado ao chamador
}  // executa etapa do firmware do robo

void writeBuffer(int index_w,unsigned char c)  // atualiza atuador/saida com o valor indicado
{  // executa etapa do firmware do robo
  buffer[index_w]=c;  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo
void parseData()  // define rotina de atuacao/leitura do robo
{   // executa etapa do firmware do robo
    isStart = false;  // executa etapa do firmware do robo
    action = readBuffer(9);  // executa etapa do firmware do robo
    device = readBuffer(10);  // executa etapa do firmware do robo
    val = readBuffer(12);  // executa etapa do firmware do robo
    if (device==0x05)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
      if(val<20)val=0;  // decisao condicional do comportamento autonomo
      ledcWrite(7, val);  // configura PWM do LED/flash da ESP32-CAM
      delay(1);  // aguarda estabilizacao/temporizacao do atuador
    }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo


void loop()  // define rotina de atuacao/leitura do robo
{  // executa etapa do firmware do robo
  WiFiClient client = server.available();  // configura rede WiFi AP do robo para video e comando
  if (client)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    WA_en = true;  // executa etapa do firmware do robo
    ED_client = true;  // executa etapa do firmware do robo
    unsigned long previousMillis = millis();  // 上一个检查时间  // executa etapa do firmware do robo
    const unsigned long timeoutDuration = 3000;  // 超时时间(2秒)  // executa etapa do firmware do robo
    Serial.println("[Client connected]");  // envia telemetria ao Monitor Serial
    while (client.connected())  // mantem o modo autonomo ate trocar de modo
    {  // executa etapa do firmware do robo
     if ((millis() - previousMillis) > timeoutDuration && client.available() == 0 && st==true)  // decisao condicional do comportamento autonomo
      {  // executa etapa do firmware do robo
        break;  // executa etapa do firmware do robo
      }    // executa etapa do firmware do robo
      if (client.available())  // decisao condicional do comportamento autonomo
      {  // executa etapa do firmware do robo
        previousMillis = millis();   // 111111  // executa etapa do firmware do robo
        unsigned char clientBuff = client.read()&0xff;  // executa etapa do firmware do robo
        Serial.write(clientBuff);  // atualiza atuador/saida com o valor indicado

        st = false;         // 111111  // executa etapa do firmware do robo
        if (clientBuff == 200)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          st = true;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo

        if(clientBuff==0x55&&isStart==false)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          if(prevc==0xff)  // decisao condicional do comportamento autonomo
          {  // executa etapa do firmware do robo
            index_a=1;  // executa etapa do firmware do robo
            isStart = true;  // executa etapa do firmware do robo
          }  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        else  // executa etapa do firmware do robo
        {  // executa etapa do firmware do robo
          prevc = clientBuff;  // executa etapa do firmware do robo
          if(isStart)  // decisao condicional do comportamento autonomo
          {  // executa etapa do firmware do robo
            if(index_a==2)  // decisao condicional do comportamento autonomo
            {  // executa etapa do firmware do robo
            dataLen = clientBuff;   // executa etapa do firmware do robo
            }  // executa etapa do firmware do robo
            else if(index_a>2)  // decisao condicional do comportamento autonomo
            {  // executa etapa do firmware do robo
              dataLen--;  // executa etapa do firmware do robo
            }  // executa etapa do firmware do robo
            writeBuffer(index_a,clientBuff);  // atualiza atuador/saida com o valor indicado
          }  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        index_a++;  // executa etapa do firmware do robo
        if(index_a>120)  // decisao condicional do comportamento autonomo
        {  // executa etapa do firmware do robo
          index_a=0;   // executa etapa do firmware do robo
          isStart=false;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
        if(isStart&&dataLen==0&&index_a>3)  // decisao condicional do comportamento autonomo
        {   // executa etapa do firmware do robo
          isStart = false;  // executa etapa do firmware do robo
          parseData();  // executa etapa do firmware do robo
          index_a=0;  // executa etapa do firmware do robo
        }  // executa etapa do firmware do robo
      }  // executa etapa do firmware do robo
        
     else if ((millis() - previousMillis) > timeoutDuration && Serial.available() == 0 && st==true)  // decisao condicional do comportamento autonomo
       {  // executa etapa do firmware do robo
        Serial.write(Stop,17);  // atualiza atuador/saida com o valor indicado
       }     // executa etapa do firmware do robo
      
        //client.print(clientBuff);
            
      // static unsigned long Test_time = 0;
      // if (millis() - Test_time > 3000)
      // {
      //   Test_time = millis();
      //   if (0 == (WiFi.softAPgetStationNum()))
      //   {
      //     Serial.write(Stop,17);
      //     Serial.println("[Client disconnected]");
      //   }
      // }
    }  // executa etapa do firmware do robo
    Serial.write(Stop,17);  // atualiza atuador/saida com o valor indicado
    client.stop();  // executa etapa do firmware do robo
    Serial.println("[Client disconnected]");  // envia telemetria ao Monitor Serial
  }  // executa etapa do firmware do robo
  else  // executa etapa do firmware do robo
  {  // executa etapa do firmware do robo
    if (ED_client == true)  // decisao condicional do comportamento autonomo
    {  // executa etapa do firmware do robo
      ED_client = false;  // executa etapa do firmware do robo
      Serial.write(Stop,17);  // atualiza atuador/saida com o valor indicado
    }  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo
}  // executa etapa do firmware do robo

Código real CameraWebServer.cpp (APP) comentado

📦 Bibliotecas desta lição: as mesmas do sketch 6.2 (núcleo ESP32 2.0.12), nada a baixar — este .cpp compila junto ao .ino na mesma pasta.

#include "esp_system.h"  // embutida no núcleo ESP32 2.0.12, nada a baixar
#include "esp_camera.h"  // embutida no núcleo ESP32 2.0.12, nada a baixar
#include <WiFi.h>  // embutida no núcleo ESP32 2.0.12, nada a baixar

const char *ssid = "KUONGSHUN-AD176";  // executa etapa do firmware do robo
const char *password = "12345678";  // executa etapa do firmware do robo
String wifi_name;  // executa etapa do firmware do robo

#define PWDN_GPIO_NUM     32  // define constante de pino/mapa de hardware
#define RESET_GPIO_NUM    -1  // define constante de pino/mapa de hardware
#define XCLK_GPIO_NUM      0  // define constante de pino/mapa de hardware
#define SIOD_GPIO_NUM     26  // define constante de pino/mapa de hardware
#define SIOC_GPIO_NUM     27  // define constante de pino/mapa de hardware
#define Y9_GPIO_NUM       35  // define constante de pino/mapa de hardware
#define Y8_GPIO_NUM       34  // define constante de pino/mapa de hardware
#define Y7_GPIO_NUM       39  // define constante de pino/mapa de hardware
#define Y6_GPIO_NUM       36  // define constante de pino/mapa de hardware
#define Y5_GPIO_NUM       21  // define constante de pino/mapa de hardware
#define Y4_GPIO_NUM       19  // define constante de pino/mapa de hardware
#define Y3_GPIO_NUM       18  // define constante de pino/mapa de hardware
#define Y2_GPIO_NUM        5  // define constante de pino/mapa de hardware
#define VSYNC_GPIO_NUM    25  // define constante de pino/mapa de hardware
#define HREF_GPIO_NUM     23  // define constante de pino/mapa de hardware
#define PCLK_GPIO_NUM     22  // define constante de pino/mapa de hardware

void startCameraServer();  // configura/inicializa a camera OV2640
void CameraWebServer_init()  // configura/inicializa a camera OV2640
{  // executa etapa do firmware do robo
  camera_config_t config;  // configura/inicializa a camera OV2640
  config.ledc_channel = LEDC_CHANNEL_0;  // configura PWM do LED/flash da ESP32-CAM
  config.ledc_timer = LEDC_TIMER_0;  // configura PWM do LED/flash da ESP32-CAM
  config.pin_d0 = Y2_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d1 = Y3_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d2 = Y4_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d3 = Y5_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d4 = Y6_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d5 = Y7_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d6 = Y8_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_d7 = Y9_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_xclk = XCLK_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_pclk = PCLK_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_vsync = VSYNC_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_href = HREF_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_sccb_sda = SIOD_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_sccb_scl = SIOC_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_pwdn = PWDN_GPIO_NUM;  // executa etapa do firmware do robo
  config.pin_reset = RESET_GPIO_NUM;  // executa etapa do firmware do robo
  config.xclk_freq_hz = 20000000;  // executa etapa do firmware do robo
  config.frame_size = FRAMESIZE_UXGA;  // executa etapa do firmware do robo
  config.pixel_format = PIXFORMAT_JPEG; // for streaming  // executa etapa do firmware do robo
  //config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
  config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;  // configura/inicializa a camera OV2640
  config.fb_location = CAMERA_FB_IN_PSRAM;  // configura/inicializa a camera OV2640
  config.jpeg_quality = 12;  // executa etapa do firmware do robo
  config.fb_count = 1;  // executa etapa do firmware do robo
  
  // if PSRAM IC present, init with UXGA resolution and higher JPEG quality
  //                      for larger pre-allocated frame buffer.
  if(config.pixel_format == PIXFORMAT_JPEG){  // decisao condicional do comportamento autonomo
    if(psramFound()){  // decisao condicional do comportamento autonomo
      config.jpeg_quality = 10;  // executa etapa do firmware do robo
      config.fb_count = 2;  // executa etapa do firmware do robo
      config.grab_mode = CAMERA_GRAB_LATEST;  // configura/inicializa a camera OV2640
    } else {  // executa etapa do firmware do robo
      // Limit the frame size when PSRAM is not available
      config.frame_size = FRAMESIZE_SVGA;  // executa etapa do firmware do robo
      config.fb_location = CAMERA_FB_IN_DRAM;  // configura/inicializa a camera OV2640
    }  // executa etapa do firmware do robo
  } else {  // executa etapa do firmware do robo
    // Best option for face detection/recognition
    config.frame_size = FRAMESIZE_240X240;  // executa etapa do firmware do robo
#if CONFIG_IDF_TARGET_ESP32S3  // executa etapa do firmware do robo
    config.fb_count = 2;  // executa etapa do firmware do robo
#endif  // executa etapa do firmware do robo
  }  // executa etapa do firmware do robo
  // camera init
  esp_err_t err = esp_camera_init(&config);  // configura/inicializa a camera OV2640
  if (err != ESP_OK)  // decisao condicional do comportamento autonomo
  {  // executa etapa do firmware do robo
    Serial.printf("Camera init failed with error 0x%x", err);  // envia telemetria ao Monitor Serial
    return;  // retorna valor calculado ao chamador
  }  // executa etapa do firmware do robo
  sensor_t *s = esp_camera_sensor_get();  // configura/inicializa a camera OV2640
  //drop down frame size for higher initial frame rate
  //s->set_framesize(s, FRAMESIZE_SXGA); //字节长度采样值:60000                 #9 (画质高)  1280x1024
  s->set_framesize(s, FRAMESIZE_SVGA); //字节长度采样值:40000                   #7 (画质中)  800x600  // executa etapa do firmware do robo
  //s->set_framesize(s, FRAMESIZE_QVGA); //字节长度采样值:10000                #4 (画质低)  320x240

  s->set_vflip(s, 0);   //图片方向设置(上下)  // executa etapa do firmware do robo
  s->set_hmirror(s, 0); //图片方向设置(左右)  // executa etapa do firmware do robo

  // WiFi.setTxPower(WIFI_POWER_19_5dBm);
  WiFi.mode(WIFI_AP);  // configura rede WiFi AP do robo para video e comando
  WiFi.softAP(ssid, password, 5);  // configura rede WiFi AP do robo para video e comando
  // WiFi.softAP(ssid, password);
  Serial.print("\r\n");  // envia telemetria ao Monitor Serial
  startCameraServer();  // configura/inicializa a camera OV2640
  Serial.print("\r\n");  // envia telemetria ao Monitor Serial
  Serial.print("Camera Ready! Use 'http://");  // envia telemetria ao Monitor Serial
  Serial.print(WiFi.softAPIP());  // envia telemetria ao Monitor Serial
  Serial.println("' to connect");  // envia telemetria ao Monitor Serial
}  // executa etapa do firmware do robo

Gravação, pareamento e teste

Grave 6.1 no UNO e 6.2 na CAM com UART desplugada, reconecte, ligue com baterias, instale o APK, conecte-se ao AP, selecione ESP32-CAM Mecanum Smart Car no app e toque conectar até Connected Successfully. Opere D-pad, giro no lugar, sliders de tilt/farol/velocidade e os 4 modos; Connected Fail indica AP perdido — reconecte o WiFi e tente de novo.

💡 Dica: qualquer comando de direção força o modo livre; reative o modo autônomo após pilotar.

⚠️ Atenção: vflip difere entre CAM V0.3 e V2.0; ajuste set_vflip se a imagem sair invertida.

Aplicativo KUONGSHUN (Android e iOS)

Instalação via APK da pasta 4_Android_Software_Installation_Package (Android) ou busca por kuongshun na App Store (iOS). Fluxo: conectar ao AP, abrir o app, escolher idioma, selecionar ESP32-CAM Mecanum Smart Car, tocar conectar, pilotar com vídeo ao vivo. Controles: área de vídeo com play/pausa/fechar, slider de tilt (sobe = inclina para baixo), D-pad omnidirecional com giros, sliders de farol e velocidade, chaves dos 4 modos e indicador de conexão. A ESP32-CAM opera em modo AP — access point — criando a rede KUONGSHUN-AD176 com senha 12345678 e IP fixo 192.168.4.1192.168.4.1. O video usa MJPEG sobre HTTP — motion JPEG over hypertext transfer protocol — com multipart x-mixed-replace, onde cada frame JPEG e delimitado por boundary e empurrado em chunked encoding. A taxa util aproximada e:

R≈f⋅Setframe=SRef+tcodR \approx f \cdot S \qquad \text{e} \qquad t_{frame} = \frac{S}{R_{ef}} + t_{cod}

onde RR e o bitrate, ff o framerate, SS o tamanho medio do JPEG e tcodt_{cod} o tempo de compressao. SVGA (800×600800 \times 600) a qualidade 1010–1212 equilibra nitidez e latencia; UXGA trava o stream por esgotar PSRAM e banda. O enlace de comando UNO ↔\leftrightarrow ESP32-CAM usa UART a 115200 bps115200\,\text{bps} (8N18N1), com pacotes de 44 bytes (AB modelo valor FF) no modo Web e quadros FF 55 ... no modo APP, ambos com timeout de 10 ms10\,\text{ms}. A potencia de TX em 19,5 dBm19{,}5\,\text{dBm} maximiza alcance indoor a custa de consumo, por isso video so e estavel com bateria cheia. O canal fixo 55 reduz interferencia com roteadores domesticos.

Instalação do aplicativo KUONGSHUNTela de controle do AD176 no aplicativo

Guia Diagnóstico (Troubleshooting)

SintomaCausa raizAção corretiva
Upload falha / timeout no UNOUART com a CAM conectada contendendo RX/TX; placa ou porta erradaDesplugar jumper UART; selecionar Arduino UNO e COMxx; trocar cabo por dados; reinstalar CH340
Upload falha na ESP32-CAMNúcleo 3.x ou placa errada; UART conectadaInstalar ESP32 2.0.12; selecionar ESP32 Dev Module; desplugar UART no upload
Só aparece COM1Cabo só-carga ou CH340 ausenteTrocar cabo Tipo-C de dados; instalar driver da pasta 2_Programming_Preparation
Rede KUONGSHUN-AD176 não apareceBateria fraca, fiação errada, CAM sem bootRecarregar 18650; conferir chave e LEDs; revisar UART e alimentação; regravar 5.2/6.2
Connected Fail no appAP perdido ou cliente TCP antigo presoReconectar WiFi ao AP; fechar e reabrir app; reconectar; checar bateria
Imagem invertidaVariante CAM V0.3 vs V2.0 com vflip divergenteAlternar s->set_vflip(s,1/0) e set_hmirror no CameraWebServer.cpp e regravar
Vídeo com delay/travandoUXGA/qualidade alta sem PSRAM/banda; bateria fracaFixar SVGA qualidade 10-12; aproximar do robô; recarregar; canal 5 longe do roteador
Robô não anda / anda fracoSomente USB sem 18650; PWM baixo; rodas no X erradoInstalar 2x18650 carregadas; elevar speeds a 250; corrigir orientação Mecanum
Gira ao contrário / lateral invertidaByte de direção ou X das rodas trocadoConferir tabela 163/92/106/149 e reinstalar rodas no X correto
Servo vibra / não centralizaBraço calçado fora do 90°; queda de 5 VRegravar Lição 2, resetar a 90°, reposicionar braço reto; recarregar baterias
HC-SR04 sempre 0 ou fixoTRIG/ECHO trocados; eco preso; objeto fora do coneConferir D12 TRIG/D13 ECHO; testar anteparo a 20 cm; checar pulseIn/58
Seguidor ignora a linhaLimiar 400/500 fora da pista; sensor alto; luz forteImprimir leituras no Serial; recalibrar limiar; baixar altura; sombrear pista
Servo inverte no app (sobe=desce)Convenção do slider do appComportamento oficial: slider para cima reduz ângulo e inclina para baixo; operar invertido
Porta 192.168.4.1 não abreConectado ao roteador em vez do AP; IP erradoConectar ao AP KUONGSHUN-AD176, manter sem internet, digitar exatamente 192.168.4.1
Modo autônomo não engataPacote com modelo errado; modo preso em whileReenviar comando de modo; resetar UNO; checar RXpack_func/parseData no Serial 115200
Servo.h: No such file or directory / does not name a typeServo.zip não instalado ou IDE não reiniciadaReinstalar pela tabela-mestre (Etapa 3 da Preparação), conferir pasta libraries/Servo/Servo.h, reiniciar a IDE
esp_camera.h: No such file or directory / erro em ledcSetupNúcleo ESP32 3.x ou pacote ESP32 ausenteVoltar ao pacote ESP32 2.0.12 do fabricante, selecionar ESP32 Dev Module, recompilar

Expansões de engenharia (leitura densa complementar)

Aprofundamento para atingir densidade de curso: repetição analítica dos fenômenos com parametrização distinta. As rodas Mecanum possuem roletes a 45∘45^{\circ} em torno do cubo. Cada roda gera forca perpendicular ao eixo do rolete, decomponivel em componentes longitudinal FxF_x e lateral FyF_y. Com quatro rodas independentes em configuracao X, a soma vetorial permite translacao omnidirecional sem mudar a orientacao do chassi. O principio formal da cinematica direta do 4WD Mecanum, com semi-distancias LxL_x e LyL_y do centro, raio rr e velocidades angulares ω1…ω4\omega_1 \ldots \omega_4, e:

[vxvyωz]=r4[1111−111−1−1Lx+Ly1Lx+Ly−1Lx+Ly1Lx+Ly][ω1ω2ω3ω4]\begin{bmatrix} v_x \\ v_y \\ \omega_z \end{bmatrix} = \frac{r}{4} \begin{bmatrix} 1 & 1 & 1 & 1 \\ -1 & 1 & 1 & -1 \\ -\frac{1}{L_x+L_y} & \frac{1}{L_x+L_y} & -\frac{1}{L_x+L_y} & \frac{1}{L_x+L_y} \end{bmatrix} \begin{bmatrix} \omega_1 \\ \omega_2 \\ \omega_3 \\ \omega_4 \end{bmatrix}

onde vxv_x e a velocidade longitudinal, vyv_y a lateral e ωz\omega_z a taxa de guinada. A decomposicao por rolete explica os codigos decimais da tabela do fabricante: cada byte de 8 bits mapeia os 8 terminais de ponte H dos quatro motores via 74HC595, de modo que frentes paralelas somam FxF_x (marcha 163/92) e oposicoes simetricas somam FyF_y (translacao 106/149), enquanto diagonais produzem resultante a 45∘45^{\circ} (34/129/72/20) e giros puros cancelam translacao e somam momento (83/172). A velocidade linear de cada roda segue v=ωrv = \omega r, e a forca de tracao disponivel e limitada pelo atrito Fmax=μNF_{max} = \mu N, por isso piso liso reduz derrapagem dos roletes e melhora a lateralidade. O driver usa dois canais PWM (55 e 66) para energia e o registrador de deslocamento para direcao, separando potencia e logica como em toda ponte H dupla. O controle de velocidade usa PWM — pulse-width modulation — com periodo TT e largura tont_{on}. O ciclo de trabalho e definido por:

D=tonTeVmed=D⋅VccD = \frac{t_{on}}{T} \qquad \text{e} \qquad V_{med} = D \cdot V_{cc}

onde DD e o duty cycle e VmedV_{med} a tensao media aplicada ao motor. No Arduino UNO, analogWrite(pino, valor) gera D=valor/255D = valor/255 em ∼490 Hz\sim 490\,\text{Hz} (pinos 55 e 66 em ∼980 Hz\sim 980\,\text{Hz}). O torque medio cresce com DD, mas abaixo de certo limiar o atrito estatico impede a partida, por isso os exemplos usam 120120 a 250250. A energia mecanica entregue segue P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos quatro motores somados excede largamente o que o USB do PC fornece, razao pela qual a tracao so e valida com as duas celulas 18650 instaladas e chave ligada. O pino ENEN do expansor habilita as saidas em nivel baixo, e o latch STCPSTCP transfere o byte deslocado de uma vez, evitando estados intermediarios nas pontes. O HC-SR04 mede distancia por tempo de voo do ultrassom. O gatilho de 10 μs10\,\mu\text{s} emite 8 ciclos a 40 kHz40\,\text{kHz}; o eco retorna apos tt microssegundos de ida e volta. Com vsom≈343 m/sv_{som} \approx 343\,\text{m/s}:

d=vsom⋅t2=t58  cm(t  em  μs)d = \frac{v_{som} \cdot t}{2} = \frac{t}{58} \; \text{cm} \qquad (t \; \text{em} \; \mu\text{s})

onde dd e a distancia ao obstaculo. O divisor 5858 usado em pulseIn(ECHO, HIGH)/58.00 deriva de 104/172≈58,110^4/172 \approx 58{,}1. A zona cega abaixo de ∼2 cm\sim 2\,\text{cm} e o cone de ∼15∘\sim 15^{\circ} exigem servo centralizado a 90∘90^{\circ} nas leituras de desvio, e superficies absorventes inclinadas subestimam dd. O firmware filtra com delay(10) entre disparos para dissipar ecos multiplos, e os limiares 15/25/50 cm15/25/50\,\text{cm} dos modos seguimento e desvio derivam diretamente dessa resolucao centimetrica. O seguidor de linha usa tres sensores reflexivos IR com comparacao analogica. Cada canal retorna 0…10230 \ldots 1023 via ADC de 10 bits, onde preto absorve IR (valor baixo) e branco reflete (valor alto). O limiar Black_LineBlack\_Line particiona o espaco de observacao, e a maquina de estados mapeia as 23=82^3 = 8 combinacoes em correcoes diferenciais. A lei de controle e proporcional por zona: erro lateral estimado e∈{−2,−1,0,+1,+2}e \in \{-2,-1,0,+1,+2\} gera correcao de guinada Δω=Kp⋅e\Delta \omega = K_p \cdot e implementada como giros Clockwise/ContrarotateClockwise/Contrarotate com PWM 160/220160/220 contra cruzeiro 120/180120/180. A tensao lida em cada canal e:

Vin=ADC1023⋅VrefcomVref=5,0 VV_{in} = \frac{ADC}{1023} \cdot V_{ref} \qquad \text{com} \qquad V_{ref} = 5{,}0\,\text{V}

onde ADCADC e a contagem e VrefV_{ref} a referencia do UNO. Calibracao com Serial.println dos tres canais sobre preto e branco define o limiar real da pista (400400 a 500500 conforme o lote), pois luz ambiente desloca o ponto otimo. Faixa estreita demais causa oscilacao; larga demais corta curvas. A geometria dos tres pontos a frente do eixo motor cria antecipacao natural da curva, equivalente a acao derivativa mecanica. O servo SG90 e comandado por PPM com periodo de 20 ms20\,\text{ms}. A largura do pulso codifica o angulo:

θ=tp−1,0 ms1,0 ms⋅90∘1,0≤tp≤2,0 ms\theta = \frac{t_p - 1{,}0\,\text{ms}}{1{,}0\,\text{ms}} \cdot 90^{\circ} \qquad 1{,}0 \leq t_p \leq 2{,}0\,\text{ms}

onde θ\theta varia de 0∘0^{\circ} a 180∘180^{\circ} e tpt_p e a largura em milissegundos. A biblioteca Servo.h abstrai o timer em write(graus), com 90∘90^{\circ} como frente mecanica da camera. O torque τ∼1,8 kgf.cm\tau \sim 1{,}8\,\text{kgf.cm} exige alimentacao 5 V5\,\text{V} estavel; jitter indica queda de tensao sob carga dos motores. A varredura 0→180→00 \rightarrow 180 \rightarrow 0 com passo de 10 ms10\,\text{ms} do exemplo produz velocidade angular ω≈100∘/s\omega \approx 100^{\circ}/\text{s}, suave para calibrar o braco do pan-tilt sem forcar engrenagens. O reset ao 90∘90^{\circ} antes do ajuste mecanico garanteDatum repetivel. A ESP32-CAM opera em modo AP — access point — criando a rede KUONGSHUN-AD176 com senha 12345678 e IP fixo 192.168.4.1192.168.4.1. O video usa MJPEG sobre HTTP — motion JPEG over hypertext transfer protocol — com multipart x-mixed-replace, onde cada frame JPEG e delimitado por boundary e empurrado em chunked encoding. A taxa util aproximada e:

R≈f⋅Setframe=SRef+tcodR \approx f \cdot S \qquad \text{e} \qquad t_{frame} = \frac{S}{R_{ef}} + t_{cod}

onde RR e o bitrate, ff o framerate, SS o tamanho medio do JPEG e tcodt_{cod} o tempo de compressao. SVGA (800×600800 \times 600) a qualidade 1010–1212 equilibra nitidez e latencia; UXGA trava o stream por esgotar PSRAM e banda. O enlace de comando UNO ↔\leftrightarrow ESP32-CAM usa UART a 115200 bps115200\,\text{bps} (8N18N1), com pacotes de 44 bytes (AB modelo valor FF) no modo Web e quadros FF 55 ... no modo APP, ambos com timeout de 10 ms10\,\text{ms}. A potencia de TX em 19,5 dBm19{,}5\,\text{dBm} maximiza alcance indoor a custa de consumo, por isso video so e estavel com bateria cheia. O canal fixo 55 reduz interferencia com roteadores domesticos. Na prática de bancada, cada parágrafo acima converte-se em um ensaio mensurável: cronometrar os 2 s por estado da Lição 1, plotar varredura do servo contra tempo, tabular distância serial versus trena, mapear trios IR sobre preto/branco/cinza, medir RSSI e latência do MJPEG em SVGA/SXGA/QVGA, e registrar corrente de estol versus PWM — compondo o caderno de engenharia do AD176.

Solução de problemas

Olá! Sou o assistente técnico da RoboBuilders. Descreva seu problema com o Kit Robô Avançado 4WD Com Câmera AD176 - 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.