← Índice del curso

Robótica y Automatización · Tema 7

Sensores de línea y de contacto

Una marca en el suelo y un interruptor mecánico pueden aportar información esencial al robot. Vamos a convertir reflectancia y contactos en estados útiles, con calibración, polaridad, tratamiento del rebote y decisiones explícitas ante señales ambiguas.

01 · Punto de partida

Observar el suelo y el contacto

En el tema anterior medimos distancia sin tocar el entorno. Ahora vamos a estudiar dos observaciones más locales: qué superficie hay debajo de un sensor y si una pieza accionó un contacto.

El reflectivo permite distinguir una marca del fondo para seguir una trayectoria. Un final de carrera informa que una articulación alcanzó una zona mecánica. Un bumper informa que una parte del robot hizo contacto con un objeto. Son datos simples, pero su interpretación necesita contexto.

Este tema prepara la adquisición. El control completo del seguidor de línea y las maniobras de recuperación se desarrollan más adelante; aquí no conectaremos motores desde los ejemplos de código.

02 · Luz reflejada

Cómo funciona un reflectivo infrarrojo

Un emisor ilumina una zona cercana y un receptor observa parte de la luz que regresa. La respuesta depende de la reflectancia infrarroja, la distancia, el ángulo y la iluminación ambiente. Una cinta que se ve negra al ojo no necesariamente tiene el mismo contraste en infrarrojo que otra cinta negra.

El sensor no reconoce el concepto «línea»: entrega una señal relacionada con el retorno óptico. La clasificación aparece cuando comparamos esa señal con referencias tomadas sobre el suelo y la marca.

Salidas que pueden aparecer en módulos reflectivos.
SalidaQué se adquiereQué revisar
AnalógicaTensión convertida con un ADCRango eléctrico, polaridad y calibración
Comparador digitalUn estado por encima o debajo de un ajusteNivel activo y posición del umbral
Temporizada tipo RCTiempo de descarga de un circuitoSecuencia de lectura, timeout y biblioteca correspondiente

La nota de aplicación de Pololu QTR muestra salidas analógicas y temporizadas. Una interfaz que usa un pin digital para medir tiempo no equivale a un comparador que solo entrega «línea sí/no».

Montá los sensores rígidamente a una altura apropiada para su modelo. Si el chasis cabecea o cambia la separación al suelo, puede cambiar el contraste aunque la superficie sea la misma. Protegé el campo de observación de piezas del propio robot.

03 · Dar significado a los números

Calibrar fondo y línea

Tomá varias lecturas de cada canal sobre el fondo y sobre la línea, en las condiciones de montaje reales. Una referencia de fondo de 200 y otra de línea de 800 permiten normalizar el canal:

q = limitar(1000 · (lectura − fondo) / (línea − fondo), 0, 1000)

La escala elegida significa 0 para la referencia de fondo y 1000 para la de línea. Con lectura 500, resulta 1000 × (500 − 200) / 600 = 500. No es una probabilidad del 50 %: es una posición en una escala calibrada.

La fórmula también sirve si la polaridad está invertida: con fondo 800 y línea 200, el denominador es negativo y la lectura de línea sigue dando 1000. Lo importante es conservar el significado de ambas referencias.

Calibrá por canal: dos sensores sobre la misma superficie pueden tener respuestas distintas. Recorré con todos ellos tanto el fondo como la marca, como propone la documentación de calibración QTR. No muevas el robot automáticamente durante una calibración sin haber preparado antes el espacio y la parada.

Limitar la escala evita valores fuera de 0–1000, pero puede ocultar que una lectura quedó lejos de las referencias. Conservá también el dato crudo para diagnosticar saturación y cambios de condiciones.

04 · De magnitud a estado

Umbrales e histéresis

Una regla simple declara línea cuando q ≥ 600. Cerca de ese límite, pequeñas variaciones pueden alternar el estado en cada lectura. La histéresis usa dos límites y conserva memoria:

  • Si estaba en fondo, entra a línea cuando q ≥ 600.
  • Si estaba en línea, vuelve a fondo cuando q ≤ 400.
  • Entre 400 y 600, conserva el estado anterior.

