Kit Robô Tartaruga ESP32 WiFi AD177 - Curso Completo

Kit Robô Tartaruga ESP32 WiFi AD177 — Curso Completo com Projetos Práticos

Introdução

Este curso apresenta o Kit Robô Tartaruga ESP32 WiFi AD177, um robô móvel diferencial 2WD com ESP32 e placa de expansão, driver de motores L298N, motores N20 com redução metálica, sensor ultrassônico HC-SR04 montado sobre servo, seguidor de linha de 3 canais IR, receptor infravermelho com controle remoto e comando sem fio por WiFi em modo AP — access point — com portal em 192.168.4.1 e aplicativo KUONGSHUN, programado na IDE do Arduino — integrated development environment — com o núcleo esp32 2.0.12. É 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 do chassi em acrílico e da preparação do ambiente com driver CH340, passa por ensaios isolados de tração, ultrassom, servo e linha, avança para comportamentos autônomos de seguimento e desvio de obstáculos e controle infravermelho, e chega aos firmwares integrados de comando Web e APP com quatro modos selecionáveis, sempre com o resultado esperado de cada teste. Ao final, o leitor terá o robô montado, calibrado, navegando por linha, desviando de obstáculos, seguindo objetos e dirigível pelo navegador e pelo aplicativo.

O que você vai aprender:

  • Montar o chassi tartaruga 2WD com motores N20, roda boba, servo do ultrassom e torre de acrílico
  • Preparar IDE do Arduino, núcleo ESP32 2.0.12, driver CH340 e bibliotecas ESP32Servo 1.1.2 e IRremote 4.1.2
  • Validar tração diferencial, telemetria HC-SR04, centragem do servo e calibração do seguidor de 3 canais
  • Programar seguimento de objeto, desvio com varredura e controle por infravermelho com timeout
  • Operar o modo Web em 192.168.4.1 e o modo APP com protocolo em quadros na porta 100
  • Diagnosticar alimentação 18650, WiFi, upload, biblioteca e pista com matriz de sintomas e causas

Material utilizado: Kit Robô Tartaruga ESP32 WiFi AD177 disponível na loja RoboBuilders em https://robobuilders.com.br.

Visão Geral do Kit e Arquitetura de Hardware

O AD177 é um robô diferencial de duas rodas motrizes com uma terceira roda boba universal para apoio, no formato que o fabricante chama de tartaruga pelo casco em acrílico em dois andares. Um único ESP32 comanda tudo: gera os dois PWMs de velocidade, os quatro sinais de sentido da ponte H dupla L298N, o PPM do servo do ultrassom, lê o eco por tempo de voo, lê os três canais analógicos da linha e decodifica o infravermelho, além de manter o rádio WiFi em modo AP com servidor HTTP e servidor TCP. A energia vem de duas células 18650 em série com chave, alimentando em paralelo a lógica do ESP32 pela expansão e o estágio de potência do L298N. A separação mecânica em dois andares isola vibração e fiação de potência embaixo da eletrônica de sinal em cima, reduzindo ruído no ADC da linha e no eco do ultrassom.

A cinemática diferencial do tartaruga relaciona as velocidades lineares das rodas direita e esquerda com a velocidade do centro e a taxa de guinada. Com distância entre rodas LL e raio de roda rr, e velocidades angulares ωR\omega_R e ωL\omega_L, o modelo direto é:

v=r2 (ωR+ωL)v = \frac{r}{2}\,(\omega_R + \omega_L) ω=rL (ωR−ωL)\omega = \frac{r}{L}\,(\omega_R - \omega_L)

onde vv é a velocidade de avanço do centro e ω\omega a taxa de guinada. Marcha à frente soma velocidades iguais, giro puro usa velocidades opostas de mesmo módulo, e curva usa módulos diferentes. A velocidade linear de cada roda segue vR=ωRrv_R = \omega_R r e vL=ωLrv_L = \omega_L r. A força de tração disponível é limitada pelo atrito Fmax=μNF_{max} = \mu N, por isso piso liso com poeira reduz aderência e o robô patina em arrancadas com duty alto. O raio de curvatura instantâneo é R=v/ωR = v/\omega, e quando v=0v = 0 o robô gira em torno do próprio centro, manobra usada no desvio após ré de segurança. O código implementa as combinações como funções discretas: ambas as pontes avante para vv positivo, ambas a ré para vv negativo, pontes opostas para ω\omega puro, e uma ponte parada com a outra avante para curva fechada de raio mínimo.

Diagrama de fiação oficial do AD177 com ESP32, expansão, L298N, motores N20, ultrassom, servo, linha e receptor IRRobô tartaruga AD177 montado com dois andares em acrílico, rodas, roda boba e torre do ultrassom

Inventário do kit

A lista abaixo consolida o guia de montagem em 14 passos do fabricante com os códigos reais. Cada grupo indica a função eletromecânica no conjunto, para conferência antes de apertar o primeiro parafuso.

  • Placas de acrílico superior e inferior com furação do tartaruga — casco em dois andares que separa potência embaixo de sinal em cima e define frente estreita e traseira larga para orientação
  • 2 motores N20 com redução metálica e suportes com porcas M2 — atuadores de tração diferencial com torque elevado em baixa rotação e giro suave característico do passeio da tartaruga
  • 2 rodas de tração com pneus de borracha — conversão de torque em deslocamento com raio que entra na cinemática diferencial e na velocidade de cruzeiro
  • Roda boba universal com esferas — terceiro apoio livre que permite giro puro sem arrasto e sustenta a frente do chassi
  • Placa controladora ESP32 com USB Tipo-C e chip serial CH340C — cérebro único com WiFi, ADC de 12 bits, LEDC para PWM e portas para servo, ultrassom, linha e infravermelho
  • Placa de expansão para ESP32 — distribuição de alimentação e sinais com barras de pinos que recebem a controladora e organizam a fiação de sensores e do L298N
  • Módulo driver de motores L298N — ponte H dupla que recebe dois PWMs de velocidade e quatro sinais de sentido e entrega corrente aos dois N20
  • Sensor ultrassônico HC-SR04 com suporte e braço do servo — telemetria de distância por tempo de voo montada sobre varredura para desvio e seguimento
  • Servo com braço em forma de 1 e parafusos — pan de um eixo que aponta o ultrassom a 90 graus à frente, 30 graus à direita e 150 graus à esquerda na varredura
  • Módulo seguidor de linha de 3 canais IR com cabo XH2.54 de 5 vias para Dupont — leitura reflexiva da pista sob o bico dianteiro com trimpot de sensibilidade por canal
  • Módulo receptor infravermelho com controle remoto — comando sem fio por rajadas de 38 kHz com mapa de códigos NEC e parada por timeout
  • Caixa de baterias para 2 células 18650 com chave — barramento de cerca de 7,4 V nominal que alimenta lógica e potência em paralelo
  • Jogo de colunas de cobre M3 simples e duplas, parafusos M2, M3 e M1.6 com porcas e parafusos autorroscantes M1.4 — fixação e empilhamento dos andares com alturas que acomodam driver, expansão e torre
  • Chicotes XH2.54, jumpers Dupont, cabo de bateria e cabo USB Tipo-C de dados — interligação de sinal e potência com distinção obrigatória entre cabo de carga e cabo de dados
  • Fita preta para pista de testes e pacote de aplicativo KUONGSHUN em APK para Android com variante na App Store — ambiente de ensaio de linha e comando remoto por navegador e por aplicativo

Somatória: 15 grupos, totalizando dezenas de peças que compõem um robô diferencial completo com um ESP32, driver duplo, 2 motores com redução, 3 sensores de navegação, servo de varredura, comando infravermelho e comando WiFi em dois firmwares integrados.

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

A tabela abaixo foi extraída dos dez sketches do fabricante. É a referência única de fiação: qualquer fio fora dela impede o modo correspondente sem acusar erro de compilação.

SubsistemaPino ESP32DireçãoProtocoloObservação
PWM velocidade AGPIO 25 via canal LEDC 3SaídaLEDC 5 kHz 8 bitsledcWrite(ENA, 0-255) com duty D=valor/255D = valor/255
PWM velocidade BGPIO 13 via canal LEDC 4SaídaLEDC 5 kHz 8 bitsMesmo duty do canal A no cruzeiro
Sentido ponte AGPIO 26 IN1 e GPIO 27 IN2SaídaDigitalAvante LOW/HIGH, ré HIGH/LOW, freio HIGH/HIGH
Sentido ponte BGPIO 14 IN3 e GPIO 12 IN4SaídaDigitalMesma convenção do canal A
Gatilho ultrassomGPIO 19 TRIGSaídaPulso 10-20 usDispara trem de 8 ciclos a 40 kHz
Eco ultrassomGPIO 18 ECHOEntradapulseIn/58Largura em us dividida por 58 resulta em cm
Servo do ultrassomGPIO 16SaídaPPM 20 msESP32Servo com pulsos de 500 a 2500 us, centro 90 graus
Linha esquerdaGPIO 32EntradaADC1 12 bitsanalogRead de 0 a 4095, referência 3,3 V
Linha centroGPIO 35EntradaADC1 12 bitsCanal central da decisão de marcha
Linha direitaGPIO 34EntradaADC1 12 bitsCanal direito da decisão de curva
Receptor infravermelhoGPIO 15 nos modos 7 e 10 e GPIO 5 no modo 9EntradaNEC 38 kHzConferir fiação do passo 11 antes de gravar o modo 9; ajustar #define ao fio real
Rede de comandoAP KUONGSHUN-AD177 senha 12345678RFWiFi 802.11 + HTTP e TCP 100Portal em 192.168.4.1; canal 9 no Web e 5 no APP

O controle de velocidade usa PWM — pulse-width modulation — com período TT e largura tont_{on}. O ciclo de trabalho e a tensão média no motor são:

D=tonTD = \frac{t_{on}}{T} Vmed=D⋅(Vbat−Vdrop)V_{med} = D \cdot (V_{bat} - V_{drop})

onde DD é o duty cycle, VbatV_{bat} a tensão do pack 18650 e VdropV_{drop} a queda de cerca de 2 V2\,\text{V} na ponte L298N. No ESP32, ledcSetup(canal, 5000, 8) cria D=valor/255D = valor/255 em 5 kHz5\,\text{kHz}. O torque médio cresce com DD, mas abaixo do limiar de atrito estático o motor zumbe sem partir, por isso os exemplos usam 120120 a 255255. A potência elétrica entregue é P=Vmed⋅IP = V_{med} \cdot I, e a corrente de estol dos dois N20 somada excede o que o USB fornece, razão pela qual tração só se valida com as duas células instaladas e chave ligada. A Lei de Ohm V=R⋅IV = R \cdot I explica a queda nos enrolamentos e nos transistores da ponte, que aquecem em marcha lenta prolongada.

Montagem Mecânica (Assembly Guide)

A montagem segue os 14 passos do guia do fabricante na ordem original, da distinção de frente e traseira até as rodas. A regra de ouro é mecânica antes de energia: nenhum teste com bateria antes do passo da fiação conferido fio a fio, e nenhum aperto final antes da validação de giro livre e curso do servo. Cada passo indica peças, cuidados e validação, com a imagem oficial correspondente.

Passo 0 — Distinguir frente e traseira das placas

As duas placas de acrílico têm extremidade estreita e extremidade larga. A frente é o lado estreito, onde ficam o seguidor de linha e a torre do ultrassom. Monte sempre com a face da frente para cima para que a furação dos suportes coincida. Validação: sobreponha as duas placas com as frentes alinhadas e confira que os furos das colunas batem sem forçar. Teoria de apoio: a geometria define o centro de massa à frente do eixo motor, o que estabiliza a marcha e reduz empinamento em arrancada, pois o momento de reação M=F⋅hM = F \cdot h com altura hh baixa gera pouca transferência de carga para trás.

Passo 0 — Frente estreita e traseira larga das placas de acrílico do tartarugaPasso 0 — Sobreposição das placas com frentes alinhadas

💡 Dica: fotografe cada passo com o celular. A foto resolve a maioria dos diagnósticos de fiação e orientação.

Passo 1 — Fixar os motores N20 no chassi inferior

Encaixe cada N20 no suporte metálico com a porca M2 pré-alojada na cavidade do furo antes de passar o parafuso M2 por 10 de cabeça chata, e fixe o conjunto na placa inferior. Observe a orientação dos suportes para que os eixos fiquem coaxiais e as caixas de redução para dentro. Validação: gire cada eixo com o dedo e sinta a redução suave sem pontos duros. Teoria de apoio: a redução multiplica o torque pelo inverso da relação e divide a rotação na mesma proporção, com potência mecânica P=τ⋅ωP = \tau \cdot \omega conservada a menos do rendimento η\eta das engrenagens. O N20 metálico entrega passeio lento e forte, ideal para seguimento fino a baixa velocidade sem trepidação.

Passo 1 — Motores N20 com suportes e parafusos M2 na placa inferior

⚠️ Atenção: porca fora da cavidade espana o suporte. Aloje a porca primeiro e aperte com firmeza moderada para não trincar o acrílico.

Passo 2 — Montar o seguidor de linha de 3 canais

Fixe quatro colunas de cobre M3 por 7 com parafusos M3 por 6 de cabeça chata na região do bico, alinhe o módulo de três vias sobre as colunas e trave com mais quatro parafusos, e conecte o chicote XH2.54 de 5 vias ao conector do módulo. Validação: módulo paralelo à placa a cerca de um dedo de altura do solo futuro, sem inclinação lateral. Teoria de apoio: cada canal tem um LED emissor infravermelho e um fototransistor receptor. O preto absorve e o branco reflete, de modo que a tensão do divisor varia com a refletância ρ\rho. A leitura do ESP32 é:

Vin=ADC4095⋅3,3 VV_{in} = \frac{ADC}{4095} \cdot 3{,}3\,\text{V}

onde ADCADC é a contagem de 12 bits. O limiar Black_LineBlack\_Line particiona preto e branco, e o trimpot desloca o ponto de transição. Altura excessiva dilui o contraste e exige recalibração.

Passo 2 — Seguidor de 3 canais sobre colunas com chicote XH2.54

Passo 3 — Montar a roda boba universal

Fixe duas colunas M3 por 7 na furação dianteira com quatro parafusos M3 por 6 e aparafuse a roda boba sobre elas. Validação: esfera gira livre em qualquer direção e a placa fica nivelada quando apoiada nos dois eixos traseiros mais a boba. Teoria de apoio: o apoio em três pontos define um plano estável, e a boba universal impõe restrição holonômica nula, permitindo giro puro com v=0v = 0 e ω≠0\omega \neq 0 sem arrasto lateral. Folga excessiva aqui vira oscilação de guinada na linha, corrigida com coluna bem travada.

Passo 3 — Roda boba universal na dianteira

Passo 4 — Montar o módulo driver L298N

Fixe quatro colunas M3 por 7 na região central inferior, alinhe o L298N sobre elas respeitando a orientação com bornes de motores para os lados e borne de alimentação para trás, e trave com oito parafusos. Validação: dissipador sem encostar no acrílico e bornes acessíveis para a fiação do passo 11. Teoria de apoio: cada ponte H tem quatro chaves em H que invertem a polaridade no motor. A queda Vdrop≈2 VV_{drop} \approx 2\,\text{V} nos Darlingtons converte-se em calor P=Vdrop⋅IP = V_{drop} \cdot I, por isso marcha lenta prolongada com duty alto aquece o dissipador e exige pausas entre ensaios.

Passo 4 — Driver L298N sobre colunas com orientação dos bornes

⛔ Perigo: nunca alimente o L298N invertido. Inversão de bateria destrói a ponte e a expansão em segundos. Confira polaridade duas vezes antes do primeiro ON.

Passo 5 — Montar a controladora ESP32 e a expansão

Fixe quatro colunas M3 por 7 na placa inferior, alinhe a expansão sobre elas e trave, e encaixe a controladora ESP32 nos barramentos da expansão até o fundo sem pinos tortos. Validação: placa paralela, sem folga, com USB Tipo-C acessível pela lateral para upload. Teoria de apoio: a expansão é um distribuidor passivo de alimentação e sinal. O contato intermitente em barra de pinos gera reset espúrio por queda de VccV_{cc} durante pico de corrente dos motores, sintoma clássico de placa mal assentada que se confunde com defeito de firmware.

Passo 5 — Expansão e controladora ESP32 assentada

Passo 6 — Montar as colunas de sustentação de 40 mm

Fixe as quatro colunas longas M3 por 40 nos cantos da placa inferior com parafusos M3 por 10. Elas definem o vão entre andares que acomoda driver, expansão e chicotes. Validação: quatro topos no mesmo plano, sem coluna bamba. Teoria de apoio: o vão adequado garante convecção ao redor do L298N e raio de curvatura suave aos chicotes, evitando fadiga por dobra fechada que rompe cobre com a vibração da marcha.

Passo 6 — Colunas longas de sustentação entre andares

Passo 7 — Montar a caixa de baterias na placa superior

Fixe a caixa de 2 células 18650 na placa superior com quatro parafusos M3 por 10 e porcas M3, respeitando a orientação com fios para trás e frente da placa alinhada com a frente inferior. Não instale as células ainda. Validação: caixa firme, sem tocar as colunas, com chave e fios livres. Teoria de apoio: duas células em série somam tensão Vpack=V1+V2≈7,4 VV_{pack} = V_1 + V_2 \approx 7{,}4\,\text{V} nominal e mantêm a capacidade em ampère-hora. Chave desligada durante a fiação evita curto acidental de ferramenta sobre os bornes.

Passo 7 — Caixa 18650 na placa superior

⚠️ Atenção: use apenas células 18650 íntegras, sem amassados ou capa rasgada, e sempre em par com cargas semelhantes. Célula danificada é risco de incêndio.

Passo 8 — Montar o servo do ultrassom

