

Tercera práctica del itinerario: reutilizamos motores DC para construir un coche controlado desde una interfaz web servida por la propia ESP32. Integra dos motores, puente H L298N, servo de dirección/escaneo, sensor ultrasónico de obstáculos y mando web responsive.
La placa crea una red WiFi propia y sirve una web de control para manejar el coche desde el móvil.
Controla dos motores DC. Permite avance, retroceso y giro diferencial activando cada motor por separado.
Ideal para “Motores con nueva vida”: ruedas, reductoras o motores reutilizados de juguetes/maquetas.
Se utiliza para mover el sensor ultrasónico y escanear el entorno. La dirección del coche se realiza con los motores (giro diferencial).
Detecta obstáculos midiendo distancia. Si baja de un umbral, el código bloquea el avance por seguridad.
Los motores no se alimentan desde la ESP32. Usa pilas, batería o fuente externa y comparte GND.
| ESP32 | DESTINO | FUNCIÓN |
|---|---|---|
| GPIO 26 | L298N IN1 | Motor izquierdo adelante |
| GPIO 27 | L298N IN2 | Motor izquierdo atrás |
| GPIO 14 | L298N IN3 | Motor derecho adelante |
| GPIO 12 | L298N IN4 | Motor derecho atrás |
| GPIO 25 | ENA | PWM velocidad motor izquierdo |
| GPIO 33 | ENB | PWM velocidad motor derecho |
| GPIO 13 | Servo señal | Giro servo / radar |
| GPIO 5 | HC-SR04 TRIG | Disparo ultrasonidos |
| GPIO 18 | HC-SR04 ECHO | Entrada con divisor a 3.3V |
Motor izquierdo adelante + motor derecho adelante.
Motor izquierdo atrás + motor derecho atrás.
Se mueve el motor izquierdo hacia delante y el derecho se para.
Se mueve el motor derecho hacia delante y el izquierdo se para.
Opcional: un motor adelante y otro atrás.
Si la distancia baja del umbral, bloquea el avance.
/* COCHE WIFI ESP32 + L298N + 2 MOTORES + SERVO + HC-SR04 SSID: COCHE_ESP32 · PASS: circularfab · Abrir http://192.168.4.1 OJO: GND común y ECHO del HC-SR04 con divisor a 3.3V */ #include <WiFi.h> #include <WebServer.h> #include <ESP32Servo.h> const char* ssid = "COCHE_ESP32"; const char* password = "circularfab"; WebServer server(80); Servo servoRadar; const int IN1=26, IN2=27, IN3=14, IN4=12; const int ENA=25, ENB=33; const int PIN_SERVO=13, TRIG=5, ECHO=18; int velocidad=180; const int DISTANCIA_MINIMA=18; String paginaWeb(){ return R"rawliteral( <!DOCTYPE html><html lang="es"><head><meta name="viewport" content="width=device-width, initial-scale=1"><meta charset="UTF-8"><title>Mando Coche ESP32</title> <style>body{margin:0;background:#071414;color:#ecfffb;font-family:Arial;text-align:center}h1{font-size:34px;margin:20px 0 4px;color:#00d5c8}small{color:#7aa09b}.panel{max-width:420px;margin:20px auto;padding:20px;border:1px solid #244242;border-radius:22px;background:#0f1f1f}.grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;margin-top:20px}button{height:78px;border-radius:16px;border:1px solid #244242;background:#0a1818;color:#ecfffb;font-size:26px;font-weight:bold}button:active{border-color:#00d5c8;color:#00d5c8}.stop{background:#341010;color:#ff3b3b}input{width:90%;accent-color:#00d5c8}.row{margin:18px 0;color:#7aa09b}</style></head><body> <h1>COCHE ESP32</h1><small>Motores con nueva vida · Arduino Week 2026 · Circular FAB</small><div class="panel"><div class="row">Velocidad: <span id="v">180</span></div><input type="range" min="80" max="255" value="180" oninput="vel(this.value)"><div class="grid"><div></div><button onclick="cmd('F')">▲</button><div></div><button onclick="cmd('L')">◀</button><button class="stop" onclick="cmd('S')">■</button><button onclick="cmd('R')">▶</button><div></div><button onclick="cmd('B')">▼</button><div></div></div><div class="row">Servo: <span id="a">90</span>º</div><input type="range" min="20" max="160" value="90" oninput="servo(this.value)"><p id="dist">Distancia: -- cm</p></div><script>function cmd(c){fetch('/cmd?c='+c)}function vel(v){document.getElementById('v').innerText=v;fetch('/vel?v='+v)}function servo(a){document.getElementById('a').innerText=a;fetch('/servo?a='+a)}setInterval(()=>fetch('/dist').then(r=>r.text()).then(t=>document.getElementById('dist').innerText='Distancia: '+t+' cm'),700);</script></body></html> )rawliteral"; } long medirDistancia(){ digitalWrite(TRIG, LOW); delayMicroseconds(2); digitalWrite(TRIG, HIGH); delayMicroseconds(10); digitalWrite(TRIG, LOW); long duracion = pulseIn(ECHO, HIGH, 30000); if(duracion==0) return 999; return duracion * 0.034 / 2; } void motorIzq(int sentido){ digitalWrite(IN1,sentido==1); digitalWrite(IN2,sentido==-1); analogWrite(ENA,sentido==0?0:velocidad); } void motorDer(int sentido){ digitalWrite(IN3,sentido==1); digitalWrite(IN4,sentido==-1); analogWrite(ENB,sentido==0?0:velocidad); } void parar(){ motorIzq(0); motorDer(0); } void adelante(){ if(medirDistancia()<DISTANCIA_MINIMA){parar(); return;} motorIzq(1); motorDer(1); } void atras(){ motorIzq(-1); motorDer(-1); } void derecha(){ motorIzq(1); motorDer(0); } void izquierda(){ motorIzq(0); motorDer(1); } void handleCmd(){ String c=server.arg("c"); if(c=="F")adelante(); if(c=="B")atras(); if(c=="L")izquierda(); if(c=="R")derecha(); if(c=="S")parar(); server.send(200,"text/plain","OK"); } void handleVel(){ velocidad=constrain(server.arg("v").toInt(),80,255); server.send(200,"text/plain","OK"); } void handleServo(){ int a=constrain(server.arg("a").toInt(),20,160); servoRadar.write(a); server.send(200,"text/plain","OK"); } void setup(){ Serial.begin(115200); pinMode(IN1,OUTPUT); pinMode(IN2,OUTPUT); pinMode(IN3,OUTPUT); pinMode(IN4,OUTPUT); pinMode(ENA,OUTPUT); pinMode(ENB,OUTPUT); pinMode(TRIG,OUTPUT); pinMode(ECHO,INPUT); servoRadar.attach(PIN_SERVO); servoRadar.write(90); parar(); WiFi.softAP(ssid,password); Serial.println(WiFi.softAPIP()); server.on("/",[](){server.send(200,"text/html",paginaWeb());}); server.on("/cmd",handleCmd); server.on("/vel",handleVel); server.on("/servo",handleServo); server.on("/dist",[](){server.send(200,"text/plain",String(medirDistancia()));}); server.begin(); } void loop(){ server.handleClient(); }