Si la secuencia es 550, 610, 580, 450, 390 y empieza en fondo, los estados son fondo, línea, línea, línea, fondo. La memoria evita cambios continuos alrededor de un único límite.

La histéresis no espera un tiempo fijo: decide según amplitud y estado previo. El antirrebote temporal, en cambio, exige estabilidad durante un intervalo. Ambas técnicas tienen objetivos y efectos distintos.

Los límites se eligen desde las distribuciones medidas de fondo y línea. Si ambas se superponen mucho, ajustar umbrales no crea información que el sensor no está observando.

05 · Información espacial

Varios sensores para ubicar una línea

Un solo canal indica qué tiene debajo. Tres canales distribuidos transversalmente aportan un patrón espacial. Usaremos izquierda, centro y derecha, vistos desde el robot mirando hacia adelante.

Tres sensores sobre una línea central Un arreglo de tres sensores mira el suelo. La línea está bajo el canal central; el izquierdo y el derecho observan fondo. Las posiciones relativas son menos uno, cero y más uno. Izquierda · −1Derecha · +1FondoFondoCentro0
Interpretaciones posibles con un bit por canal; 1 significa línea detectada.
Patrón I–C–DObservaciónQué evitar asumir
010Solo el centro detecta líneaNo garantiza la dirección futura de la marca
100 / 001Detección a izquierda / derechaNo fija por sí sola la velocidad de los motores
110 / 011Dos canales vecinos detectanPuede depender de ancho y ubicación
000Ningún canal supera el umbralNo distingue línea perdida, hueco o fallo
111 / 101Patrón amplio o separadoNo identifica automáticamente un cruce

Para patrones compatibles con una única marca local podemos calcular un centro ponderado:

x = (−1 · wI + 0 · wC + 1 · wD) / (wI + wC + wD)

En el laboratorio pondremos w = q solo en canales que superen el umbral; los demás pesan cero. Es un criterio didáctico y produce saltos al cruzar el umbral. Con 000 el denominador es cero; con 111 o 101 evitaremos dar una posición única aunque el promedio numérico pudiera calcularse.

06 · Interacción mecánica

Finales de carrera y bumpers

Un final de carrera se acciona cuando una pieza alcanza cierta posición. Puede dar una referencia inicial o indicar el límite de una articulación. Un bumper distribuye el contacto de un obstáculo mediante una pieza mecánica que acciona uno o varios interruptores.

El contacto no mide distancia anticipadamente. Entre tocar el mecanismo y detenerse pueden transcurrir adquisición, procesamiento y frenado. El recorrido útil del pulsador o bumper debe ser compatible con ese movimiento residual.

Una referencia de origen tampoco es una medición continua de posición. Tras encontrarla, el robot puede estimar desplazamientos con pasos o encoders, pero debe considerar pérdida de pasos, holgura y montaje.

Revisá fuerza y recorrido de accionamiento, posición de montaje y resistencia mecánica. No uses el pequeño pulsador como tope que absorbe toda la energía de un carro.

07 · Interpretación eléctrica

Cableado y polaridad

Una entrada sin referencia puede quedar flotante. Una resistencia de pull-up mantiene un nivel alto cuando el contacto está abierto; el contacto a masa produce nivel bajo al cerrar. La prueba InputPullupSerial de Arduino muestra esa conexión.

En un interruptor con terminales COM, NO y NC, NO es normalmente abierto y NC normalmente cerrado en su estado mecánico de reposo. Con COM a GND y la entrada configurada con pull-up:

Niveles esperados en un circuito simple, sin cortocircuitos ni otras conexiones.
Contacto hacia la entradaReposoAccionadoCable abierto
NOHIGHLOWHIGH: parecido al reposo
NCLOWHIGHHIGH: parecido al accionamiento

Con NC podemos tratar una apertura como condición de parada, tanto si la provoca el mecanismo como un cable interrumpido. No permite distinguir ambas causas ni detectar todos los fallos: un cortocircuito a masa puede ocultar el accionamiento.

