01 · Punto de partida
Qué hace falta para seguir una línea
Seguir una línea parece lo más simple de la robótica móvil, y por eso se enseña primero: el entorno viene dibujado y el sensor es barato. Pero hay muchos modos de que no funcione. Un seguidor de línea es, en el fondo, un lazo de realimentación (tema 40) cuya medición es la posición de la línea respecto del robot, y cuyo actuador es la diferencia de velocidad entre las ruedas (tema 26).
Este tema se ocupa de la medición y de la lógica de decisión: qué se ve y qué significa. El tema 31 se ocupa de corregir el movimiento con esa información. Conviene separarlos porque la mayoría de los fracasos de un seguidor de línea nacen en la parte de sensores, no en el controlador.
En el tema 7 vimos cómo funciona un sensor reflectivo, su calibración de fondo y línea, los umbrales con histéresis y los patrones de varios sensores. Aquí lo usamos como una pieza de un sistema completo.
02 · Dimensionar
Geometría del arreglo
Un arreglo lineal de n sensores, perpendicular al avance, se describe con pocos parámetros:
d: separación entre sensores contiguos.s: diámetro del campo de visión de cada sensor sobre el suelo (depende de la altura; unos milímetros). Es lo que mira, no el tamaño del componente.w: ancho de la línea (una cinta aislante común mide entre 18 y 19 mm).L: distancia desde el arreglo hasta el eje de las ruedas, en el sentido del avance.
De ahí salen tres consecuencias:
| Magnitud | Fórmula | Qué significa |
|---|---|---|
| Cobertura | (n − 1)·d + s | Ancho total que el arreglo observa. Si el robot se desvía más que eso, pierde la línea |
| Hueco entre campos | d − s | Franja del suelo que ningún sensor ve. La línea debe ser más ancha que el hueco para ser vista siempre |
| Resolución | ≈ d | Con sensores binarios, la posición se conoce a pasos de la separación; con lecturas analógicas se interpola |
Con n = 5, d = 10 mm y s = 8 mm, la cobertura es de 48 mm y el hueco es de 2 mm: una cinta de 18 mm siempre cae sobre algún sensor, pero una línea fina de 3 mm puede quedar en el hueco, a medio camino entre dos sensores, con lecturas débiles que el ruido oculta. Con d = 15 mm el hueco es de 7 mm y una línea de 3 mm se pierde en más de un tercio de las posiciones.
Reglas de diseño: la línea debe ser más ancha que el hueco (con margen); el arreglo debe ser más ancho que lo que el robot puede desviarse entre dos correcciones; y la separación debe dar una resolución acorde con la precisión que se pide. Más sensores dan más cobertura y resolución, a costa de más entradas, más cableado y más tiempo de lectura.
La altura de los sensores sobre el suelo importa: determina el campo s y la señal. Las fichas de los módulos indican un rango; fuera de él, el contraste cae. Fijalos rígidos y a una altura constante: una altura que varía con las vibraciones cambia las lecturas.
03 · Limpiar la señal
De la lectura a la información
Cada sensor entrega un valor distinto para el mismo suelo (tolerancias, altura, iluminación). Antes de comparar o combinar lecturas hay que normalizarlas con una calibración (tema 7): se registra el mínimo y el máximo de cada sensor mientras el arreglo pasa sobre la línea y el fondo, y se lleva cada lectura a una escala común. Para una línea oscura (menos reflectiva):
donde q = 0 es fondo y q = 1000 es línea. Con mín = 120 y máx = 880, una lectura de 300 da q = 763 y una de 500, q = 500. La misma fórmula con los roles invertidos sirve para una línea clara sobre fondo oscuro. Si el contraste máx − mín es pequeño (digamos, menos de unas decenas de cuentas de 1023), el sensor no distingue la línea: se avisa y se revisa altura, luz o cableado.
Para decidir si un sensor «ve la línea» se usan dos umbrales con histéresis (600 para activarse y 400 para desactivarse, sobre 0–1000): evita que un sensor en el borde de la línea alterne cada ciclo (tema 7). Y la calibración se repite cuando cambian la iluminación, el suelo o la cinta, porque las lecturas dependen de ellos. Una luz solar directa puede saturar sensores infrarrojos; conviene sombrear el arreglo o usar sensores con modulación.
Dos decisiones prácticas: conservar el valor analógico normalizado (sirve para estimar la posición con más resolución que el patrón binario) y mantener el estado binario con histéresis (sirve para clasificar patrones). Se usan en lugares distintos.
04 · Una medida continua
Dónde está la línea
Con las lecturas normalizadas qi de cada sensor y su posición xi sobre el arreglo (positiva a la izquierda, como el eje y del robot, tema 20), la posición de la línea se estima como promedio ponderado:
Solo se incluyen las lecturas por encima de una pequeña compuerta de ruido, y si la suma es cero no hay línea. Por ejemplo, con cinco sensores separados 8 mm y lecturas (0; 0,3; 1; 0,5; 0), las posiciones son (+16; +8; 0; −8; −16) mm y p = (8·0,3 − 8·0,5)/1,8 ≈ −0,9 mm: la línea está casi centrada, un poco hacia la derecha.
Este estimador interpola entre sensores, pero no es exacto: tiene un error de discretización que depende del patrón de superposición. En un modelo simple (cada sensor ve la fracción de su campo cubierta por la línea), con d = 10, w = 18 y s = 8 mm, el error típico (cuadrático medio) es de 1,1 mm y el máximo, de 2,7 mm. Con una línea fina (3 mm), sube a 2,7 y 4,7 mm. Con la línea 3 mm a la izquierda, las lecturas son (0; 0,75; 1; 0; 0) y la estimación resulta 4,3 mm: un error de 1,3 mm.
Es un error sistemático, con forma de «ondulación» según dónde caiga la línea, y es pequeño frente a la cobertura. No hace falta corregirlo para seguir una línea, pero conviene saberlo: la medida de posición no tiene mejor precisión que unos milímetros con este tipo de arreglo, por muy fino que sea el controlador que la use.
El cálculo del tema 31 usará esta posición como el error del lazo: cuánto se aparta la línea del centro del robot.
05 · Qué hacer con lo que se ve
Estrategias de decisión
| Estrategia | Sensores | Cómo decide | Limitación |
|---|---|---|---|
| Seguir el borde | 1 | Si ve línea gira a un lado, si ve fondo al otro | Siempre zigzaguea; no sabe de qué lado se salió |
| Todo o nada con 2 sensores | 2, a los lados de la línea | El que ve línea indica hacia qué lado corregir | Corrección brusca; con la línea fina, el centro es ambiguo |
| Tabla de patrones | 3 a 8, binarios | Cada patrón tiene una acción asociada | Pasos discretos de corrección; hay que enumerar los casos |
| Proporcional a la posición | 5 a 8, analógicos | La corrección crece con el error medido (tema 31) | Requiere calibración y ajuste de ganancia |
Los esquemas de todo o nada son fáciles de entender y de depurar, pero producen movimiento a golpes y exigen velocidades bajas. La corrección proporcional da trayectorias suaves y permite ir más rápido. Aun con un controlador proporcional, el clasificador de patrones sigue siendo necesario para detectar lo que el controlador no puede manejar: la línea perdida, los cruces y las curvas cerradas.
Por eso conviene una arquitectura en dos niveles: un clasificador que interpreta el patrón (¿estoy sobre la línea, la perdí, es un cruce?) y, según su veredicto, un comportamiento: seguir con corrección proporcional, buscar la línea, avanzar recto sobre una marca (tema 33).
06 · Lo que rompe a los seguidores
Casos de borde
Con cinco sensores binarios (el 0 es el de la izquierda extrema), estos son los patrones relevantes:
| Patrón | Interpretación | Acción |
|---|---|---|
| 00100, 01110 | Línea centrada | Seguir recto |
| 01100, 11000, 10000 | Línea a la izquierda (más o menos desviada) | Corregir a la izquierda, más fuerte cuanto más extremo |
| 00110, 00011, 00001 | Línea a la derecha | Corregir a la derecha |
| 11100 / 00111 | Curva cerrada o ramificación hacia ese lado | Según la tarea: doblar (girar en el lugar hasta reencontrar la línea) o seguir recto |
| 11111 | Cruce, marca ancha o zona negra | Avanzar recto un tramo corto, contarlo si hace falta y volver a leer |
| 00000 | Línea perdida | Girar hacia el último lado visto, con tiempo máximo |
| 10101 y similares | Inconsistente: ruido, mancha o línea doble | Conservar la acción anterior; no actuar sobre esta lectura |
Línea perdida. Es el caso crítico. El robot debe recordar de qué lado vio la línea por última vez: si la perdió por la izquierda, se salió por la izquierda y la recuperación es girar hacia allí. Hace falta un tiempo máximo de búsqueda; si no reaparece, el robot se detiene (una línea interrumpida, el final del recorrido o un fallo). Un robot que busca para siempre es un robot que se pierde.
Ángulos rectos. Con un ángulo de 90°, la línea desaparece por delante cuando el robot sigue recto, y aparece por un costado. Los sensores extremos activos con el central también activo (patrón 11100 o 00111) revelan la curva: se gira en el lugar hasta que la línea vuelve al centro. Un controlador proporcional puro suele no alcanzar a doblar a velocidad alta.
Huecos y discontinuidades. Una línea cortada en un tramo corto se resuelve avanzando recto unos centímetros con el rumbo previo; para esto sirve la memoria de la última dirección (o el giróscopo, tema 29).
Condiciones del entorno. Cambios de iluminación, brillos sobre una superficie lustrosa, sombras o suciedad alteran las lecturas. Reduce los problemas calibrar en el mismo lugar donde se usa, proteger el arreglo de la luz externa y evitar superficies con brillo.
07 · Hasta dónde se puede apurar
Geometría y velocidad
La velocidad máxima de un seguidor no depende solo de los motores: la fija la geometría del arreglo y la rapidez con que se reacciona.
- Distancia por ciclo. El robot avanza
v·Tentre dos lecturas. ConT = 20 ms, a 30 cm/s son 6 mm; a 90 cm/s, 18 mm, igual al ancho de una cinta. A esa velocidad, la línea puede cambiar entre lecturas lo suficiente como para que la corrección llegue tarde. - Distancia de anticipación. Con el arreglo a una distancia
Lpor delante del eje, una curva de radioRdesplaza la línea lateralmente unosL²/(2R)respecto del arreglo si el robot sigue recto. El arreglo pierde la línea cuando eso supera la semi-coberturah, es decir, siR < L²/(2h). ConL = 60 mmyh = 24 mm, el radio mínimo del peor caso es unos 75 mm. - Compromiso de L. Un arreglo adelantado ve venir la curva y permite anticipar, pero amplifica el efecto de cada giro (un pequeño giro del chasis desplaza mucho el arreglo) y favorece las oscilaciones. Uno cercano al eje es más estable pero reacciona tarde.
- Reducir la velocidad según el patrón. Pasar más lento cuando la línea se aparta del centro (patrones extremos) es una regla eficaz: el robot ya se está saliendo y necesita más tiempo para volver.
Estas cuentas son del peor caso y aproximadas, pero sirven para decidir antes de construir: qué radio de curva admite una pista, o cómo debe ser el arreglo para el recorrido previsto.
08 · Código para la placa
Lectura y clasificación en Arduino
Supuestos que debés verificar: UNO R3; cinco sensores reflectivos analógicos en A0 a A4 (el A0 es el de la izquierda), separados 10 mm; línea oscura sobre fondo claro; la lectura sube con la reflectividad. Si tu módulo es al revés, cambiá LINEA_OSCURA. El sketch solo observa: no maneja motores.
// Lectura, calibración y clasificación de un arreglo de 5 sensores reflectivos analógicos (A0 a A4).
// El sensor 0 (A0) es el de la izquierda extrema; la posición de la línea es positiva hacia la izquierda.
// Este sketch solo observa: la corrección de las ruedas se desarrolla en el tema 31.
const byte N = 5;
const byte PIN_SENSOR[N] = {A0, A1, A2, A3, A4};
const float SEPARACION = 10.0; // mm entre sensores contiguos - medila
const bool LINEA_OSCURA = true; // true si la línea refleja menos y la lectura baja sobre ella (invertir si no)
const int UMBRAL_ALTO = 600, UMBRAL_BAJO = 400; // histéresis sobre la escala normalizada 0..1000
const int COMPUERTA = 100; // ignorar lecturas normalizadas menores (ruido) al estimar la posición
const unsigned long PERIODO_MS = 10, IMPRESION_MS = 200, CALIBRACION_MS = 3000;
int minimo[N], maximo[N], q[N];
bool activo[N];
const char *ultimoLado = "centro";
unsigned long ultimo = 0, ultimaImpresion = 0;
void calibrar() {
for (byte i = 0; i < N; i++) { minimo[i] = 1023; maximo[i] = 0; }
Serial.println("Calibrando 3 s: pasá el arreglo varias veces sobre la línea y el fondo");
const unsigned long inicio = millis();
while (millis() - inicio < CALIBRACION_MS) {
for (byte i = 0; i < N; i++) {
const int v = analogRead(PIN_SENSOR[i]);
if (v < minimo[i]) minimo[i] = v;
if (v > maximo[i]) maximo[i] = v;
}
}
for (byte i = 0; i < N; i++) {
Serial.print("sensor "); Serial.print(i); Serial.print(": min="); Serial.print(minimo[i]);
Serial.print(" max="); Serial.println(maximo[i]);
if (maximo[i] - minimo[i] < 100) Serial.println(" ATENCION: contraste bajo, revisá altura, luz y cableado");
}
}
void leer() { // llena q[] con 0 = fondo y 1000 = línea, y actualiza los estados
for (byte i = 0; i < N; i++) {
const long rango = max(1, maximo[i] - minimo[i]);
const long v = analogRead(PIN_SENSOR[i]);
long norm = LINEA_OSCURA ? (maximo[i] - v) * 1000L / rango : (v - minimo[i]) * 1000L / rango;
q[i] = constrain(norm, 0, 1000);
if (!activo[i] && q[i] >= UMBRAL_ALTO) activo[i] = true; // histéresis (tema 7)
else if (activo[i] && q[i] <= UMBRAL_BAJO) activo[i] = false;
}
}
bool posicion(float &mm) { // promedio ponderado de las lecturas; false si no hay línea
long suma = 0;
float acumulado = 0;
for (byte i = 0; i < N; i++) {
if (q[i] < COMPUERTA) continue;
suma += q[i];
acumulado += ((N - 1) / 2.0 - i) * SEPARACION * q[i];
}
if (suma == 0) return false;
mm = acumulado / suma;
return true;
}
const char *clasificar() {
byte cuantos = 0, primero = 255, ultimoActivo = 0;
float suma = 0;
for (byte i = 0; i < N; i++) {
if (!activo[i]) continue;
cuantos++; suma += i;
if (primero == 255) primero = i;
ultimoActivo = i;
}
if (cuantos == 0) return "PERDIDA";
if (cuantos == N) return "CRUCE O ZONA NEGRA";
if (ultimoActivo - primero + 1 != cuantos) return "INCONSISTENTE";
if (activo[0] && activo[1] && activo[2] && !activo[3] && !activo[4]) return "RAMA A LA IZQUIERDA";
if (activo[4] && activo[3] && activo[2] && !activo[1] && !activo[0]) return "RAMA A LA DERECHA";
const float c = suma / cuantos;
if (c < 1.5) return "IZQUIERDA FUERTE";
if (c < 1.9) return "IZQUIERDA";
if (c <= 2.1) return "CENTRADA";
if (c <= 2.5) return "DERECHA";
return "DERECHA FUERTE";
}
void actualizarMemoria(const char *estado) { // recordar de qué lado estaba la línea antes de perderla
if (strstr(estado, "IZQUIERDA")) ultimoLado = "izquierda";
else if (strstr(estado, "DERECHA")) ultimoLado = "derecha";
else if (strcmp(estado, "CENTRADA") == 0) ultimoLado = "centro";
}
void setup() {
Serial.begin(115200);
Serial.println("C: calibrar; cualquier otra tecla no hace nada");
for (byte i = 0; i < N; i++) { minimo[i] = 0; maximo[i] = 1023; activo[i] = false; }
calibrar();
}
void loop() {
if (Serial.available() > 0 && toupper(Serial.read()) == 'C') calibrar();
const unsigned long ahora = millis();
if (ahora - ultimo < PERIODO_MS) return;
ultimo = ahora;
leer();
const char *estado = clasificar();
actualizarMemoria(estado);
if (ahora - ultimaImpresion >= IMPRESION_MS) {
ultimaImpresion = ahora;
for (byte i = 0; i < N; i++) { Serial.print(activo[i] ? '1' : '0'); }
Serial.print(" q=");
for (byte i = 0; i < N; i++) { Serial.print(q[i]); Serial.print(i < N - 1 ? "," : ""); }
float mm;
if (posicion(mm)) { Serial.print(" pos="); Serial.print(mm, 1); Serial.print(" mm"); }
else Serial.print(" pos=sin linea");
Serial.print(" "); Serial.print(estado);
if (strcmp(estado, "PERDIDA") == 0) { Serial.print(" (ultimo lado: "); Serial.print(ultimoLado); Serial.print(")"); }
Serial.println();
}
}
Al arrancar calibra durante 3 s: pasá el arreglo varias veces sobre la línea y el fondo. Después imprime cada 200 ms una línea como 01100 q=12,640,980,40,0 pos=4.0 mm IZQUIERDA: el patrón binario con histéresis, las lecturas normalizadas, la posición estimada (positiva a la izquierda) y la clasificación. Cuando no hay línea muestra PERDIDA (ultimo lado: izquierda), con la memoria del último lado. El comando C repite la calibración.
Probalo con el robot parado, moviendo el arreglo a mano sobre una línea de prueba, y comprobá cada fila de la tabla de casos de borde. Las decisiones que dependen de la clasificación (qué hacer en cada estado) se desarrollan en los temas 31 y 33. Las lecturas analógicas en el UNO tardan en torno a 100 µs cada una, así que cinco sensores caben holgadamente en un ciclo de 10 ms.
09 · Exploración interactiva
Laboratorios: el arreglo y los patrones
1. Un arreglo sobre una línea
Vista desde arriba: la banda clara es la línea; los rectángulos son los campos de visión de los sensores (lima si ven la línea en al menos la mitad de su campo). Las barras muestran la lectura de cada sensor (fracción del campo cubierta por la línea). La marca naranja es la posición estimada; la roja punteada, el centro del robot. La posición es positiva hacia la izquierda.
Elegí la geometría del arreglo.
Con los valores iniciales (cinco sensores, 10 mm, línea de 18 mm), la línea a 3 mm da el patrón 01100 y la posición estimada es 4,3 mm (error de 1,3 mm); el error típico en todo el rango es de 1,1 mm y nunca se pierde la línea. Bajá el ancho de la línea a 3 mm: se pierde en el 6 % de las posiciones. Con 3 mm y separación de 15 mm, en el 37 %. Subí el campo de cada sensor a 12 mm con la línea fina: ya no se pierde. Con 3 sensores a 10 mm, la cobertura es de solo 28 mm.
2. Clasificar un patrón
Marcá qué sensores ven la línea (de izquierda a derecha) y el último lado en que se vio. El laboratorio interpreta el patrón y propone una acción, con la misma lógica del sketch.
Marcá un patrón.
Probá 01100 (izquierda), 11000 (izquierda fuerte), 11100 (rama a la izquierda), 11111 (cruce), 10101 (inconsistente) y 00000 (perdida: la acción depende del último lado). Un patrón inconsistente no debe producir una orden brusca: es mejor mantener lo que se hacía.
10 · Código ejecutable
Analizar el arreglo en Python
Repetimos el modelo del laboratorio: lecturas por superposición, posición por promedio ponderado, barrido de la línea sobre el arreglo para medir el error y las posiciones perdidas, y el clasificador de patrones. Sirve para dimensionar un arreglo antes de construirlo.
Probalo en el navegador. Python se descarga con Pyodide la primera vez y requiere conexión. El código es editable y no controla ningún robot.
import math
def lecturas(n, d, w, s, p):
"""Fracción del campo de cada sensor cubierta por la línea (modelo 1D). Izquierda positiva."""
res = []
for i in range(n):
x = ((n - 1) / 2 - i) * d
solape = max(0.0, min(x + s / 2, p + w / 2) - max(x - s / 2, p - w / 2))
res.append(solape / s)
return res
def posicion(n, d, r, ruido_min=0.1):
util = [v if v >= ruido_min else 0.0 for v in r]
total = sum(util)
if total == 0:
return None
return sum(((n - 1) / 2 - i) * d * v for i, v in enumerate(util)) / total
def barrido(n, d, w, s, mitad):
errores, perdidas, total = [], 0, 0
paso = 0.1
p = -mitad
while p <= mitad + 1e-9:
total += 1
est = posicion(n, d, lecturas(n, d, w, s, p))
if est is None:
perdidas += 1
else:
errores.append(est - p)
p += paso
rms = math.sqrt(sum(e * e for e in errores) / len(errores)) if errores else float("nan")
return rms, max((abs(e) for e in errores), default=float("nan")), perdidas / total * 100
def clasificar(bits, ultimo_lado="centro"):
n = sum(bits)
if n == 0:
return f"PERDIDA (ultimo lado: {ultimo_lado})"
if n == len(bits):
return "CRUCE O ZONA NEGRA"
activos = [i for i, b in enumerate(bits) if b]
if activos[-1] - activos[0] + 1 != n:
return "INCONSISTENTE"
if bits[0] and bits[1] and bits[2] and not bits[3] and not bits[4]:
return "RAMA A LA IZQUIERDA"
if bits[4] and bits[3] and bits[2] and not bits[1] and not bits[0]:
return "RAMA A LA DERECHA"
c = sum(activos) / n
if c < 1.5: return "IZQUIERDA FUERTE"
if c < 1.9: return "IZQUIERDA"
if c <= 2.1: return "CENTRADA"
if c <= 2.5: return "DERECHA"
return "DERECHA FUERTE"
configs = [
("n=5, d=10, linea 18 mm, vision 8 mm", 5, 10, 18, 8),
("n=5, d=10, linea 3 mm, vision 8 mm", 5, 10, 3, 8),
("n=5, d=15, linea 3 mm, vision 8 mm", 5, 15, 3, 8),
("n=5, d=15, linea 18 mm, vision 8 mm", 5, 15, 18, 8),
]
for nombre, n, d, w, s in configs:
cobertura = (n - 1) * d + s
rms, pico, perdidas = barrido(n, d, w, s, (n - 1) * d / 2)
print(f"{nombre}: cobertura={cobertura} mm; error rms={rms:.2f} mm; maximo={pico:.2f} mm; posiciones sin linea={perdidas:.1f} %")
r = lecturas(5, 10, 18, 8, 3.0)
print("Lecturas con la linea 3 mm a la izquierda:", [round(v, 2) for v in r], "posicion estimada:", round(posicion(5, 10, r), 2), "mm")
print("Patrones (indice 0 = izquierda extrema):")
for patron in ("00100", "01110", "01100", "11000", "10000", "00110", "00011", "11100", "00111", "11111", "00000", "10101", "11110"):
print(f" {patron}: {clasificar([int(c) for c in patron], 'izquierda')}")
# Normalización con la calibración de mínimo y máximo (línea oscura: la lectura baja sobre la línea)
minimo, maximo = 120, 880
print("Normalizacion (min=120, max=880):", [(x, round(1000 * (maximo - x) / (maximo - minimo))) for x in (150, 300, 500, 700, 850)])Con 5 sensores a 10 mm, línea de 18 mm y campo de 8 mm: cobertura de 48 mm, error típico de 1,13 mm, máximo de 2,73 mm y ninguna posición perdida. Con línea de 3 mm: 2,71 y 4,70 mm, y 6 % de posiciones sin línea. Con 15 mm de separación y línea de 3 mm: 37,3 % sin línea. La clasificación da CENTRADA para 00100 y 01110, IZQUIERDA para 01100, RAMA A LA IZQUIERDA para 11100, CRUCE para 11111, INCONSISTENTE para 10101 y PERDIDA para 00000. La normalización con mín 120 y máx 880 lleva 300 a 763 y 500 a 500.
Probá n = 7 con d = 8, o un campo s = 12, y compará el error y las posiciones perdidas. Agregá una compuerta de ruido distinta y mirá cómo cambian las pérdidas con la línea fina.
11 · Método y diagnóstico
Pruebas y diagnóstico
- Con el robot parado, pasá el arreglo a mano por una línea de prueba y verificá que cada sensor llega a valores altos sobre la línea y bajos sobre el fondo.
- Revisá el contraste de cada sensor tras calibrar:
máx − mínpequeño indica altura, cableado o iluminación malos. - Comprobá el orden: el sensor 0 debe corresponder al de la izquierda y la posición debe ser positiva con la línea a la izquierda.
- Recorré a mano los patrones de la tabla y confirmá la clasificación de cada uno.
- Probá con luz distinta (ventana, lámpara, sombra) y con otra superficie; repetí la calibración donde vayas a usarlo.
- Dibujá una pista con curvas de radio decreciente y cruces, y anotá el radio mínimo que el arreglo no pierde.
- Provocá una pérdida de línea (levantá el arreglo, cortá la cinta) y verificá la política de búsqueda y su tiempo máximo.
«Con más sensores siempre es mejor»
Mejora cobertura y resolución, pero agrega cableado, tiempo de lectura y calibraciones. Más allá de lo que la pista exige, no aporta.
«Calibré una vez y sirve para siempre»
Las lecturas dependen de la luz, la altura, el suelo y la cinta. Hay que recalibrar cuando cambie algo de eso.
«Si no ve la línea, sigo recto»
Seguir recto sin ver la línea la pierde más. Hay que girar hacia el último lado conocido, con un tiempo máximo.
«Todos los sensores activos significa que estoy sobre la línea»
Significa cruce, zona negra, marca ancha o un sensor con el umbral mal calibrado. Hay que distinguirlo del centro.
«Un sensor que oscila entre 0 y 1 está roto»
Lo más probable es que esté en el borde de la línea sin histéresis, o con ruido. Revisá umbrales y calibración antes de cambiarlo.
«La posición estimada es exacta al milímetro»
Tiene un error de discretización de uno o pocos milímetros que depende de la geometría y del ancho de la línea.
12 · Práctica guiada
Predecí antes de comprobar
1. Cobertura
Un arreglo tiene 6 sensores separados 12 mm y cada uno ve un círculo de 8 mm. ¿Cuál es su cobertura?
Ver solución
(6 − 1)·12 + 8 = 68 mm.
2. Línea que se pierde
Con d = 12 mm y s = 8 mm, ¿qué ancho mínimo debe tener la línea para no caer en el hueco entre dos sensores?
Ver solución
El hueco es d − s = 4 mm. La línea debe ser más ancha que 4 mm (y en la práctica con margen, porque la lectura en el borde es muy débil).
3. Normalizar
Un sensor calibró mín = 120 y máx = 880. Con línea oscura, ¿qué valor normalizado da una lectura de 300? Si el sensor estaba desactivado y los umbrales son 600/400, ¿se activa? ¿Y con una lectura de 500?
Ver solución
q = 1000·(880 − 300)/760 ≈ 763: supera 600, se activa. Con 500, q = 500: entre 400 y 600 conserva el estado anterior (desactivado).
4. Posición ponderada
Cinco sensores separados 8 mm (el 0 a la izquierda) leen (0; 0,3; 1; 0,5; 0). ¿Cuánto vale la posición estimada y hacia dónde está la línea?
Ver solución
Posiciones (+16, +8, 0, −8, −16). p = (8·0,3 − 8·0,5)/1,8 ≈ −0,89 mm: casi centrada, apenas a la derecha.
5. Clasificar
Clasificá los patrones 01100, 11100 y 10101.
Ver solución
01100: línea a la izquierda, corrección suave. 11100: curva cerrada o ramificación hacia la izquierda. 10101: inconsistente (hay huecos entre los activos), conservar la acción anterior.
6. Curva mínima
El arreglo está 60 mm delante del eje y su semi-cobertura es de 24 mm. ¿Qué radio de curva, como mínimo, puede soportar en el peor caso sin perder la línea?
Ver solución
Rmín ≈ L²/(2h) = 3600/48 = 75 mm. Una curva más cerrada exigiría que el robot ya estuviera girando, o un arreglo más ancho o más cercano.
7. Avance por ciclo
Con un ciclo de lectura y control de 20 ms, ¿cuánto avanza el robot entre lecturas a 30 cm/s y a 90 cm/s? ¿Cómo se compara con una cinta de 18 mm?
Ver solución
0,30 × 0,02 = 6 mm y 0,90 × 0,02 = 18 mm. A 90 cm/s avanza el ancho completo de la cinta por ciclo: la información llega tarde y la velocidad se vuelve el límite.
13 · Síntesis
Ideas para recordar
- Un seguidor de línea es un lazo cerrado cuya medición es la posición de la línea; la mayoría de los fallos nacen en los sensores.
- La geometría fija lo posible: cobertura
(n−1)·d + s, huecod − smenor que el ancho de la línea, y resolución del orden ded. - Se normaliza cada sensor con su mínimo y máximo y se calibra donde se usa; el contraste bajo es una señal de alerta.
- La posición se estima con un promedio ponderado; tiene un error de discretización de unos milímetros.
- Se combinan un clasificador de patrones (qué situación es) y un comportamiento (qué hacer).
- Los casos de borde —línea perdida, cruces, curvas cerradas, lecturas inconsistentes— necesitan una política explícita, con memoria del último lado y tiempos máximos.
- La velocidad máxima la limitan la distancia por ciclo y la anticipación del arreglo, no solo los motores.
- Más sensores no siempre es mejor: se dimensiona según la pista.
¿Listo para el tema 31?
Antes de avanzar, dibujá la pista que quieras recorrer (ancho de la línea, radio mínimo de curva, cruces) y dimensioná tu arreglo: cantidad de sensores, separación, altura y distancia al eje. Calculá la cobertura, el hueco y el radio mínimo que no pierde la línea.
En el próximo tema usamos la posición de la línea para corregir el movimiento: el seguidor de línea con control proporcional, que calcula el error de posición y ajusta la velocidad de cada rueda.