Circular FAB
CIRCULAR FAB Jarandilla de la Vera · Arduino Week 2026
Circular FAB
CIRCULAR FAB
Jarandilla de la Vera · Práctica educativa de robótica

COCHE WIFI
ESP32
L298N

Motores con nueva vida · Arduino Week 2026 · Circular FAB

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.

ESP32 WiFiL298N2 motores DCServo SG90HC-SR04Fuente externa
HC-SR04 · distancia
WiFi AP · 192.168.4.1
SERVO 90º
01 / MATERIALES

COMPONENTES DE LA PRÁCTICA

📶

ESP32 NodeMCU / WROOM

La placa crea una red WiFi propia y sirve una web de control para manejar el coche desde el móvil.

🧲

L298N Puente H doble

Controla dos motores DC. Permite avance, retroceso y giro diferencial activando cada motor por separado.

⚙️

2 motores DC recuperados

Ideal para “Motores con nueva vida”: ruedas, reductoras o motores reutilizados de juguetes/maquetas.

🦾

Servo SG90 movimiento sensor ultrasónico

Se utiliza para mover el sensor ultrasónico y escanear el entorno. La dirección del coche se realiza con los motores (giro diferencial).

📏

HC-SR04 ultrasonidos

Detecta obstáculos midiendo distancia. Si baja de un umbral, el código bloquea el avance por seguridad.

🔋

Fuente externa 6–12V

Los motores no se alimentan desde la ESP32. Usa pilas, batería o fuente externa y comparte GND.

02 / CONEXIONES

ESQUEMA GENERAL

ESP32WiFi + WebServerL298NPuente H dobleM IZQM DERFUENTE6–12V motoresHC-SR04TRIG + ECHOSERVOSG90IN1 GP26IN2 GP27IN3 GP14IN4 GP12+VmotorGND comúnTRIG GP5ECHO GP18*SERVO GP13
// TABLA DE PINES PROPUESTA
ESP32DESTINOFUNCIÓN
GPIO 26L298N IN1Motor izquierdo adelante
GPIO 27L298N IN2Motor izquierdo atrás
GPIO 14L298N IN3Motor derecho adelante
GPIO 12L298N IN4Motor derecho atrás
GPIO 25ENAPWM velocidad motor izquierdo
GPIO 33ENBPWM velocidad motor derecho
GPIO 13Servo señalGiro servo / radar
GPIO 5HC-SR04 TRIGDisparo ultrasonidos
GPIO 18HC-SR04 ECHOEntrada con divisor a 3.3V
03 / LÓGICA DE MOVIMIENTO

GIRO DIFERENCIAL

⬆️

Adelante

Motor izquierdo adelante + motor derecho adelante.

⬇️

Atrás

Motor izquierdo atrás + motor derecho atrás.

↪️

Derecha

Se mueve el motor izquierdo hacia delante y el derecho se para.

↩️

Izquierda

Se mueve el motor derecho hacia delante y el izquierdo se para.

🔄

Giro sobre sí mismo

Opcional: un motor adelante y otro atrás.

🛑

Obstáculo

Si la distancia baja del umbral, bloquea el avance.

04 / CÓDIGO

SKETCH ESP32 CON WEB SERVER

coche_wifi_esp32_l298n.ino
/* 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(); }
05 / MANDO WEB

INTERFAZ DE CONDUCCIÓN

EstadoPARADO
Distancia42 cm
WiFiCOCHE_ESP32
Velocidad180
Servo / radar90º
OBSTÁCULO
Distancia frontal: 42 cm
06 / NOTAS DE MONTAJE

SEGURIDAD Y AJUSTES

⚠ GND COMÚN OBLIGATORIOUne GND de la fuente de motores, GND del L298N, GND del servo y GND de la ESP32.
⚠ ECHO DEL HC-SR04 A 3.3VEl pin ECHO suele entregar 5V. La ESP32 trabaja a 3.3V: usa divisor resistivo, por ejemplo 1kΩ + 2kΩ.
🔋 NO ALIMENTAR MOTORES DESDE LA ESP32Los motores deben ir a fuente externa. La ESP32 solo envía señales de control.
✅ GIRO SUAVE PARA TALLERPara girar a la derecha se mueve solo el motor izquierdo; para girar a la izquierda, solo el derecho.
✅ PRUEBA POR PARTESPrimero web, luego un motor, después dos motores, después servo y por último el sensor de distancia.