Separá el dato eléctrico del significado: primero nivel = digitalRead(pin), después contactoActivo = nivel == HIGH para este montaje NC. No supongas que HIGH siempre significa «pulsado».

Estas conexiones son para contactos secos y lógica compatible. Una salida de sensor industrial puede necesitar adaptación; no conectes una señal de otra tensión directamente al GPIO. Verificá también los terminales reales con la documentación o una medición sin alimentación.

08 · Tiempo y estados

Rebote y tiempo de reacción

Al accionar un contacto mecánico puede abrirse y cerrarse varias veces antes de quedar estable. Si contás cada flanco, una sola acción puede parecer varios eventos. El ejemplo Debounce de Arduino presenta el problema y una técnica temporal.

Un antirrebote por estabilidad conserva el último nivel crudo y el instante de su cambio. Solo actualiza el estado confirmado si el nivel no vuelve a cambiar durante un intervalo elegido. No requiere detener el programa con delay().

Si el primer contacto ocurre a los 10 ms, rebota hasta los 18 ms y exigimos 20 ms de estabilidad, la confirmación llega a los 38 ms. Son 28 ms desde el primer contacto. A 30 cm/s se recorren 30 × 0,028 = 0,84 cm antes de sumar frenado.

El intervalo se determina con mediciones y requisitos del mecanismo. También importa el período de lectura: un contacto breve puede pasar entre dos muestreos y no ser observado. Ningún filtro recupera un pulso que nunca adquiriste.

09 · Código para la placa

Prueba de contacto con parada enclavada

Usaremos UNO R3 y un contacto seco NC: COM a GND y NC a D2, conectado sin alimentación. El código solo informa estados por serie; no gobierna un motor. Arranca inhibido. Enviá R desde el monitor a 115200 baudios para rearmar cuando el contacto lleve al menos 20 ms cerrado.

const byte PIN_CONTACTO = 2;
const unsigned long ESTABILIDAD_MS = 20;
bool ultimoCrudo;
bool estable;
bool parada = true;
unsigned long cambioMs = 0;
unsigned long ultimoLog = 0;

void setup() {
  pinMode(PIN_CONTACTO, INPUT_PULLUP);
  Serial.begin(115200);
  ultimoCrudo = digitalRead(PIN_CONTACTO);
  estable = ultimoCrudo;
  cambioMs = millis();
}

void loop() {
  const unsigned long ahora = millis();
  const bool crudo = digitalRead(PIN_CONTACTO);
  if (crudo != ultimoCrudo) {
    ultimoCrudo = crudo;
    cambioMs = ahora;
  }
  const bool confirmado = ahora - cambioMs >= ESTABILIDAD_MS;
  if (confirmado) estable = crudo;

  // NC abierto: accionamiento o cable interrumpido.
  if (crudo == HIGH) parada = true;

  if (Serial.available() > 0) {
    const char comando = Serial.read();
    if (comando == 'R' && confirmado
        && estable == LOW && crudo == LOW) {
      parada = false;
    }
  }
  if (ahora - ultimoLog >= 100) {
    ultimoLog = ahora;
    Serial.print("Crudo="); Serial.print(crudo);
    Serial.print("; estable="); Serial.print(estable);
    Serial.println(parada ? "; parada solicitada" : "; rearmado");
  }
}

Accionar o desconectar el contacto solicita parada desde la primera muestra HIGH. Volver al reposo no borra la solicitud: exige un rearme explícito y estabilidad LOW. En una máquina real, rearmar debe permitir preparar un nuevo arranque, sin provocar movimiento automáticamente.

El mensaje «estable» puede conservar el estado anterior mientras se confirma un cambio; el booleano confirmado expresa si el nivel actual cumplió el intervalo. El registro cada 100 ms no muestra todos los rebotes; para observarlos hace falta otra captura temporal.

Este esquema no detecta cortos a masa y depende de que el programa siga leyendo. No reemplaza la arquitectura de parada estudiada en el tema 4.

10 · Exploración interactiva

Laboratorios: patrones de línea y rebote

1. Tres canales sobre el suelo