Fixe o servo na furação da placa superior com dois parafusos M2 por 10 de cabeça redonda e porcas M2, com o eixo para cima e a face do eixo voltada para a frente. Validação: servo perpendicular, sem folga rotacional na caixa. Teoria de apoio: o servo será o pan do ultrassom. O centro mecânico a 90 graus deve coincidir com a frente geométrica, e qualquer desalinhamento aqui vira erro sistemático de ±10∘\pm 10^{\circ} na varredura de desvio, que o firmware não compensa.

Passo 8 — Servo do ultrassom com eixo para cima

Passo 9 — Montar o ultrassom sobre o servo em três subetapas

Primeiro fixe o HC-SR04 no suporte em U com quatro parafusos M1.6 por 10 e porcas M1.6 com as cápsulas para frente e sem tocar os pinos. Depois fixe o braço em forma de 1 no eixo do servo com dois parafusos autorroscantes M1.4 por 5. Por fim una o suporte ao braço com o parafuso pequeno do kit do servo. Validação: conjunto gira solidário ao eixo sem escorregar e sem cabo tracionando. Teoria de apoio: o ultrassom mede por tempo de voo com d=vsom⋅t/2d = v_{som} \cdot t/2. O suporte rígido garante que o eixo acústico acompanhe o ângulo comandado, e folga no braço espalha o cone de 15∘15^{\circ} e degrada a comparação direita-esquerda do desvio.

Passo 9.1 — HC-SR04 no suporte em UPasso 9.2 — Braço do servo e fixação do suporte
Passo 9.3 — Torre do ultrassom sobre o servo

Passo 10 — Montar o receptor infravermelho

Fixe o módulo receptor na lateral dianteira com dois parafusos M2 por 10 e porcas M2, com o olho receptor para frente e sem obstrução do casco. Validação: LED do módulo visível e olho desobstruído em 180 graus frontais. Teoria de apoio: o receptor usa fotodiodo com filtro de 38 kHz e decodificador NEC. Obstrução parcial reduz o alcance de metros para centímetros e gera quadros corrompidos que o firmware descarta, sintoma que se confunde com pilha fraca do controle.

Passo 10 — Receptor infravermelho na dianteira

Passo 11 — Fiação completa de sinal e potência

Com a chave desligada e sem baterias, ligue os motores aos bornes do L298N, os enables e sentidos à expansão conforme o mapa de pinos, o TRIG e o ECHO do ultrassom, o sinal do servo, os três canais da linha e o sinal do receptor IR, e o cabo de bateria em paralelo na expansão e no L298N. Distinga o chicote XH2.54 com trava do jumper Dupont avulso. Validação: cada fio puxado de leve sem soltar, polaridade da bateria conferida com multímetro, e USB Tipo-C de dados separado do cabo de carga. Teoria de apoio: a malha de potência carrega ampères com queda V=R⋅IV = R \cdot I nos contatos, enquanto a malha de sinal carrega microampères sensível a ruído. Trançar sinal longe dos fios de motor reduz diafonia no ADC da linha e no eco.

Passo 11 — Diagrama de fiação de sinal e potência

⛔ Perigo: confira duas vezes o paralelo da bateria na expansão e no L298N antes de inserir as células. Curto no barramento funde trilhas e pode inflar células 18650.

Passo 12 — Unir os andares superior e inferior

Apoie a placa superior sobre as quatro colunas de 40 mm, passe os chicotes pelo vão sem prensar, e trave com quatro parafusos M3 por 10. Validação: vão uniforme, nenhum fio esmagado, torre do ultrassom livre acima do casco. Teoria de apoio: a compressão de chicote contra coluna cria falha intermitente por vibração, o defeito mais difícil de diagnosticar porque some com o robô parado na bancada e reaparece em marcha.

Passo 12 — União dos andares com vão para chicotes

Passo 13 — Montar as rodas de tração

Encaixe as duas rodas nos eixos dos N20 até o fundo com pressão firme e simétrica. Validação: rodas coplanares, sem bamboleio, com giro livre e sem roçar no acrílico. Teoria de apoio: excentricidade de roda injeta oscilação periódica na odometria com frequência f=v/(2πr)f = v/(2\pi r), que o seguidor de linha interpreta como erro de pista e corrige com zigue-zague. Roda bem centrada é pré-requisito de linha lisa.

Passo 13 — Rodas de tração nos eixos N20Passo 13 — Robô tartaruga com rodas e conferência final

Preparação do Ambiente (Programming Preparation)

A preparação instala a cadeia completa de gravação antes do primeiro upload: IDE do Arduino, driver do conversor serial CH340, núcleo ESP32 e bibliotecas do kit. Nenhuma lição compila sem as quatro camadas, e a maioria dos erros de porta e de biblioteca nasce aqui. Reserve uma hora calma, com cabo Tipo-C de dados conhecido e internet estável para o gerenciador de placas.

IDE do Arduino e driver CH340

Baixe a IDE no site oficial do Arduino e instale a versão estável para Windows ou macOS conforme o guia do fabricante. Conecte a ESP32 com cabo Tipo-C de dados e observe se o sistema cria uma porta serial. Se aparecer apenas COM1 no Windows ou nenhum dispositivo USB com VID 0x1A86 no macOS, instale manualmente o pacote CH340 da pasta de recursos do kit e reinicie. Validação: Gerenciador de Dispositivos mostra a porta sem triângulo amarelo, e a IDE lista a COM correspondente em Ferramentas e Porta. Teoria de apoio: o CH340 converte USB em UART TTL para o bootloader do ESP32. Cabo de carga sem fios de dados alimenta a placa sem criar porta, o erro mais comum do primeiro upload, que se resolve trocando o cabo e não o driver.

Download da IDE do Arduino no site oficialInstalação manual do driver CH340 no Windows

⚠️ Atenção: use cabo Tipo-C de dados, não cabo de carga. Sem fios D+ e D-, a placa acende mas a porta nunca aparece.

Núcleo ESP32 2.0.12 na IDE

Abra Arquivo e Preferências e adicione a URL do gerenciador da Espressif em URLs Adicionais para Gerenciadores de Placas. Em Ferramentas, Placa e Gerenciador de Placas, busque esp32 e instale a versão 2.0.12, sem aceitar a latest automaticamente. Selecione ESP32 Dev Module em Ferramentas e Placa. Validação: o menu mostra ESP32 Dev Module e o exemplo WiFiScan compila sem erro. Teoria de apoio: o núcleo entrega compilador Xtensa, bootloader, WiFi, LEDC e ADC. A versão 2.0.12 preserva a API ledcSetup e ledcAttachPin usada em todos os sketches do kit. O núcleo 3.x removeu essas funções e quebra 100 por cento dos códigos do AD177 com erro de compilação, por isso fixar a versão é inegociável e o primeiro item do troubleshooting.

URL do gerenciador ESP32 nas preferênciasInstalação do núcleo ESP32 2.0.12 e seleção do Dev Module

⛔ Perigo: núcleo ESP32 3.x não compila os sketches do kit. Se a compilação acusar ledcSetup was not declared, volte o núcleo para 2.0.12 no Gerenciador de Placas.

Tabela-mestre de bibliotecas do curso

Todas as dependências externas do curso estão consolidadas abaixo com versão pinada e duas vias de instalação. Instale uma vez e confira antes de cada lição pelo quadro da lição.

