ROBOT SEGUIDOR DE LINEA
1) Propósito de la clase
-
Producto final: robot que sigue una línea negra sobre fondo blanco.
-
KUD (Know–Understand–Do)
-
Know: sensores IR reflectivos (TCRT5000 o similares), puente H (L298N), PWM, umbral.
-
Understand: el seguidor corrige su rumbo comparando izquierda vs derecha y ajustando la velocidad diferencial.
-
Do: cablear, calibrar sensores, cargar código, probar y optimizar (búsqueda y corrección).
-
2) Materiales
-
Arduino UNO/Nano + cable USB
-
Driver de motores L298N (o TB6612FNG)
-
Chasis con 2 motores DC + 1 rueda loca (o kit de auto)
-
2 sensores IR reflectivos (TCRT5000 o módulos similares)
(opción avanzada: arreglo QTR-8A/8RC) -
Portapilas (6 V–7.4 V) independiente del Arduino (recomendado)
-
Jumpers hembra–macho, bridas, cinta doble faz
-
(Opcional) pulsador para autocalibración (con resistencia interna pull-up)
3) Esquema de cableo (texto)
Sensores
-
Sensor Izq → A0
-
Sensor Der → A1
-
VCC 5 V, GND común
L298N → Arduino
-
ENA → D5 (PWM)
-
IN1 → D8
-
IN2 → D9
-
ENB → D6 (PWM)
-
IN3 → D10
-
IN4 → D11
-
12 V (o 7–12 V) al borne +12V del L298N (desde baterías de motores)
-
GND del L298N unido al GND de Arduino (masa común)
Pulsador de calibración (opcional)
-
Un lado a D12, otro a GND (usaremos
INPUT_PULLUP)
Coloca los sensores a ~5–8 mm del suelo. Alinea el centro entre ruedas y que queden paralelos.
4) Secuencia didáctica (90’ × 2 sesiones)
Sesión 1 – Explora, conecta y calibra (90’)
-
Hook (10’): videos/gifs de robots seguidores; lluvia de ideas: ¿cómo “ven” la línea?
-
Mini-lección (15’): reflexión vs absorción; analogRead; umbral; PWM.
-
Manos a la obra (45’): cableo completo y montaje sensores.
-
Calibración (10’): medir blanco y negro; definir umbrales.
-
Cierre (10’): checklist de pruebas y ticket de salida (qué funcionó/qué mejorar).
Sesión 2 – Programa, prueba y mejora (90’)
-
Carga del código base (20’) y verificación serial.
-
Pruebas en pista (30’): curvas en S, T, bifurcación; registro de observaciones.
-
Optimización (25’): ajustar
baseSpeed, umbrales; desafío “vuelta limpia”. -
Cierre (15’): retroalimentación tipo Purple Pen y breve demo.
5) Código base (analógico con autocalibración + lógica simple)
Diseñado para módulos TCRT5000 analógicos. Si tu módulo entrega digital invertido, invierte las comparaciones
</>o usadigitalRead().
// Robot Seguidor de Línea - Arduino UNO
// Sensores analógicos en A0 (izq), A1 (der). L298N en pines indicados.
// Autocalibración con botón en D12 (a GND). Si no hay botón, usa timeout.
const int S_LEFT = A0;
const int S_RIGHT = A1;
const int ENA = 5; // PWM
const int IN1 = 8;
const int IN2 = 9;
const int ENB = 6; // PWM
const int IN3 = 10;
const int IN4 = 11;
const int CAL_BTN = 12; // a GND (INPUT_PULLUP)
int thrLeft = 500; // valores por defecto (se sobreescriben al calibrar)
int thrRight = 500;
int baseSpeed = 140; // 0..255
int turnBoost = 90; // cuánto se acelera el motor opuesto al que pisa la línea
int lastTurn = 1; // 1 = derecha, -1 = izquierda (para búsqueda cuando pierde la línea)
void setup() {
pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT);
pinMode(ENA, OUTPUT); pinMode(ENB, OUTPUT);
pinMode(CAL_BTN, INPUT_PULLUP);
Serial.begin(115200);
delay(300);
Serial.println("== Seguidor de Linea - Calibracion ==");
calibrateSensors(3500); // espera botón o avanza con timeout (ms)
Serial.print("Umbrales: L="); Serial.print(thrLeft);
Serial.print(" R="); Serial.println(thrRight);
// Dirección por defecto: adelante
setDirForward();
}
void loop() {
int leftVal = analogRead(S_LEFT);
int rightVal = analogRead(S_RIGHT);
// Regla común en TCRT5000: negro refleja menos IR -> lectura mas BAJA.
bool leftOnLine = (leftVal < thrLeft);
bool rightOnLine = (rightVal < thrRight);
if (leftOnLine && rightOnLine) {
// Ambos sobre la línea -> seguir recto
setSpeed(baseSpeed, baseSpeed);
} else if (leftOnLine && !rightOnLine) {
// izquierda pisa linea -> gira a la IZQUIERDA (freno izq, impulsa der)
setSpeed(baseSpeed - turnBoost, baseSpeed + turnBoost);
lastTurn = -1;
} else if (!leftOnLine && rightOnLine) {
// derecha pisa linea -> gira a la DERECHA
setSpeed(baseSpeed + turnBoost, baseSpeed - turnBoost);
lastTurn = 1;
} else {
// Ninguno ve la línea -> estrategia de búsqueda
if (lastTurn > 0) {
setSpeed(baseSpeed + turnBoost, 0); // giro suave a la derecha
} else {
setSpeed(0, baseSpeed + turnBoost); // giro suave a la izquierda
}
}
// (Opcional) Telemetría por Serial para afinar
// Serial.print(leftVal); Serial.print('\t'); Serial.println(rightVal);
delay(5);
}
// ---------- Funciones de movimiento ----------
void setDirForward() {
// Motores en avance
digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
}
void setSpeed(int leftPWM, int rightPWM) {
leftPWM = constrain(leftPWM, 0, 255);
rightPWM = constrain(rightPWM, 0, 255);
analogWrite(ENA, leftPWM);
analogWrite(ENB, rightPWM);
}
// ---------- Calibracion ----------
void calibrateSensors(unsigned long timeoutMs) {
int wL=0, wR=0, bL=0, bR=0;
Serial.println("1) Coloca sensores SOBRE BLANCO y pulsa el boton (o espera)...");
waitBtnOrTimeout(timeoutMs);
averageReadings(wL, wR);
Serial.println("2) Ahora SOBRE LA LINEA NEGRA y pulsa (o espera)...");
waitBtnOrTimeout(timeoutMs);
averageReadings(bL, bR);
// umbral = punto medio entre blanco y negro
thrLeft = (wL + bL) / 2;
thrRight = (wR + bR) / 2;
// Seguridad: si la diferencia es pequeña, usa defaults
if (abs(wL - bL) < 30) thrLeft = 500;
if (abs(wR - bR) < 30) thrRight = 500;
}
void waitBtnOrTimeout(unsigned long timeoutMs) {
unsigned long t0 = millis();
while (millis() - t0 < timeoutMs) {
if (digitalRead(CAL_BTN) == LOW) { delay(300); return; }
delay(5);
}
}
void averageReadings(int &outL, int &outR) {
long sumL=0, sumR=0;
for (int i=0; i<200; i++) { sumL += analogRead(S_LEFT); sumR += analogRead(S_RIGHT); delay(2); }
outL = sumL / 200; outR = sumR / 200;
}
Si tus sensores “leen al revés” (negro = valor alto), cambia las comparaciones a
>enleftOnLine/rightOnLine.
Variante PID (extensión “visión de futuro”)
Para trayectorias más rápidas y suaves, sustituye la lógica por un controlador PD:
// Dentro de loop(), después de leer sensores (leftVal/rightVal)
// Normaliza 0..1000 (ajusta si usas otro rango)
int error = (rightVal - thrRight) - (leftVal - thrLeft); // signo define giro
static int lastError = 0;
float Kp = 0.22; // empieza bajo
float Kd = 3.2; // amortigua oscilaciones
int correction = (int)(Kp*error + Kd*(error - lastError));
lastError = error;
int L = constrain(baseSpeed - correction, 0, 255);
int R = constrain(baseSpeed + correction, 0, 255);
setSpeed(L, R);
6) Pruebas y calibración rápida
-
Dibuja un circuito con cinta aislante negra de 18–20 mm sobre cartulina blanca.
-
Ajusta altura de sensores: si están muy altos/ bajos, el contraste cae.
-
Si “serpentea”, baja
Kp/turnBoost. Si no corrige, súbelos. -
Si pierde la línea en curvas cerradas, reduce
baseSpeedo acerca sensores.
7) Evaluación (rúbrica corta, 10 puntos)
-
Cableado correcto y seguro (2)
-
Calibración y registro de umbrales (2)
-
Robot sigue línea y corrige en curvas (4)
-
Iteración/optimización documentada (2)
8) Seguridad y buenas prácticas
-
GND común entre Arduino y driver.
-
Alimenta motores y Arduino por fuentes separadas o usa regulador dedicado.
-
No toques el L298N por la parte inferior (posibles cortos).
-
Retira hélices/ruedas al probar motores en la mesa.
9) Diferenciación y retos
-
Básico: umbral fijo, pista oval.
-
Medio: autocalibración + “S” pronunciada.
-
Avanzado: PD + cruce en T (decidir rumbo por última memoria).
-
Pro: arreglo QTR-8A y PID fino; o visión con HuskyLens.
10) Extensiones maker
-
Diseña el chasis en Google Slides (plantilla a escala) y corta en MDF 3 mm con tu láser.
-
Añade un buzzer para tonos al perder la línea.
-
Integra OLED 0.96" para ver
L/R, umbrales y error.
Si quieres, te genero:
-
una pista imprimible A3,
-
una plantilla de chasis para láser,
-
o un poster-guía para tus estudiantes con pasos de calibración.
Comments
Post a Comment