Lecturas ficticias de ADC de 10 bits. Cada canal usa las mismas referencias para aislar el efecto de la polaridad; un montaje real se calibra por canal.

Umbral único de este laboratorio: q ≥ 600. Se rechaza una separación de referencias menor que 100 cuentas; es un criterio didáctico, no una especificación de sensor.

Patrón I–C–D—
Posición relativa—
Canales activos—

Modificá las lecturas para observar el patrón.

Normalización por canal. No representa probabilidad ni certeza.
Canalq (0–1000)Detecta línea

Recorrido guiado de línea

  1. Con las referencias 200/800 y los valores iniciales, el patrón es 010 y la posición es 0.
  2. Subí izquierda a 800: resulta 110 y la posición ponderada es −0,5.
  3. Pulsá «Todo fondo»: 000 no produce una posición. «Todo línea» genera 111, que tratamos como ambiguo.
  4. Cambiá a referencias invertidas y pulsá «Línea central»: los datos crudos pasan a 800, 200, 800, pero el significado sigue siendo 010.
  5. Elegí contraste insuficiente: se anulan patrón y posición, en vez de amplificar un contraste pobre.

2. Una pulsación con varios flancos

Esta segunda prueba usa un contacto NO con pull-up: HIGH en reposo y LOW activo. Se simula cada milisegundo entre 0 y 80 ms. Cierra a 10 ms, abre a 12, cierra a 14, abre a 16 y queda cerrado desde 18 ms. No es una medición de un pulsador real.

Entradas activas crudas—
Entradas activas confirmadas—
Primera confirmación activa—
Retardo desde primer contacto—

Elegí el tiempo de estabilidad.

Instantes donde cambia el nivel crudo o el confirmado.
TiempoCrudoConfirmado

Con 0 ms aparecen tres activaciones confirmadas. Con 20 ms aparece una, a los 38 ms: el retardo respecto del primer contacto es 28 ms. Con 40 ms se confirma a los 58 ms. Los resultados muestran por qué filtrar un evento no equivale a reaccionar inmediatamente.

11 · Código ejecutable

Histéresis en Python

Comparemos un umbral único de 600 con una regla que entra a 600 y sale a 400. Los valores ya están normalizados y se consideran válidos y recientes.

Probalo en el navegador. El código es editable. Python se descarga con Pyodide la primera vez y requiere conexión; no controla hardware.

lecturas = [550, 610, 590, 605, 580, 450, 390]
en_linea = False
anterior_simple = False
cambios_simple = 0
cambios_histeresis = 0

for q in lecturas:
    simple = q >= 600
    previo = en_linea
    if not en_linea and q >= 600:
        en_linea = True
    elif en_linea and q <= 400:
        en_linea = False
    cambios_simple += simple != anterior_simple
    cambios_histeresis += en_linea != previo
    anterior_simple = simple
    print(f"q={q}: simple={simple}; histéresis={en_linea}")

print("Cambios con umbral único:", cambios_simple)
print("Cambios con histéresis:", cambios_histeresis)

El umbral único cambia cuatro veces y la histéresis dos: entra con 610 y sale con 390. Cambiá la última lectura a 450: la histéresis mantiene línea porque todavía no cruzó el límite de salida.

La memoria inicial también importa. Si el programa arranca en mitad de la banda, necesitás una política de inicialización. En un sistema real, una calibración inválida debe producir un estado de medida no utilizable, no conservar indefinidamente una decisión vieja.

12 · Método y diagnóstico

Pruebas y errores frecuentes

  1. Registrá fondo y línea por canal, con altura y alimentación de trabajo.
  2. Repetí sobre bordes, curvas, uniones y cambios de iluminación.
  3. Ensayá 000, 111 y patrones separados sin asignarles significados automáticos.
  4. Verificá niveles de contacto en reposo, accionado y con cable abierto.
  5. Capturá los cambios temporales y elegí el filtrado desde la reacción requerida.
  6. Probá enclavamiento y rearme antes de integrar actuadores.
«Negro siempre da cero y blanco siempre da uno»

Depende de óptica, electrónica y polaridad. Medí referencias y documentá el nivel activo; no deduzcas la lógica por el color visible.