Biblioteca (#include)Buscar no GerenciadorVersão usada no cursoDownload ZIP (espelho oficial)Lições
ESP32Servo por Kevin HarringtonESP32Servo1.1.2ESP32Servo no GitHub madhephaestus/ESP32Servo3, 5, 6, 10
IRremote por shirriff, z3t0, ArminJoIRremote4.1.2IRremote no GitHub Arduino-IRremote/Arduino-IRremote7, 9, 10
WiFi do núcleo ESP32embutida no núcleo 2.0.12, nada a instalar2.0.12acompanha o pacote ESP32 da Espressif8, 9, 10
esp_http_server do IDFembutida no núcleo, nada a instalar2.0.12acompanha o pacote ESP328, 9

Via Gerenciador, recomendada: Sketch, Incluir Biblioteca, Gerenciar Bibliotecas, buscar o nome exato, selecionar a versão pinada no seletor, Instalar e reiniciar a IDE. Via ZIP: baixar o ZIP no espelho oficial, Sketch, Incluir Biblioteca, Adicionar Biblioteca .ZIP, selecionar o arquivo e reiniciar a IDE. Conferência: Arquivo, Exemplos, ESP32Servo, Sweep deve abrir e compilar para ESP32 Dev Module sem No such file or directory, e Arquivo, Exemplos, IRremote, SimpleReceiver deve abrir e compilar. Dependências transitivas: a 4.1.2 do IRremote não exige bibliotecas auxiliares no ESP32. Erro típico ESP32Servo.h: No such file or directory indica pasta libraries/ESP32Servo ausente ou IDE aberta durante a cópia sem reiniciar.

Cópia da pasta libraries e conferência dos exemplos

💡 Dica: copie a pasta libraries do kit para a pasta de sketches sem alterar o caminho do Sketchbook, ou instale pelas versões pinadas acima. Nunca misture as duas vias com versões diferentes.

Primeiro upload e Monitor Serial

Com a placa conectada, selecione ESP32 Dev Module e a COM correta, abra o sketch da lição, clique em Verificar e depois em Carregar, e aguarde a barra de progresso com pontos e o aviso de sucesso. Abra o Monitor Serial com o baud rate do sketch, 9600 na maioria das lições e 115200 no modo APP, com retorno de linha adequado. Validação: mensagens de telemetria aparecem sem lixo de caracteres, o que confirma cristal, baud e aterramento íntegros. Teoria de apoio: o upload usa o bootloader ROM via RTS e DTR para reset automático. Falha de conexão com Failed to connect pede BOOT segurado na placa, cabo de dados e porta correta, nessa ordem, antes de suspeitar de driver.

Lições na Ordem do Tutorial do Fabricante

As dez lições abaixo seguem a ordem do PDF ESP32 WiFi Intelligent Turtle Car V2.0.24.6.24, sem reordenar nem fundir. Cada lição mantém o padrão interno: teoria do fenômeno com equações, componentes, conexões, bibliotecas, firmware comentado linha a linha, gravação com resultado esperado e avisos. Grave uma lição por vez e valide antes de avançar, porque os modos integrados 9 e 10 pressupõem tração, ultrassom, servo, linha e infravermelho já funcionais isoladamente.

Lição 1 — Colocar o carro em movimento

A primeira lição valida a cadeia completa de potência: ESP32, L298N, dois N20 e baterias. O sketch aciona as quatro combinações de ponte em sequência de dois segundos: avante, ré, esquerda e direita, com parada. É o ensaio de fumaça do robô: se ele anda nas quatro direções, a fiação de potência e os sentidos estão corretos. A teoria central é a ponte H: cada motor tem dois terminais comandados por IN1/IN2 e IN3/IN4, com enables em nível alto liberando corrente. A tabela de verdade implementada é avante LOW/HIGH em ambas as pontes, ré HIGH/LOW, esquerda com pontes opostas em um sentido e direita com o oposto, e parada com todos em HIGH. A velocidade aqui é plena porque os enables vão a HIGH digital, sem PWM, o que entrega Vmed≈Vbat−VdropV_{med} \approx V_{bat} - V_{drop} com D=1D = 1. A potência dissipada na ponte segue P=Vdrop⋅IP = V_{drop} \cdot I e o aquecimento é normal em bancada curta. O período de dois segundos por estado deriva de delay(2000), tempo suficiente para observar o sentido sem o robô sair da mesa se elevado no suporte. A mensagem de cada estado no Monitor Serial a 9600 bps confirma a máquina de estados mesmo sem ver o robô andar.

D=1D = 1 Vmed=Vbat−Vdrop≈7,4 V−2,0 VV_{med} = V_{bat} - V_{drop} \approx 7{,}4\,\text{V} - 2{,}0\,\text{V}

onde VmedV_{med} é a tensão plena no motor nesta lição sem PWM. Nas lições seguintes o LEDC modulará DD entre 0 e 1 para controlar velocidade com a mesma ponte e os mesmos sentidos validados aqui. A cinemática diferencial prevê que avante soma vR=vLv_R = v_L, ré soma negativa, e giros usam vR=−vLv_R = -v_L para ω\omega puro com R=0R = 0. Se uma roda gira invertida, inverta os dois fios dela no borne do L298N com a bateria removida, nunca no código, para preservar o mapa de sentidos das lições integradas.

Componente necessárioFunção no ensaio
Chassi montado com 2 N20 e rodasPlanta de tração diferencial sob teste
ESP32 com expansãoGeração dos sentidos e enables
Driver L298NEstágio de potência das duas pontes
2 células 18650 com chaveBarramento de potência da tração
Cabo Tipo-C de dadosUpload do sketch de marcha
Lição 1 — Abertura do programa de marcha no caminho do kitLição 1 — Seleção da placa ESP32 Dev Module e da porta COM
Conexão validadaPinoSentido
Enable AGPIO 25Saída HIGH
IN1/IN2GPIO 26/27Saída digital
IN3/IN4GPIO 14/12Saída digital
Enable BGPIO 13Saída HIGH

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

//www.kuongshun.com

//    The direction of the car's movement
//  ENA   ENB   IN1   IN2   IN3   IN4   Description  
//  HIGH  HIGH  HIGH  LOW   LOW   HIGH  Car is runing forward
//  HIGH  HIGH  LOW   HIGH  HIGH  LOW   Car is runing back
//  HIGH  HIGH  LOW   HIGH  LOW   HIGH  Car is turning left
//  HIGH  HIGH  HIGH  LOW   HIGH  LOW   Car is turning right
//  HIGH  HIGH  LOW   LOW   LOW   LOW   Car is stoped
//  HIGH  HIGH  HIGH  HIGH  HIGH  HIGH  Car is stoped
//  LOW   LOW   N/A   N/A   N/A   N/A   Car is stoped

//define L298n module IO Pin
#define ENA 25  // cria constante simbolica para pino ou parametro do hardware
#define IN1 26  // cria constante simbolica para pino ou parametro do hardware
#define IN2 27  // cria constante simbolica para pino ou parametro do hardware
#define IN3 14  // cria constante simbolica para pino ou parametro do hardware
#define IN4 12  // cria constante simbolica para pino ou parametro do hardware
#define ENB 13  // cria constante simbolica para pino ou parametro do hardware


void Forward(){   // define rotina de atuacao, leitura ou protocolo do robo
  digitalWrite(ENA,HIGH); //enable L298n A channel
  digitalWrite(ENB,HIGH); //enable L298n B channel
  digitalWrite(IN1,LOW); //set IN1 LOW level
  digitalWrite(IN2,HIGH);  //set IN2 HIGH level
  digitalWrite(IN3,LOW);  //set IN3 low level
  digitalWrite(IN4,HIGH); //set IN4 hight level
  Serial.println("Forward");//send message to serial monitor
}

void Back(){  // define rotina de atuacao, leitura ou protocolo do robo
  digitalWrite(ENA,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(ENB,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN1,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2,LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4,LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Back");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Right(){  // define rotina de atuacao, leitura ou protocolo do robo
  digitalWrite(ENA,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(ENB,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN1,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2,LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3,LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4,HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Left");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Left(){  // define rotina de atuacao, leitura ou protocolo do robo
  digitalWrite(ENA,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(ENB,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN1,LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2,HIGH);                                                                                                   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4,LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Right");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Stop(){  // define rotina de atuacao, leitura ou protocolo do robo
  digitalWrite(IN1,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4,HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Stop");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

//before execute loop() function, 
//setup() function will execute first and only execute once
void setup() {  // define rotina de atuacao, leitura ou protocolo do robo
  Serial.begin(9600);//open serial and set the baudrate
  pinMode(IN1,OUTPUT);//before useing io pin, pin mode must be set first 
  pinMode(IN2,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN3,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN4,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENA,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENB,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
}

//Repeat execution
void loop() {  // define rotina de atuacao, leitura ou protocolo do robo
  Forward();  //go forward
  delay(2000);//delay 2000 ms
  Back();     //go back
  delay(2000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
  Left();     //turning left
  delay(2000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
  Right();    //turning right
  delay(2000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
  Stop();     //Stop
  delay(2000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno

}

Gravação: conecte o Tipo-C de dados, selecione ESP32 Dev Module e a COM, clique em Carregar e aguarde o sucesso. Desconecte o USB, apoie o robô com as rodas livres ou leve ao chão livre, instale as duas 18650 e ligue a chave. Resultado esperado: avante por 2 s, ré por 2 s, esquerda por 2 s, direita por 2 s, parada por 2 s, em ciclo, com mensagens Forward, Back, Left, Right e Stop no Monitor a 9600 quando conectado. Se uma direção sai trocada, desligue, remova as baterias e inverta os dois fios do motor correspondente no borne. Se nada anda mas o Serial avança, suspeite de bateria fraca ou chave desligada, porque o USB sozinho não sustenta os N20.

⚠️ Atenção: primeiro teste sempre no chão livre ou com o robô suspenso. Tração plena em bancada derruba o robô e rompe a torre do ultrassom.

Lição 2 — Módulo sensor ultrassônico e Monitor Serial

A segunda lição isola a telemetria de distância que alimentará o seguimento e o desvio. O sketch dispara o TRIG, mede o ECHO com pulseIn e imprime a distância em centímetros a 9600 bps. O princípio é o tempo de voo: o módulo emite 8 ciclos a 40 kHz e o eco retorna após ida e volta até o obstáculo. Com velocidade do som vsom≈340 m/sv_{som} \approx 340\,\text{m/s}, a distância é metade do percurso total. O divisor 58 converte microssegundos em centímetros porque 104/172≈58,110^4/172 \approx 58{,}1. O período de medição acima de 60 ms evita que o eco tardio de um disparo contamine o seguinte, e o delay(10) entre leituras mais o delay(100) do laço garantem janela limpa. A zona morta abaixo de 2 cm e o cone de cerca de 15 graus exigem alvo plano e perpendicular na bancada para leitura estável. Superfície absorvente como tecido ou inclinada subestima a distância ou perde o eco, fenômeno que reaparecerá como leitura zero ou máxima nos modos autônomos.

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

onde dd é a distância e tt a largura do pulso de eco. A resolução de 0,2 cm0{,}2\,\text{cm} do fabricante deriva do clock de microssegundos do ESP32, e o alcance de 2 cm a 450 cm cobre da mesa ao corredor. A precisão prática em sala é de poucos centímetros até 2 m, degradando com vento de ventilador e ruído ultrassônico de impacto. O pino TRIG em GPIO 19 como saída e o ECHO em GPIO 18 como entrada dedicam o par ultrassônico sem conflito com PWM e servo, e a leitura bloqueante de pulseIn impõe que os modos autônomos intercalem medição e movimento em fatias curtas.

Componente necessárioFunção no ensaio
HC-SR04 na torreEmissor e receptor do trem ultrassônico
ESP32 com expansãoGatilho, cronometria e cálculo
Cabo USB de dadosTelemetria no Monitor Serial
Lição 2 — Upload do programa do ultrassomLição 2 — Monitor Serial com distância em centímetros a 9600
Conexão validadaPinoSentido
TRIGGPIO 19Saída
ECHOGPIO 18Entrada
VCC/GND5 V e GND da expansãoAlimentação

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

//www.kuongshun.com

float checkdistance()  // define rotina de atuacao, leitura ou protocolo do robo
{
    digitalWrite(19, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
    delayMicroseconds(2);  // gera temporizacao fina em microssegundos exigida pelo gatilho do ultrassom
    digitalWrite(19, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
    delayMicroseconds(10);  // gera temporizacao fina em microssegundos exigida pelo gatilho do ultrassom
    digitalWrite(19, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
    float distance = pulseIn(18, HIGH) / 58.00;  // mede a largura do pulso de eco para calcular a distancia por tempo de voo
    delay(10);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    return distance;  // devolve o valor calculado ao chamador da funcao
}

void Ultrasonic_Sensor_Module()  // define rotina de atuacao, leitura ou protocolo do robo
{
    int Distance = 0;  // define rotina de atuacao, leitura ou protocolo do robo
    Distance = checkdistance();  // executa etapa do firmware do robo tartaruga
    Serial.print("Distance:");  // envia telemetria ao Monitor Serial para validacao do ensaio
    Serial.print(Distance);  // envia telemetria ao Monitor Serial para validacao do ensaio
    Serial.println("CM");  // envia telemetria ao Monitor Serial para validacao do ensaio
    delay(100);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
}

void setup()  // define rotina de atuacao, leitura ou protocolo do robo
{
    Serial.begin(9600);  // inicializa a UART de depuracao para o Monitor Serial
    pinMode(19, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
    pinMode(18, INPUT);  // configura o pino como entrada ou saida digital antes do uso
}
void loop()  // define rotina de atuacao, leitura ou protocolo do robo
{
    Ultrasonic_Sensor_Module();  // executa etapa do firmware do robo tartaruga
}

Gravação: selecione placa e porta, carregue e abra o Monitor Serial a 9600 bps. Resultado esperado: linhas Distance: XX CM atualizando cerca de dez vezes por segundo, caindo ao aproximar a mão e subindo ao afastar. Aponte para parede lisa a 30 cm e confira leitura entre 28 e 32. Se a leitura trava em zero, confira TRIG e ECHO trocados. Se oscila sem alvo, afaste de ventilador e de outro ultrassom na bancada. Se mostra lixo de caracteres, ajuste o baud do Monitor para 9600 exatamente.

💡 Dica: valide com régua na bancada antes de ir ao chão. Telemetria calibrada aqui evita seguimento nervoso e desvio cego nas lições 5 e 6.

Lição 3 — Servo pan e correção do ângulo

A terceira lição domina o pan que carrega o ultrassom e corrige o zero mecânico do braço. O sketch centraliza a 90 graus por um segundo e varre de 0 a 180 e de volta com passo de um grau a cada 10 ms. A teoria é o PPM de 20 ms: a largura do pulso entre cerca de 0,5 ms e 2,5 ms codifica o ângulo, com 1,5 ms ao centro. A biblioteca ESP32Servo abstrai os timers LEDC do ESP32 em attach com pulsos de 500 a 2500 us e write em graus. A velocidade de varredura resultante é de cerca de 100 graus por segundo, suave para observar simetria sem forçar engrenagens. O ajuste mecânico usa o reset: com o servo comandado a 90 graus, desliga-se o sinal, solta-se o braço, realinha-se à frente e reencaixa-se, eliminando erro sistemático que deslocaria a varredura do desvio.

θ=tp−0,5 ms2,0 ms⋅180∘\theta = \frac{t_p - 0{,}5\,\text{ms}}{2{,}0\,\text{ms}} \cdot 180^{\circ} 0,5≤tp≤2,5 ms0{,}5 \leq t_p \leq 2{,}5\,\text{ms}

onde θ\theta é o ângulo e tpt_p a largura do pulso. O centro de 90 graus corresponde a tp≈1,5 mst_p \approx 1{,}5\,\text{ms} e define a frente do robô. O torque de cerca de 1,8 kgf.cm1{,}8\,\text{kgf.cm} exige 5 V estável, e jitter com motores ligados indica queda de barramento, não defeito do servo. O pino GPIO 16 dedicado evita conflito com os PWMs de tração nos canais 3 e 4 e com o ADC da linha. A repetibilidade do zero mecânico determina a simetria das leituras a 30 e 150 graus no desvio, e erro aqui vira preferência espúria por um lado.

Componente necessárioFunção no ensaio
Servo com braço em 1Pan do ultrassom com centro a 90 graus
ESP32 com expansãoGeração do PPM de 20 ms
2 células 18650Corrente de pico do servo sob carga
Lição 3 — Upload do teste de ângulo do servoLição 3 — Centralização a 90 graus e varredura simétrica
Conexão validadaPinoSentido
Sinal do servoGPIO 16Saída PPM
Alimentação5 V e GNDAlimentação

📦 Bibliotecas desta lição: ESP32Servo por Kevin Harrington, John K. Bennett (versão 1.1.2).

  • Via Gerenciador (recomendado): Sketch > Incluir Biblioteca > Gerenciar Bibliotecas… → buscar ESP32Servo → selecionar 1.1.2 → Instalar → reiniciar a IDE.
  • Via ZIP: baixar em madhephaestus/ESP32Servo (Code > Download ZIP) → Sketch > Incluir Biblioteca > Adicionar Biblioteca .ZIP… → reiniciar a IDE.
  • Conferência: Arquivo > Exemplos > ESP32Servo > Sweep deve abrir e compilar sem No such file or directory.
//www.kuongshun.com

#include <ESP32Servo.h>  // inclui a biblioteca necessaria ao projeto
#define servo_PIN 16  // cria constante simbolica para pino ou parametro do hardware
Servo myservo;  // executa etapa do firmware do robo tartaruga
void setup()  // define rotina de atuacao, leitura ou protocolo do robo
{
    myservo.attach(servo_PIN,500,2500);   // associa o objeto servo ao pino de sinal com pulsos de 500 a 2500 microssegundos
    myservo.write(90);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor
    delay(1000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
}

void loop()  // define rotina de atuacao, leitura ou protocolo do robo
{
  for(int i=0;i<180;i++){  // laco de varredura incremental do ensaio ou da vigilância de modo
    myservo.write(i);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor
    delay(10);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
  }
  delay(1000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
  for(int i=180;i>0;i--){  // laco de varredura incremental do ensaio ou da vigilância de modo
    myservo.write(i);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor
    delay(10);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
  }
  delay(1000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
}

Gravação: carregue, desconecte o USB, instale as baterias e ligue. Resultado esperado: torre vai a 90 graus, pausa um segundo e varre de lado a lado simetricamente. Se a varredura é assimétrica, pressione reset na ESP32 para voltar a 90 graus, desligue, solte o braço, alinhe à frente e reencaixe. Para alterar curso, edite os limites do for e o delay(10) e recarregue. Se treme com motor ligado, recarregue as 18650, porque queda de barramento gera jitter antes de qualquer defeito mecânico.

⚠️ Atenção: nunca force o braço com a mão ligada. O torque da redução quebra dentes com facilidade. Ajuste sempre com o servo comandado a 90 graus e desligado no instante do reencaixe.

Lição 4 — Seguidor de linha de 3 canais

A quarta lição fecha a primeira malha sensorial completa: três sensores reflexivos comandando a tração diferencial para permanecer sobre a fita preta. O sketch lê os três ADCs, compara com o limiar Black_LineBlack\_Line e aplica a máquina de estados: só o centro preto avança, preto à direita corrige à direita, preto à esquerda corrige à esquerda, tudo branco conforme a variante para ou avança, e tudo preto avança sobre cruzamento. A teoria é a refletância: o preto absorve infravermelho e devolve contagem baixa, o branco reflete e devolve contagem alta, com o trimpot deslocando a curva de transição. O ADC do ESP32 tem 12 bits de 0 a 4095 com referência de 3,3 V, o que explica limiares na casa das centenas nesta lição isolada e de 2000 na integrada, conforme iluminação e altura. A lei de controle é proporcional por zona com duas intensidades: correção forte travando uma roda e correção suave com turnSpeed de 120 contra cruzeiro de 200, o que suaviza a entrada em curva sem perder a linha. A geometria com três pontos à frente do eixo cria antecipação natural equivalente a ação derivativa mecânica.

Vin=ADC4095⋅3,3 VV_{in} = \frac{ADC}{4095} \cdot 3{,}3\,\text{V} estado=f(ADCL,ADCC,ADCR,Black_Line)estado = f(ADC_L, ADC_C, ADC_R, Black\_Line)

onde ADCADC é a contagem e ff a máquina de oito combinações. A calibração imprime os três canais sobre branco e sobre preto e posiciona o limiar no meio do vão, tipicamente entre 400 e 600 nesta lição. Curva fechada demais para a velocidade estoura a pista por inércia com F=m⋅v2/RF = m \cdot v^2/R, e a correção é reduzir cruzeiro ou suavizar o raio com fita sem quina. Luz solar direta satura os fototransistores e apaga o contraste, exigindo ensaio em sombra.

Componente necessárioFunção no ensaio
Seguidor de 3 canais com trimpotsLeitura reflexiva da pista
Fita preta sobre fundo claroPista de contraste calibrável
ESP32, L298N, N20 e 18650Malha sensor-motora completa
Lição 4 — Upload do seguidor de linhaLição 4 — Calibração dos trimpots sobre preto e branco
Conexão validadaPinoSentido
Linha esquerdaGPIO 32Entrada analógica
Linha centroGPIO 35Entrada analógica
Linha direitaGPIO 34Entrada analógica
TraçãoGPIOs 25/26/27/14/12/13Saída LEDC e digital

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

//www.kuongshun.com

//Line Tracking IO define
#define LEFT_LINE_TRACJING          32  // cria constante simbolica para pino ou parametro do hardware
#define CENTER_LINE_TRACJING        35  // cria constante simbolica para pino ou parametro do hardware
#define right_LINE_TRACJING         34  // cria constante simbolica para pino ou parametro do hardware
int Left_Tra_Value;  // define rotina de atuacao, leitura ou protocolo do robo
int Center_Tra_Value;  // define rotina de atuacao, leitura ou protocolo do robo
int Right_Tra_Value;  // define rotina de atuacao, leitura ou protocolo do robo
int Black_Line = 500;//small is black

#define ENA 3  // cria constante simbolica para pino ou parametro do hardware
#define ENA_PIN 25  // cria constante simbolica para pino ou parametro do hardware
#define IN1 26  // cria constante simbolica para pino ou parametro do hardware
#define IN2 27  // cria constante simbolica para pino ou parametro do hardware
#define IN3 14  // cria constante simbolica para pino ou parametro do hardware
#define IN4 12  // cria constante simbolica para pino ou parametro do hardware
#define ENB 4  // cria constante simbolica para pino ou parametro do hardware
#define ENB_PIN 13  // cria constante simbolica para pino ou parametro do hardware

#define carSpeed 200  // cria constante simbolica para pino ou parametro do hardware
#define turnSpeed 120  // cria constante simbolica para pino ou parametro do hardware

void Forward() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW); //set IN1 LOW level
  digitalWrite(IN2, HIGH);  //set IN2 HIGH level
  digitalWrite(IN3, LOW);  //set IN3 low level
  digitalWrite(IN4, HIGH); //set IN4 hight level
  Serial.println("go forward!");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Back() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("go back!");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Left() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("go left!");  // envia telemetria ao Monitor Serial para validacao do ensaio
}
void Left_small() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, turnSpeed); //enable L298n A channel
  ledcWrite(ENB, turnSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("go left!");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Right() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H


}
void Right_small() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, turnSpeed); //enable L298n A channel
  ledcWrite(ENB, turnSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("go right!");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Stop() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0); //enable L298n A channel
  ledcWrite(ENB, 0); //enable L298n B channel
  Serial.println("Stop!");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void setup() {  // define rotina de atuacao, leitura ou protocolo do robo
  Serial.begin(9600);  // inicializa a UART de depuracao para o Monitor Serial
  pinMode(LEFT_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(CENTER_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(right_LINE_TRACJING, INPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN1, OUTPUT); //before useing io pin, pin mode must be set first
  pinMode(IN2, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN3, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN4, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENA, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENB, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  ledcSetup(ENA,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcSetup(ENB,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcAttachPin(ENA_PIN,ENA);  // associa o pino fisico de enable ao canal LEDC configurado
  ledcAttachPin(ENB_PIN,ENB);  // associa o pino fisico de enable ao canal LEDC configurado
}

void loop() {  // define rotina de atuacao, leitura ou protocolo do robo

  Left_Tra_Value = analogRead(LEFT_LINE_TRACJING);  // le o conversor AD do ESP32 no canal do sensor reflexivo de linha
  Center_Tra_Value = analogRead(CENTER_LINE_TRACJING);  // le o conversor AD do ESP32 no canal do sensor reflexivo de linha
  Right_Tra_Value = analogRead(right_LINE_TRACJING);  // le o conversor AD do ESP32 no canal do sensor reflexivo de linha
  /*Serial.println("l,c,r:");  // envia telemetria ao Monitor Serial para validacao do ensaio
  Serial.println(Left_Tra_Value);  // envia telemetria ao Monitor Serial para validacao do ensaio
  Serial.println(Center_Tra_Value);  // envia telemetria ao Monitor Serial para validacao do ensaio
  Serial.println(Right_Tra_Value);*/  // envia telemetria ao Monitor Serial para validacao do ensaio
  if (Left_Tra_Value > Black_Line && Center_Tra_Value <= Black_Line && Right_Tra_Value > Black_Line)  // decisao condicional que seleciona o comportamento autonomo
  {
    Forward();  // executa etapa do firmware do robo tartaruga
  }
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value < Black_Line)  // ramo alternativo da decisao de navegacao autonoma
  {
    Right();  // executa etapa do firmware do robo tartaruga
  }
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line)  // ramo alternativo da decisao de navegacao autonoma
  {
    Right_small();  // executa etapa do firmware do robo tartaruga
  }
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value >= Black_Line)  // ramo alternativo da decisao de navegacao autonoma
  {
    Left_small();  // executa etapa do firmware do robo tartaruga
  }
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line)  // ramo alternativo da decisao de navegacao autonoma
  {
    Left();  // executa etapa do firmware do robo tartaruga
  }
  else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line)  // ramo alternativo da decisao de navegacao autonoma
  {
    Stop();  // executa etapa do firmware do robo tartaruga
  }
  else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line)  // ramo alternativo da decisao de navegacao autonoma
  {
    Forward();  // executa etapa do firmware do robo tartaruga
  }
}

Gravação e calibração: carregue, desconecte o USB e ligue com baterias. Com o robô suspenso, aproxime cada sonda da fita preta e confira o LED correspondente acendendo, ajustando o trimpot até apagar no branco e acender no preto. Faça pista oval sem quina com fita de 19 mm sobre piso claro. Resultado esperado: centro preto avança, desvios laterais corrigem para o lado do preto, e o robô completa voltas sem sair. Se oscila, reduza carSpeed de 200 para 150. Se ignora a linha, refaça a calibração sob a luz do ensaio, pois limiar de bancada não vale para sala iluminada.

💡 Dica: desative temporariamente as impressões de debug para ganhar ciclo, mas mantenha o bloco comentado de Serial.println dos três canais para recalibrar sempre que trocar de piso.

Lição 5 — Carro seguidor de objeto

A quinta lição transforma a telemetria em comportamento: manter distância de um alvo móvel à frente usando apenas o ultrassom fixo a 90 graus. O sketch centra o servo, mede a distância e aplica quatro faixas: abaixo de 15 cm recua devagar, entre 15 e 20 para, entre 20 e 25 avança devagar, entre 25 e 50 avança pleno, e fora disso para por perda de alvo. A teoria é o controle por zonas com histerese implícita: a faixa morta de 15 a 20 cm evita oscilação de caça ao redor do ponto, e as velocidades reduzidas a 60 e 70 por cento do cruzeiro de 255 suavizam aproximação e afastamento sem solavanco. O tempo de ciclo com medição bloqueante de pulseIn mais LEDC contínuo cria amostragem de cerca de 10 Hz, suficiente para alvo a passo humano. Alvo pequeno ou absorvente subestima a distância e o robô aproxima demais, enquanto parede lateral no cone gera leitura fantasma que paralisa o avanço. A equação de malha mostra que o erro de distância comanda diretamente o duty, sem integrador, o que elimina windup mas deixa erro residual de poucos centímetros aceitável para brinquedo seguidor.

e=dmed−dalvoe = d_{med} - d_{alvo} v={−0,7 vmax,d<150,15≤d≤20+0,6 vmax,20<d≤25+vmax,25<d≤500,d>50v = \begin{cases} -0{,}7\,v_{max}, & d < 15 \\ 0, & 15 \leq d \leq 20 \\ +0{,}6\,v_{max}, & 20 < d \leq 25 \\ +v_{max}, & 25 < d \leq 50 \\ 0, & d > 50 \end{cases}

onde dmedd_{med} é a leitura em centímetros e vv a velocidade comandada com vmaxv_{max} de duty 255. A faixa de 20 cm é o ponto de equilíbrio programado, e a perda acima de 50 cm trava por segurança em vez de acelerar ao infinito. A física do ultrassom impõe que o alvo tenha pelo menos a largura do cone a cada distância, com diâmetro iluminado w≈2⋅d⋅tan⁡(7,5∘)w \approx 2 \cdot d \cdot \tan(7{,}5^{\circ}). Mão aberta a 30 cm funciona, dedo isolado falha intermitente. O servo fixo a 90 graus elimina variável de apontamento e isola o teste de controle longitudinal antes da varredura lateral da lição seguinte.

Componente necessárioFunção no ensaio
HC-SR04 centrado a 90 grausMedição frontal contínua
Servo travado à frenteEliminação da variável de pan
ESP32, L298N, N20 e 18650Atuação proporcional por zonas
Alvo móvel como caixa ou mãoReferência de distância
Lição 5 — Upload do seguidor de objetoLição 5 — Teste com obstáculo móvel à frente
Conexão validadaPinoSentido
ServoGPIO 16Saída PPM
TRIG/ECHOGPIO 19/18Saída/Entrada
TraçãoLEDC 3/4 com IN1/IN2/IN3/IN4Saída

📦 Bibliotecas desta lição: ESP32Servo por Kevin Harrington, John K. Bennett (versão 1.1.2, mesma da Lição 3, nada a baixar).

  • Conferência: Arquivo > Exemplos > ESP32Servo > Sweep compila. Se o erro for ESP32Servo.h: No such file, reinstale pela tabela-mestre e reinicie a IDE.
//www.kuongshun.com

#include <ESP32Servo.h>  //servo library
Servo myservo;      // create servo object to control servo

#define Echo 18  // cria constante simbolica para pino ou parametro do hardware
#define Trig 19  // cria constante simbolica para pino ou parametro do hardware
#define servoPIN 16  // cria constante simbolica para pino ou parametro do hardware
#define ENA 3  // cria constante simbolica para pino ou parametro do hardware
#define ENA_PIN 25  // cria constante simbolica para pino ou parametro do hardware
#define IN1 26  // cria constante simbolica para pino ou parametro do hardware
#define IN2 27  // cria constante simbolica para pino ou parametro do hardware
#define IN3 14  // cria constante simbolica para pino ou parametro do hardware
#define IN4 12  // cria constante simbolica para pino ou parametro do hardware
#define ENB 4  // cria constante simbolica para pino ou parametro do hardware
#define ENB_PIN 13  // cria constante simbolica para pino ou parametro do hardware
#define carSpeed 255  // cria constante simbolica para pino ou parametro do hardware
int rightDistance = 0, leftDistance = 0, middleDistance = 0;  // define rotina de atuacao, leitura ou protocolo do robo
int UT_distance = 0;  // define rotina de atuacao, leitura ou protocolo do robo

void Forward(){   // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Forward");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Back() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Back");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Left() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Left");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Right() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Right");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Forward_slow(){   // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0.6*carSpeed); //enable L298n A channel
  ledcWrite(ENB, 0.6*carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}

void Back_slow() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0.7*carSpeed); //enable L298n A channel
  ledcWrite(ENB, 0.7*carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Back");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Stop() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0); //enable L298n A channel
  ledcWrite(ENB, 0); //enable L298n B channel
  Serial.println("Stop!");  // envia telemetria ao Monitor Serial para validacao do ensaio
} 

//Ultrasonic distance measurement Sub function
int Distance_detection() {  // define rotina de atuacao, leitura ou protocolo do robo
  digitalWrite(Trig, LOW);     // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  delayMicroseconds(2);  // gera temporizacao fina em microssegundos exigida pelo gatilho do ultrassom
  digitalWrite(Trig, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  delayMicroseconds(20);  // gera temporizacao fina em microssegundos exigida pelo gatilho do ultrassom
  digitalWrite(Trig, LOW);     // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  float Fdistance = pulseIn(Echo, HIGH);    // mede a largura do pulso de eco para calcular a distancia por tempo de voo
  Fdistance= Fdistance / 58;         // executa etapa do firmware do robo tartaruga
  return (int)Fdistance;  // devolve o valor calculado ao chamador da funcao
}  

void setup() {   // define rotina de atuacao, leitura ou protocolo do robo
  myservo.attach(servoPIN,500,2500);    // associa o objeto servo ao pino de sinal com pulsos de 500 a 2500 microssegundos
  myservo.write(90);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor

  Serial.begin(9600);       // inicializa a UART de depuracao para o Monitor Serial
  pinMode(Echo, INPUT);      // configura o pino como entrada ou saida digital antes do uso
  pinMode(Trig, OUTPUT);    // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN1, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN2, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN3, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN4, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENA, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENB, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  ledcSetup(ENA,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcSetup(ENB,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcAttachPin(ENA_PIN,ENA);  // associa o pino fisico de enable ao canal LEDC configurado
  ledcAttachPin(ENB_PIN,ENB);  // associa o pino fisico de enable ao canal LEDC configurado
  Stop();  // executa etapa do firmware do robo tartaruga
} 

void loop() {  // define rotina de atuacao, leitura ou protocolo do robo
  myservo.write(90);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor
  UT_distance = Distance_detection();  // executa etapa do firmware do robo tartaruga
  Serial.println(UT_distance);  // envia telemetria ao Monitor Serial para validacao do ensaio
  if (UT_distance < 15) {  // decisao condicional que seleciona o comportamento autonomo
    Back_slow();  // executa etapa do firmware do robo tartaruga
  } else if (15 <= UT_distance && UT_distance <= 20) {  // ramo alternativo da decisao de navegacao autonoma
    Stop();  // executa etapa do firmware do robo tartaruga
  } else if (20 <= UT_distance && UT_distance <= 25) {  // ramo alternativo da decisao de navegacao autonoma
    Forward_slow();  // executa etapa do firmware do robo tartaruga
  } else if (25 <= UT_distance && UT_distance <= 50) {  // ramo alternativo da decisao de navegacao autonoma
    Forward();  // executa etapa do firmware do robo tartaruga
  } else {  // ramo alternativo da decisao de navegacao autonoma
    Stop();  // executa etapa do firmware do robo tartaruga
  }
}

Gravação: carregue, leve ao chão livre com baterias e ligue. Resultado esperado: com caixa a 40 cm o robô avança, a 22 cm avança devagar, a 18 cm para, e a 10 cm recua devagar até estabilizar perto de 18 cm. Afaste a caixa além de 60 cm e ele para por perda. Se avança sem parar, confira ECHO solto que lê zero convertido em marcha. Se recua sem alvo, confiraeco preso em HIGH por curto. Ajuste os limiares 15, 20, 25 e 50 no loop para sala pequena ou corredor longo, mantendo a faixa morta de pelo menos 5 cm.

⚠️ Atenção: teste de seguimento exige área livre de 3 m. Recuo inesperado contra parede derruba a torre se houver obstáculo atrás fora do cone frontal.

Lição 6 — Carro com desvio de obstáculos e varredura

A sexta lição adiciona percepção lateral: ao detectar parede à frente abaixo de 25 cm, o robô para, gira o ultrassom a 30 e 150 graus, compara os lados e escapa para o mais livre com ré de segurança e giro. O sketch implementa a máquina clássica de desvio com três medidas por ciclo: centro, direita e esquerda, com pausas de acomodação do servo entre elas. A teoria é a amostragem espacial com sensor único multiplexado no tempo: em vez de três sonares, um sonar varrido emula três direções ao custo de latência de cerca de um segundo por decisão. A comparação usa máximo de espaço livre, e o empate com ambos os lados bloqueados comanda ré adicional. A ré antes do giro descola o para-choque da parede e evita arrasto lateral da roda boba, com vv negativo curto seguido de ω\omega puro. O limiar de 25 cm equilibra antecipação e falsos positivos: menor trava em porta estreita, maior desvia de sombra acústica sem obstáculo real.

dC≤25⇒parard_C \leq 25 \Rightarrow \text{parar} {girar aˋ direita,dR>dLgirar aˋ esquerda,dL>dRreˊ extra,dR,dL≤25\begin{cases} \text{girar à direita}, & d_R > d_L \\ \text{girar à esquerda}, & d_L > d_R \\ \text{ré extra}, & d_R, d_L \leq 25 \end{cases}

onde dCd_C, dRd_R e dLd_L são as leituras a 90, 30 e 150 graus. Os ângulos assimétricos em torno do centro compensam a montagem espelhada do suporte, e os delay de 200 a 500 ms acomodam o transitório mecânico antes de cada Distance_detection. A física do cone exige que a parede tenha largura suficiente nas três direções, e quina viva espalha o eco e subestima o lado real. A velocidade de cruzeiro com duty 255 garante torque para escapar de tapete alto, mas em piso liso causa derrapagem no giro que se corrige reduzindo para 200 sem alterar a lógica.

Componente necessárioFunção no ensaio
HC-SR04 na torre varridaSonar multiplexado em três direções
Servo de panApontamento sequencial 90, 30 e 150 graus
ESP32, L298N, N20 e 18650Decisão e escape diferencial
Corredor com caixasLabirinto de validação do desvio
Lição 6 — Upload do desvio de obstáculosLição 6 — Varredura direita e esquerda com comparação
Conexão validadaPinoSentido
ServoGPIO 16Saída PPM
TRIG/ECHOGPIO 19/18Saída/Entrada
TraçãoLEDC com INsSaída

📦 Bibliotecas desta lição: ESP32Servo por Kevin Harrington, John K. Bennett (versão 1.1.2, mesma da Lição 3, nada a baixar).

//www.kuongshun.com

#include <ESP32Servo.h>  //servo library
Servo myservo;      // create servo object to control servo

#define Echo 18  // cria constante simbolica para pino ou parametro do hardware
#define Trig 19  // cria constante simbolica para pino ou parametro do hardware
#define servoPIN 16  // cria constante simbolica para pino ou parametro do hardware
#define ENA 3  // cria constante simbolica para pino ou parametro do hardware
#define ENA_PIN 25  // cria constante simbolica para pino ou parametro do hardware
#define IN1 26  // cria constante simbolica para pino ou parametro do hardware
#define IN2 27  // cria constante simbolica para pino ou parametro do hardware
#define IN3 14  // cria constante simbolica para pino ou parametro do hardware
#define IN4 12  // cria constante simbolica para pino ou parametro do hardware
#define ENB 4  // cria constante simbolica para pino ou parametro do hardware
#define ENB_PIN 13  // cria constante simbolica para pino ou parametro do hardware
#define carSpeed 255  // cria constante simbolica para pino ou parametro do hardware
int rightDistance = 0, leftDistance = 0, middleDistance = 0;  // define rotina de atuacao, leitura ou protocolo do robo

void Forward(){   // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Forward");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Back() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Back");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Left() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Left");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Right() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Right");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Stop() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0); //enable L298n A channel
  ledcWrite(ENB, 0); //enable L298n B channel
  Serial.println("Stop!");  // envia telemetria ao Monitor Serial para validacao do ensaio
} 

//Ultrasonic distance measurement Sub function
int Distance_detection() {  // define rotina de atuacao, leitura ou protocolo do robo
  digitalWrite(Trig, LOW);     // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  delayMicroseconds(2);  // gera temporizacao fina em microssegundos exigida pelo gatilho do ultrassom
  digitalWrite(Trig, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  delayMicroseconds(20);  // gera temporizacao fina em microssegundos exigida pelo gatilho do ultrassom
  digitalWrite(Trig, LOW);     // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  float Fdistance = pulseIn(Echo, HIGH);    // mede a largura do pulso de eco para calcular a distancia por tempo de voo
  Fdistance= Fdistance / 58;         // executa etapa do firmware do robo tartaruga
  return (int)Fdistance;  // devolve o valor calculado ao chamador da funcao
}  

void setup() {   // define rotina de atuacao, leitura ou protocolo do robo
  myservo.attach(servoPIN,500,2500);    // associa o objeto servo ao pino de sinal com pulsos de 500 a 2500 microssegundos
  myservo.write(90);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor

  Serial.begin(9600);       // inicializa a UART de depuracao para o Monitor Serial
  pinMode(Echo, INPUT);      // configura o pino como entrada ou saida digital antes do uso
  pinMode(Trig, OUTPUT);    // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN1, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN2, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN3, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN4, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENA, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENB, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  ledcSetup(ENA,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcSetup(ENB,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcAttachPin(ENA_PIN,ENA);  // associa o pino fisico de enable ao canal LEDC configurado
  ledcAttachPin(ENB_PIN,ENB);  // associa o pino fisico de enable ao canal LEDC configurado
  Stop();  // executa etapa do firmware do robo tartaruga
} 

void loop() {   // define rotina de atuacao, leitura ou protocolo do robo
    myservo.write(90);  //setservo position according to scaled value   
    delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    middleDistance = Distance_detection();  // executa etapa do firmware do robo tartaruga
    Serial.print("M:");  // envia telemetria ao Monitor Serial para validacao do ensaio
    Serial.println(middleDistance);  // envia telemetria ao Monitor Serial para validacao do ensaio
    delay(500);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    if(middleDistance <= 25) {       // decisao condicional que seleciona o comportamento autonomo
      Stop();  // executa etapa do firmware do robo tartaruga
      delay(200);                           // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      myservo.write(30);            // posiciona o servo no angulo indicado para varredura ou centragem do sensor
      delay(300);        // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      rightDistance = Distance_detection();  // executa etapa do firmware do robo tartaruga
      Serial.print("R:");  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(rightDistance);  // envia telemetria ao Monitor Serial para validacao do ensaio
      delay(300);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      myservo.write(90);                // posiciona o servo no angulo indicado para varredura ou centragem do sensor
      delay(200);                                                    // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      myservo.write(150);                // posiciona o servo no angulo indicado para varredura ou centragem do sensor
      delay(400);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      leftDistance = Distance_detection();  // executa etapa do firmware do robo tartaruga
      Serial.print("L:");  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(leftDistance);  // envia telemetria ao Monitor Serial para validacao do ensaio
      delay(300);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      myservo.write(90);                // posiciona o servo no angulo indicado para varredura ou centragem do sensor
      delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      if(rightDistance > leftDistance) {  // decisao condicional que seleciona o comportamento autonomo
        Stop();  // executa etapa do firmware do robo tartaruga
        delay(100);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        Back();  // executa etapa do firmware do robo tartaruga
        delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        Right();  // executa etapa do firmware do robo tartaruga
        delay(400);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      }
      else if(rightDistance < leftDistance) {  // ramo alternativo da decisao de navegacao autonoma
        Stop();  // executa etapa do firmware do robo tartaruga
        delay(100);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        Back();  // executa etapa do firmware do robo tartaruga
        delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        Left();  // executa etapa do firmware do robo tartaruga
        delay(400);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      }
      else if((rightDistance <= 25) || (leftDistance <= 25)) {  // ramo alternativo da decisao de navegacao autonoma
        Back();  // executa etapa do firmware do robo tartaruga
        delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      }
      else {  // ramo alternativo da decisao de navegacao autonoma
        Forward();  // executa etapa do firmware do robo tartaruga
      }
    }  
    else {  // ramo alternativo da decisao de navegacao autonoma
        Forward();  // executa etapa do firmware do robo tartaruga
    }                  
}

Gravação: carregue e solte em corredor com caixas. Resultado esperado: avança até 25 cm da parede, para, olha à direita e à esquerda com a torre, gira para o lado mais livre após curta ré e retoma. Com corredor sem saída nos três lados, dá ré extra. Acompanhe no Serial a 9600 as marcas M, R e L para auditar cada decisão. Se gira sempre para o mesmo lado, recalibre o zero do servo da Lição 3, porque braço torto viesa a comparação. Se bate antes de parar, reduza o cruzeiro de 255 para 200. Se a torre vibra sem medir, recarregue as baterias, pois servo faminto consome o pico e corrompe o eco.

💡 Dica: filme a torre em câmera lenta. A sequência 90, 30, 90, 150 e 90 deve ser nítida. Salto direto de 30 para 150 sem centrar indica bateria fraca que reinicia o movimento.

Lição 7 — Carro com controle remoto infravermelho

A sétima lição entrega comando humano sem fio com o controle do kit. O sketch inicializa o receptor, decodifica quadros NEC, mapeia setas em marcha e usa timeout de 200 ms para parar ao soltar o botão. A teoria é a modulação a 38 kHz com código de endereço e comando mais repetição enquanto o botão fica pressionado. O receptor filtra a portadora e entrega o quadro decodificado com flag de repetição, que o firmware trata reutilizando o último código válido para marcha contínua sem trancos. O timeout implementa homem-morto: sem quadro novo em 200 ms, a tração para, o que protege contra perda de enlace e contra botão preso. Os códigos do fabricante para este lote são UP 0xB946FF00, DOWN 0xEA15FF00, LEFT 0xBB44FF00, RIGHT 0xBC43FF00 e OK 0xBF40FF00, com dígitos e asterisco apenas reportados no Serial. Lote diferente de controle pode trocar os códigos sem trocar o protocolo, e a calibração se faz lendo o Serial e atualizando os case.

tsem_quadro>200 ms⇒Stopt_{sem\_quadro} > 200\,\text{ms} \Rightarrow \text{Stop} quadrorep→quadroultquadro_{rep} \rightarrow quadro_{ult}

onde tsem_quadrot_{sem\_quadro} é o tempo desde o último quadro válido. A taxa de repetição do controle em cerca de 110 ms garante pelo menos um quadro por janela de 200 ms com botão pressionado, e a ausência confirma soltura ou sombra. A óptica exige visada ao olho receptor sem obstrução do casco, e luz solar direta com componente de 38 kHz eleva o piso de ruído e encurta o alcance. A pilha CR2025 ou CR2032 fraca gera quadros corrompidos descartados que se manifestam como marcha picotada, indistinguível de sombra parcial sem o diagnóstico do Serial.

Componente necessárioFunção no ensaio
Receptor IR no chassiDecodificação dos quadros de 38 kHz
Controle remoto com pilha botãoTransmissor de setas e OK
ESP32, L298N, N20 e 18650Marcha comandada com parada segura
Lição 7 — Upload do controle infravermelhoLição 7 — Instalação da pilha e visada ao receptor
Conexão validadaPinoSentido
Sinal do receptorGPIO 15Entrada digital
TraçãoLEDC 3/4 com INsSaída

📦 Bibliotecas desta lição: IRremote por shirriff, z3t0, ArminJo (versão 4.1.2).

  • Via Gerenciador (recomendado): Sketch > Incluir Biblioteca > Gerenciar Bibliotecas… → buscar IRremote → selecionar 4.1.2 → Instalar → reiniciar a IDE.
  • Via ZIP: baixar em Arduino-IRremote/Arduino-IRremote (Code > Download ZIP) → Sketch > Incluir Biblioteca > Adicionar Biblioteca .ZIP… → reiniciar a IDE.
  • Conferência: Arquivo > Exemplos > IRremote > SimpleReceiver deve abrir e compilar. Erro IRremote.h: No such file indica versão errada ou pasta duplicada em libraries.
//www.kuongshun.com

#include <IRremote.h>  // inclui a biblioteca necessaria ao projeto

int receiver = 15;  // define rotina de atuacao, leitura ou protocolo do robo
/*define channel enable output pins*/  // executa etapa do firmware do robo tartaruga
#define ENA 3  // cria constante simbolica para pino ou parametro do hardware
#define ENA_PIN 25  // cria constante simbolica para pino ou parametro do hardware
#define IN1 26  // cria constante simbolica para pino ou parametro do hardware
#define IN2 27  // cria constante simbolica para pino ou parametro do hardware
#define IN3 14  // cria constante simbolica para pino ou parametro do hardware
#define IN4 12  // cria constante simbolica para pino ou parametro do hardware
#define ENB 4  // cria constante simbolica para pino ou parametro do hardware
#define ENB_PIN 13  // cria constante simbolica para pino ou parametro do hardware
#define carSpeed 200	// initial speed of car >=0 to <=255

IRrecv irrecv(receiver);  // executa etapa do firmware do robo tartaruga
uint32_t last_decodedRawData = 0;  // executa etapa do firmware do robo tartaruga
unsigned long lastCommandTime; // Record the time of the last received command
const unsigned long commandTimeout = 200; // Set the timeout period (milliseconds)

void translateIR() // takes action based on IR code received
{
  if (irrecv.decodedIRData.flags)// Check if it is a repeat IR code 
  {
    irrecv.decodedIRData.decodedRawData = last_decodedRawData;    //set the current decodedRawData to the last decodedRawData 
    Serial.println("REPEAT!");  // envia telemetria ao Monitor Serial para validacao do ensaio
  } else//output the IR code on the serial monitor
  {
    Serial.print("IR code:0x");  // envia telemetria ao Monitor Serial para validacao do ensaio
    Serial.println(irrecv.decodedIRData.decodedRawData, HEX);  // envia telemetria ao Monitor Serial para validacao do ensaio
  }
  switch (irrecv.decodedIRData.decodedRawData)//map the IR code to the remote key
  {
    case 0xB946FF00: Serial.println("UP"); Forward();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xEA15FF00: Serial.println("DOWN"); Back();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xBB44FF00: Serial.println("LEFT"); Left();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xBC43FF00: Serial.println("RIGHT"); Right();   break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xBF40FF00: Serial.println("OK"); Stop();   break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xAD52FF00: Serial.println("0");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xE916FF00: Serial.println("1");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xE619FF00: Serial.println("2");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xF20DFF00: Serial.println("3");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xF30CFF00: Serial.println("4");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xE718FF00: Serial.println("5");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xA15EFF00: Serial.println("6");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xF708FF00: Serial.println("7");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xE31CFF00: Serial.println("8");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xA55AFF00: Serial.println("9");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xBD42FF00: Serial.println("*");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    case 0xB54AFF00: Serial.println("#");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
    default:  // executa etapa do firmware do robo tartaruga
    Serial.println(" other button   ");  // envia telemetria ao Monitor Serial para validacao do ensaio
  }// End Case  
  last_decodedRawData = irrecv.decodedIRData.decodedRawData;//store the last decodedRawData
  //delay(500); // Do not get immediate repeat
} //END translateIR

void Forward(){   // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW); //set IN1 LOW level
  digitalWrite(IN2, HIGH);  //set IN2 HIGH level
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Forward");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Back() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Back");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Left() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Left");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Right() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Right");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Stop() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0); //enable L298n A channel
  ledcWrite(ENB, 0); //enable L298n B channel
  Serial.println("Stop!");  // envia telemetria ao Monitor Serial para validacao do ensaio
} 

void setup() {  // define rotina de atuacao, leitura ou protocolo do robo
  Serial.begin(9600);  // inicializa a UART de depuracao para o Monitor Serial
  pinMode(IN1,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN2,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN3,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN4,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENA,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENB,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(13, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  ledcSetup(ENA,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcSetup(ENB,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcAttachPin(ENA_PIN,ENA);  // associa o pino fisico de enable ao canal LEDC configurado
  ledcAttachPin(ENB_PIN,ENB);  // associa o pino fisico de enable ao canal LEDC configurado
  Stop();  // executa etapa do firmware do robo tartaruga
  irrecv.enableIRIn();// Start the receiver  
}

void loop() {  // define rotina de atuacao, leitura ou protocolo do robo
  if (irrecv.decode()) // have we received an IR signal?
  {
    lastCommandTime = millis(); // Update the last command time
    translateIR();  // executa etapa do firmware do robo tartaruga
    irrecv.resume(); // receive the next value
  }
  if (millis() - lastCommandTime > commandTimeout) {  // decisao condicional que seleciona o comportamento autonomo
    Stop();   // executa etapa do firmware do robo tartaruga
    // If no new IR signal within 100 milliseconds, stop the robot
  }
} 

Gravação: instale a CR2025 ou CR2032 no controle, carregue o sketch e ligue o robô no chão. Resultado esperado: seta para cima avança, para baixo recua, esquerda e direita giram, tudo apenas enquanto o botão fica pressionado, e OK ou soltura para em até 200 ms, com códigos impressos no Serial a 9600. Se nenhum botão responde, confira visada, pilha e GPIO 15 no fio real. Se responde com códigos diferentes dos case, anote os códigos do seu Serial e atualize os cinco case de direção sem alterar a lógica de timeout. Se anda sozinho sem tocar, há fonte de 38 kHz próxima como TV ou sol direto no receptor.

⚠️ Atenção: timeout de 200 ms é segurança, não atraso. Não aumente para suavizar marcha, pois o robô passa a andar metros após soltar o botão em velocidade plena.

Lição 8 — Carro WiFi via página Web

A oitava lição corta o fio do USB e coloca o comando no navegador do celular. O ESP32 sobe em modo AP com SSID KUONGSHUN-AD177 e senha 12345678, anuncia o IP 192.168.4.1 e serve uma página com botões de marcha que disparam requisições com parâmetros de comando. A teoria é o WiFi em modo AP com servidor HTTP embarcado: o ESP32 é o roteador da sua própria célula sem internet, o celular associa e mantém a conexão mesmo com aviso de sem internet, e cada toque no botão gera um GET com variável e valor que o handler converte em marcha. O canal 9 fixo reduz disputa com roteadores domésticos nos canais 1 e 6, e a potência de 19,5 dBm maximiza alcance indoor ao custo de consumo que exige bateria cheia. A latência de toque a roda é a soma do tempo de ida do HTTP com o tempo de atuação da ponte, na casa de centenas de milissegundos, e soltar o botão envia o comando de parada, o mesmo homem-morto do infravermelho agora sobre TCP. O aviso de sem internet no celular deve ser mantido conectado, nunca alternado para dados móveis, senão o comando cai no meio da curva.

tresposta=tHTTP+tpontet_{resposta} = t_{HTTP} + t_{ponte} rede: IP=192.168.4.1,canal=9\text{rede: } IP = 192.168.4.1,\quad \text{canal} = 9

onde tHTTPt_{HTTP} é a ida e volta na célula AP e tpontet_{ponte} a comutação do L298N. O throughput necessário é mínimo porque comandos têm bytes, sem vídeo neste kit, o que torna o enlace robusto mesmo com sinal fraco. A segurança é física: sem senha não há comando, e sem associação o robô fica parado aguardando cliente. O firmware divide-se em dois arquivos: o .ino configura WiFi, imprime o IP e delega ao servidor, e o app_httpd.cpp implementa Car_init, as marchas e o cmd_handler que interpreta var=car com val de 1 a 5. A velocidade é plena com duty 255, adequada para demonstração em quadra lisa.

Componente necessárioFunção no ensaio
ESP32 com rádio WiFiPonto de acesso e servidor HTTP
Celular ou tabletNavegador com botões de marcha
ESP32, L298N, N20 e 18650Marcha comandada pela página
Lição 8 — Upload do carro Web WiFiLição 8 — Conexão ao hotspot KUONGSHUN-AD177
Lição 8 — Página de comando em 192.168.4.1
Conexão validadaParâmetroValor
SSID do APKUONGSHUN-AD177Rede aberta pelo robô
Senha12345678Oito dígitos fixos do firmware
Portal192.168.4.1Página com avante, ré, esquerda e direita
TraçãoDuty 255Marcha plena com parada ao soltar

📦 Bibliotecas desta lição: WiFi e esp_http_server — embutidas no núcleo ESP32 2.0.12, nada a baixar.

  • Instalação: nenhuma. Confira em Arquivo > Exemplos > WiFi > WiFiScan que o exemplo abre e compila para ESP32 Dev Module.
//www.kuongshun.com

#include <WiFi.h>  // inclui a biblioteca necessaria ao projeto

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


void startServer();  // inicializa o servidor HTTP ou TCP que atende o navegador e o aplicativo
void Car_init();  // define rotina de atuacao, leitura ou protocolo do robo


void setup() {   // define rotina de atuacao, leitura ou protocolo do robo
  Serial.begin(9600);  // inicializa a UART de depuracao para o Monitor Serial
  WiFi.setTxPower(WIFI_POWER_19_5dBm);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
  WiFi.mode(WIFI_AP);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
  WiFi.softAP(ssid, password, 9);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
  IPAddress myIP = WiFi.softAPIP();  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
  Serial.print("AP IP address: ");  // envia telemetria ao Monitor Serial para validacao do ensaio
  Serial.println(myIP); //probar 192.168.4.1
  Car_init();  // executa etapa do firmware do robo tartaruga
  startServer();  // inicializa o servidor HTTP ou TCP que atende o navegador e o aplicativo
}

void loop() {   // define rotina de atuacao, leitura ou protocolo do robo

}

Arquivo complementar app_httpd.cpp do modo Web, com servidor, marchas e interpretador de comandos da página:

#include "Arduino.h"  // inclui a biblioteca necessaria ao projeto
#include "esp_http_server.h"  // inclui a biblioteca necessaria ao projeto
#include <ESP32Servo.h>  // inclui a biblioteca necessaria ao projeto
#define ENA 3  // cria constante simbolica para pino ou parametro do hardware
#define ENA_PIN 25  // cria constante simbolica para pino ou parametro do hardware
#define IN1 26  // cria constante simbolica para pino ou parametro do hardware
#define IN2 27  // cria constante simbolica para pino ou parametro do hardware
#define IN3 14  // cria constante simbolica para pino ou parametro do hardware
#define IN4 12  // cria constante simbolica para pino ou parametro do hardware
#define ENB 4  // cria constante simbolica para pino ou parametro do hardware
#define ENB_PIN 13  // cria constante simbolica para pino ou parametro do hardware
#define carSpeed 255	// initial speed of car >=0 to <=255
#define LED 4  // cria constante simbolica para pino ou parametro do hardware

int val=0;  // define rotina de atuacao, leitura ou protocolo do robo
bool state = LOW;  // executa etapa do firmware do robo tartaruga
typedef struct {  // executa etapa do firmware do robo tartaruga
        httpd_req_t *req;  // executa etapa do firmware do robo tartaruga
        size_t len;  // executa etapa do firmware do robo tartaruga
} jpg_chunking_t;

httpd_handle_t camera_httpd = NULL;  // executa etapa do firmware do robo tartaruga
void stateChange(){  // define rotina de atuacao, leitura ou protocolo do robo
  state = !state;  // executa etapa do firmware do robo tartaruga
  digitalWrite(4, state);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Light");    // envia telemetria ao Monitor Serial para validacao do ensaio
}
void Car_init(){  // define rotina de atuacao, leitura ou protocolo do robo
  pinMode(LED, OUTPUT);   // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN1,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN2,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN3,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN4,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENA,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENB,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  ledcSetup(ENA,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcSetup(ENB,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcAttachPin(ENA_PIN,ENA);  // associa o pino fisico de enable ao canal LEDC configurado
  ledcAttachPin(ENB_PIN,ENB);  // associa o pino fisico de enable ao canal LEDC configurado
}

void Forward(){   // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Forward");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Back() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Back");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Left() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Left");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Right() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Right");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Stop() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0); //enable L298n A channel
  ledcWrite(ENB, 0); //enable L298n B channel
  Serial.println("Stop!");  // envia telemetria ao Monitor Serial para validacao do ensaio
} 

static esp_err_t cmd_handler(httpd_req_t *req)  // executa etapa do firmware do robo tartaruga
{
    char*  buf;  // executa etapa do firmware do robo tartaruga
    size_t buf_len;  // executa etapa do firmware do robo tartaruga
    char variable[32] = {0,};  // executa etapa do firmware do robo tartaruga
    char value[32] = {0,};  // executa etapa do firmware do robo tartaruga

    buf_len = httpd_req_get_url_query_len(req) + 1;  // executa etapa do firmware do robo tartaruga
    if (buf_len > 1) {  // decisao condicional que seleciona o comportamento autonomo
        buf = (char*)malloc(buf_len);  // executa etapa do firmware do robo tartaruga
        if(!buf){  // decisao condicional que seleciona o comportamento autonomo
            httpd_resp_send_500(req);  // executa etapa do firmware do robo tartaruga
            return ESP_FAIL;  // devolve o valor calculado ao chamador da funcao
        }
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {  // decisao condicional que seleciona o comportamento autonomo
            if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&  // decisao condicional que seleciona o comportamento autonomo
                httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) {  // executa etapa do firmware do robo tartaruga
            } else {  // ramo alternativo da decisao de navegacao autonoma
                free(buf);  // executa etapa do firmware do robo tartaruga
                httpd_resp_send_404(req);  // executa etapa do firmware do robo tartaruga
                return ESP_FAIL;  // devolve o valor calculado ao chamador da funcao
            }
        } else {  // ramo alternativo da decisao de navegacao autonoma
            free(buf);  // executa etapa do firmware do robo tartaruga
            httpd_resp_send_404(req);  // executa etapa do firmware do robo tartaruga
            return ESP_FAIL;  // devolve o valor calculado ao chamador da funcao
        }
        free(buf);  // executa etapa do firmware do robo tartaruga
    } else {  // ramo alternativo da decisao de navegacao autonoma
        httpd_resp_send_404(req);  // executa etapa do firmware do robo tartaruga
        return ESP_FAIL;  // devolve o valor calculado ao chamador da funcao
    }

    val = atoi(value);  // executa etapa do firmware do robo tartaruga
    int res = 0;  // define rotina de atuacao, leitura ou protocolo do robo

    if(!strcmp(variable, "car"))   // decisao condicional que seleciona o comportamento autonomo
    {  
      if (val==1)   // decisao condicional que seleciona o comportamento autonomo
      {
        Serial.println("claw_x");  // envia telemetria ao Monitor Serial para validacao do ensaio
        Forward();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);
      }
      else if (val==2)   // ramo alternativo da decisao de navegacao autonoma
      {   
        Serial.println("claw_y");  // envia telemetria ao Monitor Serial para validacao do ensaio
        Back();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);
      }
      else if (val==3)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("Stop");    // envia telemetria ao Monitor Serial para validacao do ensaio
        Stop();        // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2); 
      }
      else if (val==4)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("turn_x");  // envia telemetria ao Monitor Serial para validacao do ensaio
        Left();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);        
      }
      else if (val==5)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("turn_y");         // envia telemetria ao Monitor Serial para validacao do ensaio
        Right();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);              
      }
      else if (val==6)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("upper_arm_x");        // envia telemetria ao Monitor Serial para validacao do ensaio
        stateChange();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);              
      }
      else if (val==7)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("upper_arm_y");        // envia telemetria ao Monitor Serial para validacao do ensaio
        stateChange();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);              
      }
      else if (val==8)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("lower_arm_x");        // envia telemetria ao Monitor Serial para validacao do ensaio
        stateChange();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);              
      }
      else if (val==9)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("lower_arm_y");         // envia telemetria ao Monitor Serial para validacao do ensaio
        stateChange();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);              
      }
      else if (val==10)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("Reset");      // envia telemetria ao Monitor Serial para validacao do ensaio
      stateChange();  // executa etapa do firmware do robo tartaruga
      Stop();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);              
      }
      else if (val==11)   // ramo alternativo da decisao de navegacao autonoma
      {
        Serial.println("Reset");       // envia telemetria ao Monitor Serial para validacao do ensaio
        stateChange();  // executa etapa do firmware do robo tartaruga
        Stop();  // executa etapa do firmware do robo tartaruga
        //httpd_resp_set_type(req, "text/html");
        //return httpd_resp_send(req, "OK", 2);              
      }
    }        
    else   // ramo alternativo da decisao de navegacao autonoma
    { 
      Serial.println("variable");  // envia telemetria ao Monitor Serial para validacao do ensaio
      res = -1;   // executa etapa do firmware do robo tartaruga
    }

    if(res){ return httpd_resp_send_500(req); }  // decisao condicional que seleciona o comportamento autonomo

    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");  // executa etapa do firmware do robo tartaruga
    return httpd_resp_send(req, NULL, 0);  // devolve o valor calculado ao chamador da funcao
}

static const char PROGMEM INDEX_HTML[] = R"rawliteral(  // executa etapa do firmware do robo tartaruga
<!doctype html>  // executa etapa do firmware do robo tartaruga
<html>  // executa etapa do firmware do robo tartaruga
    <head>  // executa etapa do firmware do robo tartaruga
        <meta charset="utf-8">  // executa etapa do firmware do robo tartaruga
        <meta name="viewport" content="width=device-width,initial-scale=1">  // executa etapa do firmware do robo tartaruga
        <title>KUONGSHUN Turtle ROBOT</title>  // executa etapa do firmware do robo tartaruga
        <style>  // executa etapa do firmware do robo tartaruga
            *{  // executa etapa do firmware do robo tartaruga
                padding: 0; margin: 0;  // executa etapa do firmware do robo tartaruga
                font-family:monospace;  // executa etapa do firmware do robo tartaruga
            }

            *{    // executa etapa do firmware do robo tartaruga
                -webkit-touch-callout:none;    // executa etapa do firmware do robo tartaruga
                -webkit-user-select:none;    // executa etapa do firmware do robo tartaruga
                -khtml-user-select:none;    // executa etapa do firmware do robo tartaruga
                -moz-user-select:none;    // executa etapa do firmware do robo tartaruga
                -ms-user-select:none;    // executa etapa do firmware do robo tartaruga
                user-select:none;    // executa etapa do firmware do robo tartaruga
            }

        canvas {  // executa etapa do firmware do robo tartaruga
        margin: auto;  // executa etapa do firmware do robo tartaruga
        display: block;  // executa etapa do firmware do robo tartaruga

        }
        .tITULO{  // executa etapa do firmware do robo tartaruga
            text-align: center;  // executa etapa do firmware do robo tartaruga
            color: rgb(97, 97, 97);  // executa etapa do firmware do robo tartaruga

        }
        .LINK{  // executa etapa do firmware do robo tartaruga
            color: red;  // executa etapa do firmware do robo tartaruga
            width: 60px;  // executa etapa do firmware do robo tartaruga
            margin: auto;  // executa etapa do firmware do robo tartaruga
            display: block;  // executa etapa do firmware do robo tartaruga
            font-size: 14px;  // executa etapa do firmware do robo tartaruga
        }
        .cont_flex{  // executa etapa do firmware do robo tartaruga
            margin: 20px auto 20px;  // executa etapa do firmware do robo tartaruga
            width: 70%;  // executa etapa do firmware do robo tartaruga
            max-width: 400px;  // executa etapa do firmware do robo tartaruga
            display: flex;  // executa etapa do firmware do robo tartaruga
            flex-wrap: wrap;  // executa etapa do firmware do robo tartaruga
            justify-content: space-around;  // executa etapa do firmware do robo tartaruga
        }
        .cont_flex_model{  // executa etapa do firmware do robo tartaruga
            margin: 20px auto 20px;  // executa etapa do firmware do robo tartaruga
            width: 78%;  // executa etapa do firmware do robo tartaruga
            max-width: 400px;  // executa etapa do firmware do robo tartaruga
            display: flex;  // executa etapa do firmware do robo tartaruga
            flex-wrap: wrap;  // executa etapa do firmware do robo tartaruga
            justify-content: space-around;  // executa etapa do firmware do robo tartaruga
        }
        .cont_flex button{  // executa etapa do firmware do robo tartaruga
            width: 70px;  // executa etapa do firmware do robo tartaruga
            height: 30px;  // executa etapa do firmware do robo tartaruga
            border: none;  // executa etapa do firmware do robo tartaruga
            background-color: red;  // executa etapa do firmware do robo tartaruga
            border-radius: 10px;  // executa etapa do firmware do robo tartaruga
            color: white;  // executa etapa do firmware do robo tartaruga

        }
        .cont_flex_model button{  // executa etapa do firmware do robo tartaruga
            width: 100px;  // executa etapa do firmware do robo tartaruga
            height: 30px;  // executa etapa do firmware do robo tartaruga
            border: none;  // executa etapa do firmware do robo tartaruga
            background-color: yellow;  // executa etapa do firmware do robo tartaruga
            border-radius: 10px;  // executa etapa do firmware do robo tartaruga
            color: black;  // executa etapa do firmware do robo tartaruga
        }
        .cont_flex button:active{  // executa etapa do firmware do robo tartaruga
            background-color: green;  // executa etapa do firmware do robo tartaruga
        }
        .cont_flex_model button:active{  // executa etapa do firmware do robo tartaruga
            background-color: green;  // executa etapa do firmware do robo tartaruga
        }

        input{-webkit-user-select:auto;}   // executa etapa do firmware do robo tartaruga
        input[type=range]{-webkit-appearance:none;width:300px;height:25px;background:#cecece;cursor:pointer;margin:0}  // executa etapa do firmware do robo tartaruga
        input[type=range]:focus{outline:0}  // executa etapa do firmware do robo tartaruga
        input[type=range]::-webkit-slider-runnable-track{width:100%;height:2px;cursor:pointer;background:#EFEFEF;border-radius:0;border:0 solid #EFEFEF}  // executa etapa do firmware do robo tartaruga
        input[type=range]::-webkit-slider-thumb{border:1px solid rgba(0,0,30,0);height:22px;width:22px;border-radius:50px;background:#ff3034;cursor:pointer;-webkit-appearance:none;margin-top:-10px}  // executa etapa do firmware do robo tartaruga

        </style>  // executa etapa do firmware do robo tartaruga
    </head>  // executa etapa do firmware do robo tartaruga
    <body>       // executa etapa do firmware do robo tartaruga
        <h1 class="tITULO">KUONGSHUN Turtle ROBOT</h1>  // executa etapa do firmware do robo tartaruga
        <div class="cont_flex">       // executa etapa do firmware do robo tartaruga
            <button type="button" id="Forward" ontouchstart="fetch(document.location.origin+'/control?var=car&val=1');"ontouchend="fetch(document.location.origin+'/control?var=car&val=3');">Forward</button>  // executa etapa do firmware do robo tartaruga
        </div>  // executa etapa do firmware do robo tartaruga

        <div class="cont_flex">       // executa etapa do firmware do robo tartaruga
            <button type="button" id="TurnLeft" ontouchstart="fetch(document.location.origin+'/control?var=car&val=4');"ontouchend="fetch(document.location.origin+'/control?var=car&val=3');">Turnleft</button>  // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="stop" ontouchstart="fetch(document.location.origin+'/control?var=car&val=10');">Reset</button>    -->  // executa etapa do firmware do robo tartaruga
            <button type="button" id="TurnRight" ontouchstart="fetch(document.location.origin+'/control?var=car&val=5');"ontouchend="fetch(document.location.origin+'/control?var=car&val=3');">TurnRight</button>    // executa etapa do firmware do robo tartaruga
        </div>  // executa etapa do firmware do robo tartaruga

        <div class="cont_flex">       // executa etapa do firmware do robo tartaruga
            <button type="button" id="Backward" ontouchstart="fetch(document.location.origin+'/control?var=car&val=2');"ontouchend="fetch(document.location.origin+'/control?var=car&val=3');">Backward</button>  // executa etapa do firmware do robo tartaruga
        </div>  // executa etapa do firmware do robo tartaruga

        <p><br></p>  // executa etapa do firmware do robo tartaruga

        <div class="cont_flex">       // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="upper_arm_x" ontouchstart="fetch(document.location.origin+'/control?var=car&val=6');"ontouchend="fetch(document.location.origin+'/control?var=car&val=3');">upper_arm_x</button>  -->  // executa etapa do firmware do robo tartaruga
        </div>  // executa etapa do firmware do robo tartaruga

        <div class="cont_flex">       // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="lower_arm_x" ontouchstart="fetch(document.location.origin+'/control?var=car&val=8');"ontouchend="fetch(document.location.origin+'/control?var=car&val=3');">lower_arm_x</button>  -->  // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="stop" ontouchstart="fetch(document.location.origin+'/control?var=car&val=11');">Reset</button>    -->  // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="lower_arm_y" ontouchstart="fetch(document.location.origin+'/control?var=car&val=9');"ontouchend="fetch(document.location.origin+'/control?var=car&val=3');">lower_arm_y</button>  -->  // executa etapa do firmware do robo tartaruga
        </div>  // executa etapa do firmware do robo tartaruga

        <div class="cont_flex_model">       // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="model1" onmousedown="fetch(document.location.origin+'/control?var=car&val=6');">Free Control</button>-->  // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="model2" onmousedown="fetch(document.location.origin+'/control?var=model&val=7');">Obstacle Avoidance</button>-->  // executa etapa do firmware do robo tartaruga
        </div>  // executa etapa do firmware do robo tartaruga

        <div class="cont_flex_model">       // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="model3" onmousedown="fetch(document.location.origin+'/control?var=model&val=8');">Object Following</button>-->  // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="model4" onmousedown="fetch(document.location.origin+'/control?var=model&val=9');">Line Tracing</button>-->  // executa etapa do firmware do robo tartaruga
        </div>  // executa etapa do firmware do robo tartaruga

        <div class="cont_flex">       // executa etapa do firmware do robo tartaruga
        <!--    <button type="button" id="upper_arm_y" ontouchstart="fetch(document.location.origin+'/control?var=car&val=7');"ontouchend="fetch(document.location.origin+'/control?var=car&val=3');">upper_arm_y</button>  -->  // executa etapa do firmware do robo tartaruga
        </div>  // executa etapa do firmware do robo tartaruga

        <script>  // executa etapa do firmware do robo tartaruga
            window.onload = function(){  // executa etapa do firmware do robo tartaruga
                var canvas = document.getElementById("canvas");  // executa etapa do firmware do robo tartaruga
                var ctx = canvas.getContext("2d");  // executa etapa do firmware do robo tartaruga

                ctx.fillStyle = "rgb(255,0,0)";  // executa etapa do firmware do robo tartaruga
                ctx.fillRect(73,25,60,35);  // executa etapa do firmware do robo tartaruga
                ctx.clearRect(78,30,50,25);  // executa etapa do firmware do robo tartaruga

                ctx.fillRect(93,20,20,5);  // executa etapa do firmware do robo tartaruga
                ctx.fillRect(68,35,5,15);  // executa etapa do firmware do robo tartaruga
                ctx.fillRect(133,35,5,15);  // executa etapa do firmware do robo tartaruga

                ctx.beginPath();  // executa etapa do firmware do robo tartaruga
                ctx.arc(92,42,6,0,2*Math.PI,true);  // executa etapa do firmware do robo tartaruga
                ctx.fill();  // executa etapa do firmware do robo tartaruga

                ctx.beginPath();  // executa etapa do firmware do robo tartaruga
                ctx.arc(117,42,6,0,2*Math.PI,true);  // executa etapa do firmware do robo tartaruga
                ctx.fill();  // executa etapa do firmware do robo tartaruga

Gravação e operação: carregue com USB, desconecte, ligue com baterias e aguarde o LED do ESP32 aceso. No celular, abra o WiFi, conecte em KUONGSHUN-AD177 com 12345678 e mantenha mesmo com aviso de sem internet. Abra o navegador em 192.168.4.1. Resultado esperado: a página mostra os quatro botões, pressionar avança e soltar para, com a mesma resposta das lições com fio. Se a rede não aparece, confira bateria e fiação de alimentação da ESP32 e do L298N, pois rádio sem corrente não anuncia SSID. Se abre a página mas não anda, confira se outro sketch com servidor ficou gravado antes e recarregue este modo. Se o celular alterna para dados móveis, desative dados durante o ensaio.

⚠️ Atenção: mantenha o aviso de sem internet conectado. Trocar para dados móveis no meio do ensaio derruba o comando e o robô segue na última marcha até o timeout.

Lição 9 — Carro Web multifunção com modos autônomos

A nona lição funde tudo em um portal único: comando livre mais botões de linha, seguimento, desvio e infravermelho, com sliders de servo e velocidade. O sketch mantém o mesmo AP e portal, mas o app_httpd.cpp ampliado interpreta comandos de modo além de marcha, e o laço principal executa a máquina do modo ativo enquanto atende a rede e o infravermelho em paralelo. A teoria é a multiplexação cooperativa: cada modo autônomo roda em fatias de 50 ms intercaladas com leitura de rede, de modo que um toque de modo troca o comportamento sem regravar. O modo livre obedece aos botões direcionais, o desvio executa a varredura da Lição 6, o seguimento executa as zonas da Lição 5, e a linha executa a máquina da Lição 4, tudo com o mesmo mapa de pinos. O slider de servo ajusta o pan manualmente no modo livre para mirar o ultrassom, e o slider de velocidade reescreve carSpeed em tempo real, o que demonstra o efeito de DD sem recompilar. A atenção crítica é o pino do receptor neste sketch do fabricante, declarado como 5 em vez de 15: confira o fio real do passo 11 e iguale o #define ao hardware antes de culpar o controle.

modo∈{livre,desvio,seguimento,linha}modo \in \{livre, desvio, seguimento, linha\} v=D(slider)⋅(Vbat−Vdrop)v = D( slider ) \cdot (V_{bat} - V_{drop})

onde D(slider)D(slider) é o duty comandado pelo controle deslizante de 0 a 255. A transição de modo preserva a segurança com parada intermediária, e a vigilância de rede a cada 50 ms impede travamento em modo autônomo sem comando. A latência de troca é de uma a duas fatias, imperceptível em demonstração. A telemetria no Serial a 9600 registra modo e comando, auditoria útil quando o robô parece ignorar o botão porque está em modo autônomo diferente do imaginado.

Componente necessárioFunção no ensaio
Todos os sensores calibradosEntradas dos quatro modos
Celular com navegadorPortal multifunção com sliders
Controle IR com pilhaComando redundante ao Web
Lição 9 — Upload do Web multifunçãoLição 9 — Portal com modos e sliders
Conexão e modoValorObservação
AP e portalKUONGSHUN-AD177 em 192.168.4.1Mesmo acesso da Lição 8
Modo livreBotões direcionaisMarcha com parada ao soltar
Modo desvioBotão de obstáculoVarredura 90, 30 e 150 graus
Modo seguimentoBotão de followZonas 15, 20, 25 e 50 cm
Modo linhaBotão de trackingMáquina de três canais
Receptor IRGPIO 5 no código, 15 no chassi típicoIgualar código ao fio real

📦 Bibliotecas desta lição: IRremote 4.1.2 por shirriff, z3t0, ArminJo mais WiFi embutida no núcleo 2.0.12.

  • Via Gerenciador: conferir IRremote em 3 selecionada em 4.1.2 instalada. WiFi dispensa instalação.
  • Divergência de pino: o sketch declara receptor em 5. Se seu chicote está em 15 do passo 11, altere o #define para 15 antes de carregar e anote na tampa com caneta.
//www.kuongshun.com

#include <WiFi.h>  // inclui a biblioteca necessaria ao projeto
#include <IRremote.h>  // inclui a biblioteca necessaria ao projeto

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

int receiver = 5;  // define rotina de atuacao, leitura ou protocolo do robo
IRrecv irrecv(receiver);  // executa etapa do firmware do robo tartaruga
uint32_t last_decodedRawData = 0;  // executa etapa do firmware do robo tartaruga

void startServer();  // inicializa o servidor HTTP ou TCP que atende o navegador e o aplicativo
void Car_init();  // define rotina de atuacao, leitura ou protocolo do robo
void Line_Tracing_mode();  // define rotina de atuacao, leitura ou protocolo do robo
void Obstacles_Avoidance_mode();  // define rotina de atuacao, leitura ou protocolo do robo
void Object_Following_mode();  // define rotina de atuacao, leitura ou protocolo do robo
void Forward();  // define rotina de atuacao, leitura ou protocolo do robo
void Back();  // define rotina de atuacao, leitura ou protocolo do robo
void Left();  // define rotina de atuacao, leitura ou protocolo do robo
void Right();  // define rotina de atuacao, leitura ou protocolo do robo
void Stop();   // define rotina de atuacao, leitura ou protocolo do robo

void getIRData() // takes action based on IR code received
{
  if (irrecv.decode()) // have we received an IR signal?
  {
    if (irrecv.decodedIRData.flags)// Check if it is a repeat IR code
    {
      irrecv.decodedIRData.decodedRawData = last_decodedRawData;    //set the current decodedRawData to the last decodedRawData
      Serial.println("REPEAT!");  // envia telemetria ao Monitor Serial para validacao do ensaio
    } else//output the IR code on the serial monitor
    {
      Serial.print("IR code:0x");  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(irrecv.decodedIRData.decodedRawData, HEX);  // envia telemetria ao Monitor Serial para validacao do ensaio
    }
    switch (irrecv.decodedIRData.decodedRawData)//map the IR code to the remote key
    {
      case 0xB946FF00: Serial.println("UP"); Forward();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xEA15FF00: Serial.println("DOWN"); Back();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xBB44FF00: Serial.println("LEFT"); Left();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xBC43FF00: Serial.println("RIGHT"); Right();   break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xBF40FF00: Serial.println("OK"); Stop();   break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xAD52FF00: Serial.println("0");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xE916FF00: Serial.println("1");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xE619FF00: Serial.println("2");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xF20DFF00: Serial.println("3");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xF30CFF00: Serial.println("4");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xE718FF00: Serial.println("5");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xA15EFF00: Serial.println("6");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xF708FF00: Serial.println("7");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xE31CFF00: Serial.println("8");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xA55AFF00: Serial.println("9");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xBD42FF00: Serial.println("*");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xB54AFF00: Serial.println("#");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      default:  // executa etapa do firmware do robo tartaruga
        Serial.println(" other button   ");  // envia telemetria ao Monitor Serial para validacao do ensaio
    }// End Case
    last_decodedRawData = irrecv.decodedIRData.decodedRawData;//store the last decodedRawData
    delay(100); // Do not get immediate repeat
  }
  irrecv.resume(); // receive the next value
} //END translateIR



void setup() {  // define rotina de atuacao, leitura ou protocolo do robo
  Serial.begin(9600);  // inicializa a UART de depuracao para o Monitor Serial
  WiFi.setTxPower(WIFI_POWER_19_5dBm);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
  WiFi.mode(WIFI_AP);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
  WiFi.softAP(ssid, password, 9);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
  IPAddress myIP = WiFi.softAPIP();  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
  Serial.print("AP IP address: ");  // envia telemetria ao Monitor Serial para validacao do ensaio
  Serial.println(myIP); //probar 192.168.4.1
  Car_init();  // executa etapa do firmware do robo tartaruga
  startServer();  // inicializa o servidor HTTP ou TCP que atende o navegador e o aplicativo
  irrecv.enableIRIn();// Start the receiver  
}

void loop() {  // define rotina de atuacao, leitura ou protocolo do robo
  getIRData();  // executa etapa do firmware do robo tartaruga
  Object_Following_mode();    // executa etapa do firmware do robo tartaruga
  Obstacles_Avoidance_mode();  // executa etapa do firmware do robo tartaruga
  Line_Tracing_mode();  // executa etapa do firmware do robo tartaruga
}

Gravação e operação: carregue, conecte no AP, abra 192.168.4.1 e teste cada botão em sequência com espaço livre. Resultado esperado: setas movem com parada ao soltar, cada modo assume o comportamento da lição isolada correspondente, o slider do servo move a torre no modo livre e o slider de velocidade altera visivelmente o passo. Se o IR não responde só neste modo mas responde na Lição 7, o culpado é o pino 5 contra 15: ajuste e recarregue. Se um modo parece morto, confira se outro modo ficou ativo e volte ao livre antes de concluir defeito. Se a página carrega mas os sliders não atuam, recarregue sem cache do navegador.

💡 Dica: demonstre nesta ordem: livre, linha, seguimento e desvio. Cada modo pressupõe a calibração da lição isolada, e a ordem revela qual calibração falta quando um modo falha e os anteriores passam.

Lição 10 — Carro APP multifunção com protocolo em quadros

A décima lição troca o navegador pelo aplicativo KUONGSHUN com protocolo binário dedicado na porta TCP 100. O ESP32 mantém o mesmo AP, mas agora atende quadros FF 55 comprimento … com ação e dispositivo, o que permite D-pad analógico, sliders e troca de modo com menor overhead que HTTP. A teoria é o enquadramento com sincronismo: os bytes FF 55 marcam início, o comprimento delimita, e o parser só executa quadro completo, descartando ruído de rádio sem travar. As ações incluem correr com dispositivo de marcha, girar servo, ajustar velocidade e trocar func_mode entre 1 livre, 2 desvio, 3 seguimento e 4 linha. O laço atende o socket, o infravermelho e a máquina do modo ativo em paralelo, com vigilância de 50 fatias de 1 ms que aborta o modo ao chegar comando novo. O limiar de linha aqui é 2000 contagens no ADC de 12 bits, adequado à iluminação do ensaio do fabricante, e deve ser recalibrado ao seu piso sem tratar como defeito. O include residual de câmera neste sketch compila sem câmera e pode ser mantido para fidelidade ao kit.

quadro=[FF  55  len  … ]quadro = [FF\;55\;len\;\dots] func_mode∈{1,2,3,4},Black_Line=2000func\_mode \in \{1,2,3,4\},\quad Black\_Line = 2000

onde lenlen delimita o quadro e func_modefunc\_mode seleciona o comportamento. A taxa de quadros do APP em dezenas por segundo supera o clique do Web, o que suaviza o D-pad proporcional e justifica o modo APP para demonstração dinâmica. A porta 100 dedicada evita disputa com o HTTP da Lição 8, e a reconexão exige apenas reassociar no WiFi e tocar em conectar no APP, sem regravar. A segurança mantém o homem-morto: sem quadro em 200 ms no IR e sem cliente no socket, a tração para. A versão de firmware 0.12.21 impressa no Serial identifica este lote e ajuda no suporte.

Componente necessárioFunção no ensaio
Aplicativo KUONGSHUN instaladoD-pad, modos e sliders no protocolo em quadros
Celular com WiFiTransporte TCP na porta 100
Robô completo calibradoExecução dos quatro modos pelo APP
Lição 10 — Upload do APP multifunçãoLição 10 — Instalação do APK e do app na loja
Lição 10 — Conexão ao hotspot e abertura do APPLição 10 — Seleção do tartaruga ESP32 e conexão automática
Conexão e comandoValorObservação
APKUONGSHUN-AD177 com 12345678, canal 5Reassociar a cada ligada
APPKUONGSHUN com tartaruga ESP32Android por APK da pasta do kit, iOS pela loja
PortaTCP 100Toque em conectar se mostrar desconectado
ModosLivre, desvio, seguimento e linhaMesmos comportamentos das lições isoladas

📦 Bibliotecas desta lição: ESP32Servo 1.1.2 e IRremote 4.1.2 por shirriff, z3t0, ArminJo, mais WiFi embutida no núcleo 2.0.12.

  • Via Gerenciador: conferir as duas versões pinadas instaladas. Nada novo a baixar se as Lições 3 e 7 passaram.
  • Conferência: Arquivo > Exemplos > ESP32Servo > Sweep e IRremote > SimpleReceiver compilam. Receptor no GPIO 15 como na Lição 7.
#include <WiFi.h>  // inclui a biblioteca necessaria ao projeto
#include "esp_camera.h"  // inclui a biblioteca necessaria ao projeto
#include <ESP32Servo.h>  // inclui a biblioteca necessaria ao projeto
#include <Arduino.h>  // inclui a biblioteca necessaria ao projeto
#include <IRremote.h>  // inclui a biblioteca necessaria ao projeto

Servo myservo;  // executa etapa do firmware do robo tartaruga
#define Echo 18  // cria constante simbolica para pino ou parametro do hardware
#define Trig 19  // cria constante simbolica para pino ou parametro do hardware
#define servoPIN 16  // cria constante simbolica para pino ou parametro do hardware
#define ENA 3  // cria constante simbolica para pino ou parametro do hardware
#define ENA_PIN 25  // cria constante simbolica para pino ou parametro do hardware
#define IN1 26  // cria constante simbolica para pino ou parametro do hardware
#define IN2 27  // cria constante simbolica para pino ou parametro do hardware
#define IN3 14  // cria constante simbolica para pino ou parametro do hardware
#define IN4 12  // cria constante simbolica para pino ou parametro do hardware
#define ENB 4  // cria constante simbolica para pino ou parametro do hardware
#define ENB_PIN 13  // cria constante simbolica para pino ou parametro do hardware
#define LEFT_LINE_TRACJING          32  // cria constante simbolica para pino ou parametro do hardware
#define CENTER_LINE_TRACJING        35  // cria constante simbolica para pino ou parametro do hardware
#define right_LINE_TRACJING         34  // cria constante simbolica para pino ou parametro do hardware

#define CMD_RUN 1  // cria constante simbolica para pino ou parametro do hardware
#define CMD_GET 2  // cria constante simbolica para pino ou parametro do hardware
#define CMD_STANDBY 3  // cria constante simbolica para pino ou parametro do hardware
#define CMD_TRACK_1 4  // cria constante simbolica para pino ou parametro do hardware
#define CMD_TRACK_2 5  // cria constante simbolica para pino ou parametro do hardware
#define CMD_AVOID 6  // cria constante simbolica para pino ou parametro do hardware
#define CMD_FOLLOW 7  // cria constante simbolica para pino ou parametro do hardware


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

WiFiServer server(100);  // executa etapa do firmware do robo tartaruga
WiFiClient client;  // executa etapa do firmware do robo tartaruga

int receiver = 15;  // define rotina de atuacao, leitura ou protocolo do robo
IRrecv irrecv(receiver);  // executa etapa do firmware do robo tartaruga
uint32_t last_decodedRawData = 0;  // executa etapa do firmware do robo tartaruga
unsigned long lastCommandTime; // Record the time of the last received command
const unsigned long commandTimeout = 200; // Set the timeout period (milliseconds)


int Left_Tra_Value;  // define rotina de atuacao, leitura ou protocolo do robo
int Center_Tra_Value;  // define rotina de atuacao, leitura ou protocolo do robo
int Right_Tra_Value;  // define rotina de atuacao, leitura ou protocolo do robo
int Black_Line = 2000;//small is black
int Model1        = 25;                               // 模式1
int Model2        = 26;                               // 模式2
int Model3        = 27;                               // 模式3
int Model4        = 28;                               // 模式4
int carSpeed      = 200;                               // 速度
int Servo         = 90;                               // 舵机

int rightDistance = 0, leftDistance = 0, middleDistance = 0;  // define rotina de atuacao, leitura ou protocolo do robo

unsigned long IR_PreMillis;  // define rotina de atuacao, leitura ou protocolo do robo
unsigned long LT_PreMillis;  // define rotina de atuacao, leitura ou protocolo do robo


int func_mode =0;  // define rotina de atuacao, leitura ou protocolo do robo

String sendBuff;  // executa etapa do firmware do robo tartaruga
String Version = "Firmware Version is 0.12.21";  // executa etapa do firmware do robo tartaruga
byte dataLen, index_a = 0;  // executa etapa do firmware do robo tartaruga
char buffer[52];  // executa etapa do firmware do robo tartaruga
unsigned char prevc=0;  // define rotina de atuacao, leitura ou protocolo do robo
bool isStart = false;  // executa etapa do firmware do robo tartaruga
bool ED_client = true;  // executa etapa do firmware do robo tartaruga
bool WA_en = false;  // executa etapa do firmware do robo tartaruga
byte RX_package[17] = {0};  // executa etapa do firmware do robo tartaruga
uint16_t angle = 90;  // executa etapa do firmware do robo tartaruga
byte action =0;  // executa etapa do firmware do robo tartaruga
byte val = 0;  // executa etapa do firmware do robo tartaruga
char model_var = 0;  // executa etapa do firmware do robo tartaruga
int UT_distance = 0;  // define rotina de atuacao, leitura ou protocolo do robo


void Car_init(){  // define rotina de atuacao, leitura ou protocolo do robo
  myservo.attach(servoPIN,500,2500);    // associa o objeto servo ao pino de sinal com pulsos de 500 a 2500 microssegundos
  myservo.write(90);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor
  pinMode(IN1,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN2,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN3,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(IN4,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENA,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  pinMode(ENB,OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
  ledcSetup(ENA,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcSetup(ENB,5000,8);  // configura canal LEDC do ESP32 com frequencia e resolucao para PWM dos motores
  ledcAttachPin(ENA_PIN,ENA);  // associa o pino fisico de enable ao canal LEDC configurado
  ledcAttachPin(ENB_PIN,ENB);  // associa o pino fisico de enable ao canal LEDC configurado
  pinMode(Echo, INPUT);      // configura o pino como entrada ou saida digital antes do uso
  pinMode(Trig, OUTPUT);  // configura o pino como entrada ou saida digital antes do uso
}

 void Forward(){   // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}

void Forward_slow(){   // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0.6*carSpeed); //enable L298n A channel
  ledcWrite(ENB, 0.6*carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}

void Back() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Back");  // envia telemetria ao Monitor Serial para validacao do ensaio
}
void Back_slow() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0.7*carSpeed); //enable L298n A channel
  ledcWrite(ENB, 0.7*carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Back");  // envia telemetria ao Monitor Serial para validacao do ensaio
}

void Left() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, LOW);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}
void Left_single() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}
void Left_single_small() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0.6*carSpeed); //enable L298n A channel
  ledcWrite(ENB, 0.6*carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}
void Left_turn(){  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, 0.5*carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}

void Right() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  Serial.println("Right");  // envia telemetria ao Monitor Serial para validacao do ensaio
}
void Right_single() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}
void Right_single_small() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0.6*carSpeed); //enable L298n A channel
  ledcWrite(ENB, 0.6*carSpeed); //enable L298n B channel
  digitalWrite(IN1, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}
void Right_turn(){  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0.5*carSpeed); //enable L298n A channel
  ledcWrite(ENB, carSpeed); //enable L298n B channel
  digitalWrite(IN1, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN2, HIGH);   // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN3, LOW);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  digitalWrite(IN4, HIGH);  // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
}



void Stop() {  // define rotina de atuacao, leitura ou protocolo do robo
  ledcWrite(ENA, 0); //enable L298n A channel
  ledcWrite(ENB, 0); //enable L298n B channel
  Serial.println("Stop!");  // envia telemetria ao Monitor Serial para validacao do ensaio
} 

void getIRData() // takes action based on IR code received
{
  if (irrecv.decode()) // have we received an IR signal?
  {
    lastCommandTime = millis(); // Update the last command time
    if (irrecv.decodedIRData.flags)// Check if it is a repeat IR code
    {
      irrecv.decodedIRData.decodedRawData = last_decodedRawData;    //set the current decodedRawData to the last decodedRawData
      Serial.println("REPEAT!");  // envia telemetria ao Monitor Serial para validacao do ensaio
    } else//output the IR code on the serial monitor
    {
      Serial.print("IR code:0x");  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(irrecv.decodedIRData.decodedRawData, HEX);  // envia telemetria ao Monitor Serial para validacao do ensaio
    }
    switch (irrecv.decodedIRData.decodedRawData)//map the IR code to the remote key
    {
      case 0xB946FF00: Serial.println("UP"); Forward();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xEA15FF00: Serial.println("DOWN"); Back();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xBB44FF00: Serial.println("LEFT"); Left();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xBC43FF00: Serial.println("RIGHT"); Right();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xBF40FF00: Serial.println("OK"); Stop();break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xAD52FF00: Serial.println("0");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xE916FF00: Serial.println("1");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xE619FF00: Serial.println("2");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xF20DFF00: Serial.println("3");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xF30CFF00: Serial.println("4");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xE718FF00: Serial.println("5");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xA15EFF00: Serial.println("6");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xF708FF00: Serial.println("7");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xE31CFF00: Serial.println("8");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xA55AFF00: Serial.println("9");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xBD42FF00: Serial.println("*");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      case 0xB54AFF00: Serial.println("#");    break;  // envia telemetria ao Monitor Serial para validacao do ensaio
      default:  // executa etapa do firmware do robo tartaruga
        Serial.println(" other button   ");  // envia telemetria ao Monitor Serial para validacao do ensaio
    }// End Case
    last_decodedRawData = irrecv.decodedIRData.decodedRawData;//store the last decodedRawData
    //delay(100); // Do not get immediate repeat

  irrecv.resume(); // receive the next value
  }
  if ((millis() - lastCommandTime > commandTimeout)&&(lastCommandTime>0)){  // decisao condicional que seleciona o comportamento autonomo
      Stop();   // executa etapa do firmware do robo tartaruga
      lastCommandTime=0;  // executa etapa do firmware do robo tartaruga
    // If no new IR signal within 100 milliseconds, stop the robot
  }
} //END translateIR

int Distance_detection() {  // define rotina de atuacao, leitura ou protocolo do robo
  digitalWrite(Trig, LOW);     // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  delayMicroseconds(2);  // gera temporizacao fina em microssegundos exigida pelo gatilho do ultrassom
  digitalWrite(Trig, HIGH);    // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  delayMicroseconds(20);  // gera temporizacao fina em microssegundos exigida pelo gatilho do ultrassom
  digitalWrite(Trig, LOW);     // escreve nivel logico ALTO ou BAIXO definindo o sentido da ponte H
  float Fdistance = pulseIn(Echo, HIGH);    // mede a largura do pulso de eco para calcular a distancia por tempo de voo
  Fdistance= Fdistance / 58;         // executa etapa do firmware do robo tartaruga
  return (int)Fdistance;  // devolve o valor calculado ao chamador da funcao
}  

void Line_Tracing_mode() {  // define rotina de atuacao, leitura ou protocolo do robo
  if (func_mode == 4) {  // decisao condicional que seleciona o comportamento autonomo

    Left_Tra_Value = analogRead(LEFT_LINE_TRACJING);  // le o conversor AD do ESP32 no canal do sensor reflexivo de linha
    Center_Tra_Value = analogRead(CENTER_LINE_TRACJING);  // le o conversor AD do ESP32 no canal do sensor reflexivo de linha
    Right_Tra_Value = analogRead(right_LINE_TRACJING);  // le o conversor AD do ESP32 no canal do sensor reflexivo de linha
    /*Serial.println("l,c,r:");  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(Left_Tra_Value);  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(Center_Tra_Value);  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(Right_Tra_Value);*/  // envia telemetria ao Monitor Serial para validacao do ensaio
    if (Left_Tra_Value > Black_Line && Center_Tra_Value <= Black_Line && Right_Tra_Value > Black_Line) {  // decisao condicional que seleciona o comportamento autonomo
      Forward();  // executa etapa do firmware do robo tartaruga
    } else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value < Black_Line) {  // ramo alternativo da decisao de navegacao autonoma
      Right_single();  // executa etapa do firmware do robo tartaruga
    } else if (Left_Tra_Value >= Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line) {  // ramo alternativo da decisao de navegacao autonoma
      Right_turn();  // executa etapa do firmware do robo tartaruga
    } else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value >= Black_Line) {  // ramo alternativo da decisao de navegacao autonoma
      Left_turn();  // executa etapa do firmware do robo tartaruga
    } else if (Left_Tra_Value < Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line) {  // ramo alternativo da decisao de navegacao autonoma
      Left_single();  // executa etapa do firmware do robo tartaruga
    } else if (Left_Tra_Value >= Black_Line && Center_Tra_Value >= Black_Line && Right_Tra_Value >= Black_Line) {  // ramo alternativo da decisao de navegacao autonoma
      Forward();  // executa etapa do firmware do robo tartaruga
    } else if (Left_Tra_Value < Black_Line && Center_Tra_Value < Black_Line && Right_Tra_Value < Black_Line) {  // ramo alternativo da decisao de navegacao autonoma
      Forward();  // executa etapa do firmware do robo tartaruga
    }
    for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 4)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }

  }
}