«El potenciómetro del módulo lo calibra para cualquier suelo»

Ajusta un umbral del comparador. Si cambia altura, material o iluminación, la separación puede dejar de ser válida. El ajuste no elimina la necesidad de ensayos.

«111 demuestra que llegué a una intersección»

También puede ser una zona ancha, una marca transversal, polaridad incorrecta o una condición óptica anormal. Identificar cruces requiere contexto espacial y temporal.

«NC detecta cualquier rotura»

En el circuito mostrado, una apertura produce nivel activo, pero un corto a masa puede mantener el nivel de reposo. No es una supervisión completa de fallos.

«Un debounce largo siempre es mejor»

Reduce ciertos eventos espurios, pero retrasa la confirmación y puede descartar contactos breves. Evaluá ese retardo junto al movimiento residual.

13 · Práctica guiada

Predecí antes de comprobar

1. Normalización

Fondo = 200, línea = 800 y lectura = 650. ¿Qué q resulta? ¿Supera el umbral de 600?

Ver solución

q = 1000 × (650 − 200) / (800 − 200) = 750. Sí, se clasifica como línea con ese umbral. No significa una probabilidad del 75 %.

2. Polaridad invertida

Ahora fondo = 800, línea = 200 y lectura = 350. ¿Cuál es la lectura normalizada?

Ver solución

q = 1000 × (350 − 800) / (200 − 800) = 750. El significado coincide aunque la escala cruda esté invertida.

3. Patrón sin posición única

Los tres canales detectan línea con el mismo peso. El promedio da x = 0. ¿Por qué el laboratorio no lo trata como línea central normal?

Ver solución

El promedio pierde la forma del patrón. 111 puede representar una zona amplia o ambigua; no aporta la misma evidencia que 010. Dar cero sin conservar esa distinción ocultaría información importante.

4. Contacto NC

Con COM a GND, NC a una entrada con pull-up y política activa en HIGH, ¿qué ocurre al cortar el cable? ¿Y al cortocircuitar la entrada a masa?

Ver solución

El cable abierto deja HIGH y solicita parada. El corto a masa mantiene LOW y puede ocultar el accionamiento. El circuito simple no distingue ni cubre todos los fallos.

5. Retardo de confirmación

El primer contacto ocurre a 10 ms, el último rebote a 18 ms y exigís 20 ms estables. ¿Cuándo se confirma y cuánto avanza un vehículo de 50 cm/s desde el primer contacto?

Ver solución

Se confirma a 38 ms. El retardo es 28 ms y el avance 50 × 0,028 = 1,4 cm, antes de sumar otros retardos y frenado.

6. Histéresis

Con entrada a 600, salida a 400 y estado inicial fondo, procesá 620, 580, 410, 400, 590. ¿Qué estados quedan?

Ver solución

Línea, línea, línea, fondo, fondo. La igualdad con 400 dispara salida; 590 no alcanza para entrar otra vez.

14 · Síntesis

Ideas para recordar

  • Un reflectivo mide una respuesta óptica local, no el significado de una línea.
  • Calibrá fondo y marca por canal, comprobando contraste, altura y polaridad.
  • La histéresis conserva estado entre dos límites y no equivale a un filtro temporal.
  • Un arreglo aporta patrones; 000 y los patrones ambiguos necesitan tratamiento explícito.
  • Los contactos informan una condición mecánica y no absorben por sí mismos el movimiento restante.
  • NO, NC y pull-up determinan niveles eléctricos que el programa debe interpretar.
  • El antirrebote reduce eventos múltiples a costa de retardo y posible pérdida de pulsos breves.
  • Separá solicitud de parada, confirmación del estado, rearme y nuevo arranque.

¿Listo para el tema 8?

Antes de avanzar, normalizá tres lecturas con tus propias referencias y explicá qué harías ante 000. Después dibujá un contacto NC con pull-up e indicá qué fallos puede y no puede revelar.

En el próximo tema estudiamos sensores inerciales: acelerómetro, giroscopio e IMU, con orientación, deriva y una introducción a la fusión mediante filtro complementario.