void Obstacles_Avoidance_mode() {  // define rotina de atuacao, leitura ou protocolo do robo
  if (func_mode == 2) {  // decisao condicional que seleciona o comportamento autonomo

    myservo.write(90);  //setservo position according to scaled value   
    delay(300);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    middleDistance = Distance_detection();  // executa etapa do firmware do robo tartaruga
    Serial.print("M:");  // envia telemetria ao Monitor Serial para validacao do ensaio
    Serial.println(middleDistance);  // envia telemetria ao Monitor Serial para validacao do ensaio
    delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
        delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    if(middleDistance <= 25) {       // decisao condicional que seleciona o comportamento autonomo
      Stop();  // executa etapa do firmware do robo tartaruga
      delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }     
      delay(100);                      // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      myservo.write(30);            // posiciona o servo no angulo indicado para varredura ou centragem do sensor
      delay(200);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }     
      delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      rightDistance = Distance_detection();  // executa etapa do firmware do robo tartaruga
      Serial.print("R:");  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(rightDistance);  // envia telemetria ao Monitor Serial para validacao do ensaio
      delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
      delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      myservo.write(90);                // posiciona o servo no angulo indicado para varredura ou centragem do sensor
      delay(100);    // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
      delay(100);                                                  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      myservo.write(150);                // posiciona o servo no angulo indicado para varredura ou centragem do sensor
      delay(300);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
      delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      leftDistance = Distance_detection();  // executa etapa do firmware do robo tartaruga
      Serial.print("L:");  // envia telemetria ao Monitor Serial para validacao do ensaio
      Serial.println(leftDistance);  // envia telemetria ao Monitor Serial para validacao do ensaio
      delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
      delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      myservo.write(90);                // posiciona o servo no angulo indicado para varredura ou centragem do sensor
      delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
      delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      if(rightDistance > leftDistance) {  // decisao condicional que seleciona o comportamento autonomo
        Stop();  // executa etapa do firmware do robo tartaruga
        delay(100);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
        delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        Back();  // executa etapa do firmware do robo tartaruga
        delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
        delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        Right();  // executa etapa do firmware do robo tartaruga
        delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
        delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      }
      else if(rightDistance < leftDistance) {  // ramo alternativo da decisao de navegacao autonoma
        Stop();  // executa etapa do firmware do robo tartaruga
        delay(100);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
        delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        Back();  // executa etapa do firmware do robo tartaruga
        delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
        delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        Left();  // executa etapa do firmware do robo tartaruga
        delay(200);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
        delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      }
      else if((rightDistance <= 25) || (leftDistance <= 25)) {  // ramo alternativo da decisao de navegacao autonoma
        Back();  // executa etapa do firmware do robo tartaruga
        delay(100);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
        for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
        delay(100);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
      }
      else {  // ramo alternativo da decisao de navegacao autonoma
        Forward();  // executa etapa do firmware do robo tartaruga
      }
    }  
    else {  // ramo alternativo da decisao de navegacao autonoma
        Forward();  // executa etapa do firmware do robo tartaruga
    }
    delay(50);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga

          if(func_mode != 2)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
    delay(50);   // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
  }
}

void Object_Following_mode() {  // define rotina de atuacao, leitura ou protocolo do robo
  if (func_mode == 3) {  // decisao condicional que seleciona o comportamento autonomo
    myservo.write(90);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor
    UT_distance = Distance_detection();  // executa etapa do firmware do robo tartaruga
    Serial.println(UT_distance);  // envia telemetria ao Monitor Serial para validacao do ensaio
    if (UT_distance < 15) {  // decisao condicional que seleciona o comportamento autonomo
      Back_slow();  // executa etapa do firmware do robo tartaruga
    } else if (15 <= UT_distance && UT_distance <= 20) {  // ramo alternativo da decisao de navegacao autonoma
      Stop();  // executa etapa do firmware do robo tartaruga
    } else if (20 <= UT_distance && UT_distance <= 25) {  // ramo alternativo da decisao de navegacao autonoma
      Forward_slow();  // executa etapa do firmware do robo tartaruga
    } else if (25 <= UT_distance && UT_distance <= 50) {  // ramo alternativo da decisao de navegacao autonoma
      Forward();  // executa etapa do firmware do robo tartaruga
    } else {  // ramo alternativo da decisao de navegacao autonoma
      Stop();  // executa etapa do firmware do robo tartaruga
    }
    for(int i = 0;i < 50;i++)  // laco de varredura incremental do ensaio ou da vigilância de modo
        {
          delay(1);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
          Receive_data();  // executa etapa do firmware do robo tartaruga
          if(func_mode != 3)  // decisao condicional que seleciona o comportamento autonomo
            return ;  // devolve o valor calculado ao chamador da funcao
        }
  }
}




unsigned char readBuffer(int index_r)  // define rotina de atuacao, leitura ou protocolo do robo
{
  return buffer[index_r];   // devolve o valor calculado ao chamador da funcao
}
void writeBuffer(int index_w,unsigned char c)  // define rotina de atuacao, leitura ou protocolo do robo
{
  buffer[index_w]=c;  // executa etapa do firmware do robo tartaruga
}



void setup()  // define rotina de atuacao, leitura ou protocolo do robo
{
    Serial.setTimeout(10);  // executa etapa do firmware do robo tartaruga
    Serial.begin(115200);  // inicializa a UART de depuracao para o Monitor Serial
    Car_init();  // executa etapa do firmware do robo tartaruga

    //ESP32PWM::allocateTimer(1);

    delay(1000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno

    WiFi.setTxPower(WIFI_POWER_19_5dBm);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
    WiFi.mode(WIFI_AP);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
    WiFi.softAP(ssid, password, 5);  // configura o radio WiFi do ESP32 em modo ponto de acesso para comando
    Serial.print("\r\n");  // envia telemetria ao Monitor Serial para validacao do ensaio
    Serial.print("Camera Ready! Use 'http://");
    Serial.print(WiFi.softAPIP());  // envia telemetria ao Monitor Serial para validacao do ensaio
    Serial.println("' to connect");  // envia telemetria ao Monitor Serial para validacao do ensaio

    delay(100);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    server.begin();  // inicializa o servidor HTTP ou TCP que atende o navegador e o aplicativo
    delay(1000);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
    irrecv.enableIRIn();// Start the receiver  
}

void loop()  // define rotina de atuacao, leitura ou protocolo do robo
{
    RXpack_func();  // executa etapa do firmware do robo tartaruga
    getIRData();  // executa etapa do firmware do robo tartaruga
    //model4_func();
}

void functionMode()  // define rotina de atuacao, leitura ou protocolo do robo
{
    switch (func_mode)  // seleciona o comando recebido via infravermelho ou rede
    {
        case 3:  // executa etapa do firmware do robo tartaruga
                {
                    Object_Following_mode();  // follow model
                }
                break;  // executa etapa do firmware do robo tartaruga
        case 4:  // executa etapa do firmware do robo tartaruga
                {
                    Line_Tracing_mode();  // Tracking model1
                }
                break;        // executa etapa do firmware do robo tartaruga
        case 2:  // executa etapa do firmware do robo tartaruga
                {
                    Obstacles_Avoidance_mode();  // OA model
                }
                break;  // executa etapa do firmware do robo tartaruga
        default:break;  // executa etapa do firmware do robo tartaruga
    }
}

void Receive_data()  //Receive data
{
    if (client.available())  // gerencia a conexao do cliente movel no protocolo de comando em quadros
    {
        unsigned char c = client.read()&0xff;  // gerencia a conexao do cliente movel no protocolo de comando em quadros
        Serial.write(c);  // executa etapa do firmware do robo tartaruga
        if(c==0x55&&isStart==false)  // decisao condicional que seleciona o comportamento autonomo
        {
            if(prevc==0xff)  // decisao condicional que seleciona o comportamento autonomo
            {
            index_a=1;  // executa etapa do firmware do robo tartaruga
            isStart = true;  // executa etapa do firmware do robo tartaruga
            }
        }
        else  // ramo alternativo da decisao de navegacao autonoma
        {
            prevc = c;  // executa etapa do firmware do robo tartaruga
            if(isStart)  // decisao condicional que seleciona o comportamento autonomo
            {
            if(index_a==2)  // decisao condicional que seleciona o comportamento autonomo
            {
            dataLen = c;   // executa etapa do firmware do robo tartaruga
            }
            else if(index_a>2)  // ramo alternativo da decisao de navegacao autonoma
            {
                dataLen--;  // executa etapa do firmware do robo tartaruga
            }
            writeBuffer(index_a,c);  // executa etapa do firmware do robo tartaruga
            }
        }
        index_a++;  // executa etapa do firmware do robo tartaruga
        if(index_a>120)  // decisao condicional que seleciona o comportamento autonomo
        {
            index_a=0;   // executa etapa do firmware do robo tartaruga
            isStart=false;  // executa etapa do firmware do robo tartaruga
        }
        if(isStart&&dataLen==0&&index_a>3)  // decisao condicional que seleciona o comportamento autonomo
        { 
            isStart = false;  // executa etapa do firmware do robo tartaruga
            parseData();  // executa etapa do firmware do robo tartaruga
            index_a=0;  // executa etapa do firmware do robo tartaruga
        }
    }
}

void Servo_Move(int angles)  //servo
{
  myservo.write(angles);  // posiciona o servo no angulo indicado para varredura ou centragem do sensor
  if (angles >= 179) angles = 179;  // decisao condicional que seleciona o comportamento autonomo
  if (angles <= 1) angles = 1;  // decisao condicional que seleciona o comportamento autonomo
  delay(10);  // aguarda estabilizacao mecanica ou garante janela de observacao do fenomeno
}

void runModule(int device)  // define rotina de atuacao, leitura ou protocolo do robo
{
  val = readBuffer(12);  // executa etapa do firmware do robo tartaruga
  switch(device)   // seleciona o comando recebido via infravermelho ou rede
  {
    case 0x0C:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
    {   
      switch (val)  // seleciona o comando recebido via infravermelho ou rede
      {
        case 0x01:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
            Forward();  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case 0x02:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
            Back();  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case 0x03:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
            Left();  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case 0x04:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
            Right();  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case 0x05:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
            Left_single();  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case 0x06:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente

            break;  // executa etapa do firmware do robo tartaruga
        case 0x07:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
            Right_single();  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case 0x08:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente

            break;  // executa etapa do firmware do robo tartaruga
        case 0x0A:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente

            break;  // executa etapa do firmware do robo tartaruga
        case 0x09:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente

            break;  // executa etapa do firmware do robo tartaruga
        case 0x00:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
            Stop();  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        default:  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
      }
    }break;
    case 0x02:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
    {  
        Servo_Move(val);  // executa etapa do firmware do robo tartaruga
    }break;
    case 0x03:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
    {  

    }break;
    case 0x05:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
    {    

    }break;
    case 0x08:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
    {    

    }break;
    case 0x0D:  // mapeia o codigo hexadecimal do botao do controle ao movimento correspondente
    {
        carSpeed = val;  // executa etapa do firmware do robo tartaruga
    }break;
  }   
}
void parseData()  // define rotina de atuacao, leitura ou protocolo do robo
{ 
    isStart = false;  // executa etapa do firmware do robo tartaruga
    int action = readBuffer(9);  // define rotina de atuacao, leitura ou protocolo do robo
    int device = readBuffer(10);  // define rotina de atuacao, leitura ou protocolo do robo
    switch (action)  // seleciona o comando recebido via infravermelho ou rede
    {
        case CMD_RUN:  // executa etapa do firmware do robo tartaruga
            //callOK_Len01();
            func_mode = 1;  // executa etapa do firmware do robo tartaruga
            runModule(device);  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case CMD_STANDBY:  // executa etapa do firmware do robo tartaruga
            //callOK_Len01();
            func_mode = 1;  // executa etapa do firmware do robo tartaruga
            Stop();  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case CMD_TRACK_1:  // executa etapa do firmware do robo tartaruga
            //callOK_Len01();
            func_mode = 4;  // executa etapa do firmware do robo tartaruga
            //Serial.write(0x01);
            break;  // executa etapa do firmware do robo tartaruga
        case CMD_TRACK_2:  // executa etapa do firmware do robo tartaruga
            //callOK_Len01();
            func_mode = 4;  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case CMD_AVOID:  // executa etapa do firmware do robo tartaruga
            //callOK_Len01();
            func_mode = 2;  // executa etapa do firmware do robo tartaruga
            break;  // executa etapa do firmware do robo tartaruga
        case CMD_FOLLOW:  // executa etapa do firmware do robo tartaruga
            //callOK_Len01();
            func_mode = 3;  // executa etapa do firmware do robo tartaruga

Instalação do aplicativo: no Android, copie o APK da pasta do kit para o celular e instale permitindo fonte do kit; no iOS, busque kuongshun na loja e instale. Operação: ligue o robô com baterias, conecte o WiFi em KUONGSHUN-AD177, abra o APP, selecione o tartaruga ESP32 e toque em conectar. Resultado esperado: o D-pad move com parada ao soltar e já alterna para o modo livre, os botões de modo assumem desvio, seguimento e linha, o slider ajusta velocidade em tempo real, e o indicador mostra conectado. Nas próximas ligadas, basta reassociar no WiFi e abrir o APP, sem regravar. Se o APP mostra WiFi conectado mas robô desconectado, toque no indicador para reconectar o socket na porta 100. Se o D-pad anda invertido, confira IN1/IN2 e IN3/IN4 nos bornes antes de culpar o APP.

⚠️ Atenção: instale o APK apenas da pasta do kit. APK de terceiros com mesmo nome pode implementar protocolo diferente e mover o robô de forma imprevisível.

Guia Diagnóstico (Troubleshooting)

A matriz abaixo parte dos sintomas reais do kit AD177 na bancada e no chão, com causa raiz e ação corretiva sem chute. Diagnostique sempre nesta ordem: alimentação, fiação pelo mapa de pinos, versão de núcleo e biblioteca, e por fim pista e ambiente. A maioria dos chamados se resolve nos três primeiros sem trocar peça.

SintomaCausa raiz provávelAção corretiva
Nenhuma porta COM além de COM1Cabo de carga sem dados ou CH340 ausenteTrocar por cabo Tipo-C de dados conhecido e instalar o CH340 da pasta do kit, reiniciar e reconectar
Failed to connect no uploadBootloader sem reset automático ou porta erradaSelecionar a COM correta, segurar BOOT na placa durante o início do upload, soltar após os pontos
ledcSetup was not declaredNúcleo ESP32 3.x instaladoVoltar o núcleo para 2.0.12 no Gerenciador de Placas e recompilar
ESP32Servo.h: No such fileBiblioteca ausente ou IDE sem reiniciarInstalar ESP32Servo 1.1.2 pela tabela-mestre, conferir libraries/ESP32Servo, reiniciar a IDE
IRremote.h: No such fileBiblioteca ausente ou duplicadaInstalar IRremote 4.1.2, remover pasta duplicada com nome parecido, reiniciar
Robô não anda mas Serial avançaBateria fraca, chave desligada ou fio de motor soltoMedir pack acima de 7 V, ligar a chave, repuxar bornes do L298N
Uma roda gira invertidaFios do motor invertidos no borneDesligar, remover baterias e inverter os dois fios daquele motor no L298N
Servo com jitter ou varredura assimétricaBateria fraca ou braço desalinhadoRecarregar 18650 e refazer o zero a 90 graus com reset e reencaixe do braço
Ultrassom trava em zero ou oscilaTRIG e ECHO trocados ou eco contaminadoConferir GPIO 19 TRIG e 18 ECHO, afastar de ventilador, medir com alvo plano a 30 cm
Linha ignora a fita ou oscilaLimiar e trimpot fora do ponto da salaRecalibrar com Serial dos três canais e trimpots, reduzir cruzeiro de 200 para 150, ensaiar em sombra
IR não responde em nenhum modoSem visada, pilha fraca ou GPIO erradoTrocar CR2025/CR2032, apontar ao olho sem obstrução, conferir GPIO 15 no fio real
IR funciona na Lição 7 mas não na 9Código declara receptor em 5 e fio está em 15Alterar o pino para o fio real e recarregar o modo 9
Rede KUONGSHUN-AD177 não apareceAlimentação insuficiente do rádioRecarregar 18650, conferir paralelo da bateria na expansão e no L298N, religar e aguardar 10 s
Conecta no WiFi mas 192.168.4.1 não abreCelular pulou para dados móveis ou modo errado gravadoDesativar dados móveis, manter sem internet conectado, recarregar o sketch Web correspondente
APP mostra WiFi ok mas robô desconectadoSocket TCP 100 caiuTocar no indicador do APP para reconectar, reassociar no WiFi se trocou de rede
Desvio bate antes de pararCruzeiro alto ou servo descentralizadoReduzir de 255 para 200 e refazer o zero do servo da Lição 3
Seguimento avança sem pararECHO solto lendo zeroReconectar ECHO no GPIO 18 e validar telemetria antes de soltar no chão
Página Web carrega mas slider não atuaCache do navegador com JS antigoRecarregar sem cache e retestar os sliders de servo e velocidade

💡 Dica: mantenha um caderno de bancada com pack medido, limiar de linha do dia, códigos IR do seu controle e versão de núcleo. O diagnóstico cai pela metade quando o ponto de partida está anotado.

Solução de problemas

Olá! Sou o assistente técnico da RoboBuilders. Descreva seu problema com o Kit Robô Tartaruga ESP32 WiFi AD177 - 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.