Construye un robot ROS 2 que localiza marcadores visuales
Un robot que detecta un marcador óptico en la sala, estima su posición 3D relativa y se acopla perpendicularmente, estructurado en un grafo de nodos ROS 2.
Qué vas a construir
Un robot que se coloca en algún punto de una habitación, gira hasta encontrar un marcador impreso en una pared y se acerca hasta él —parándose a medio metro, escuadrado respecto a la cara del marcador y no simplemente cerca de él.
Todas las demás construcciones de este sitio ejecutan un programa en un microcontrolor. Esta es un ordenador con ruedas, y eso cambia en qué consiste el proyecto. Las partes difíciles ya no son la temporización y el cableado: son saber dónde están las cosas unas respecto a otras, y mantener honestas entre sí a varias piezas de software mientras todas corren a la vez.
Por qué este robot necesita un ordenador
Un Arduino no puede hacer esto, y la razón merece precisión. No es la velocidad bruta: es que un fotograma de cámara es un cuarto de megabyte, la detección de ArUco quiere álgebra lineal en coma flotante, y todo eso tiene que ocurrir mientras las ruedas todavía reciben órdenes a 50 Hz. Eso es un trabajo para un sistema operativo con memoria real y planificación real.
Lo que gana a cambio esa caja con Linux es la capacidad de mirar dentro de un robot en
funcionamiento. Cada mensaje entre cada parte es un topic al que puedes suscribirte desde un
portátil. Cuando el robot pasa de largo el marcador en vez de ir a él, no añades prints y
recompilas: haces ros2 topic echo de la pose y la ves estar mal en tiempo real.
La forma del grafo de nodos
Cinco responsabilidades, un nodo cada una:
| Nodo | Publica | Trabajo |
|---|---|---|
camera |
/image_raw, /camera_info |
Saca fotogramas del bus CSI |
aruco_detector |
TF camera_link → marker_7 |
Encuentra la etiqueta y resuelve su pose |
docking_controller |
/cmd_vel |
Decide hacia dónde conducir |
diff_drive |
serie hacia el Arduino | Convierte un Twist en velocidades de rueda |
odometry |
TF odom → base_link |
Integra los pulsos del encoder |
Las interfaces son lo que hace que valga la pena estructurarlo así. El controlador nunca toca una
cámara ni un motor: consume una transformada y produce un Twist. Eso significa que puedes
conducir el mismo robot con teleoperación de teclado, probar el controlador contra una
transformada falsa sin hardware alguno, y más adelante colocar un stack de navegación que publique
el topic idéntico.
Lee nodos, topics, servicios y acciones antes de dibujar tu propia versión de esa tabla. El error más común en esta etapa es hacer el controlador de acoplamiento un servicio: es un objetivo de larga duración que tienes que poder cancelar, y eso es exactamente para lo que existe una acción.
Lista de materiales
Este es el robot de dos cerebros, y la lista de piezas lo refleja: un ordenador para la percepción y un microcontrolador para lo que un ordenador no puede hacer de forma fiable.
| Componente | Cant. | Coste aprox. | Notas |
|---|---|---|---|
| Raspberry Pi 4, 4 GB | 1 | $55 | 4 GB es el suelo práctico para ROS 2 más visión. Con 1 GB empieza a intercambiar y muere |
| Módulo de cámara Pi 3 | 1 | $25 | La variante Wide es mejor para navegación: 102° en vez de 66° |
| microSD de clase A2, 32 GB | 1 | $8 | O arrancar desde un SSD USB, que es realmente más rápido |
| Disipador o ventilador | 1 | $5 | Una Pi 4 se estrangula a 80 °C, y una Pi estrangulada pierde fotogramas |
| Arduino Uno o Nano | 1 | $5 | Encoders y control de motores: la mitad de tiempo real |
| Motores N20 con encoder | 2 | $16 | |
| TB6612FNG | 1 | $3 | |
| Chasis 2WD | 1 | $12 | Sitio para una Pi, un mástil de cámara y una batería |
| Pack de baterías | 1 | $15 | 3S con regulador de 5 V conmutado dimensionado para 3 A |
| Marcadores ArUco impresos | — | $0 | Imprímelos, mide el tamaño impreso y usa la medida |
Total: unos $145–175. Este es, con diferencia, el proyecto más caro del sitio, y casi todo es la Pi.
La alimentación es donde fallan estos robots, y el fallo es caro. Un apagón durante una
escritura en la tarjeta SD corrompe la imagen completa del sistema. Usa un regulador conmutado
dimensionado muy por encima del consumo de la Pi, nunca compartas el raíl con los motores, y
comprueba vcgencmd get_throttled: cualquier valor distinto de cero significa que la alimentación
es insuficiente y que se avecina una tarjeta corrupta.
Mide tus marcadores impresos. La solución de pose de un ArUco escala directamente con el tamaño de marcador que declaras. Un marcador impreso al 95 % por el “ajustar a la página” de una impresora da poses un 5 % equivocadas a cualquier distancia, y nada en la cadena te lo va a decir.
Orden de construcción
1 — Pon ROS 2 en marcha y demuestra la red. Sigue
instalar ROS 2 en una Raspberry Pi. No avances hasta que
ros2 topic echo en tu portátil muestre un topic publicado en el robot. El descubrimiento por
Wi-Fi es, con diferencia, lo más probable que te coma una tarde, y quieres que te la coma ahora y
no mientras depuras visión.
2 — Haz que las ruedas obedezcan a un Twist. Cablea el Arduino, los encoders y el TB6612FNG, y monta el puente de cmd_vel. Hito: la teleoperación de teclado desde el portátil conduce el robot real. Calibra aquí la separación de las ruedas: todo lo de después la hereda.
3 — Calibra la cámara. Bien, con un objetivo real, siguiendo calibración de cámara y pose ArUco. Una cámara sin calibrar produce poses que parecen plausibles y están equivocadas en decenas de porcentaje en los bordes del fotograma, que es el peor modo de fallo disponible.
4 — Publica el marcador como transformada. No como un mensaje propio con una x y una y dentro.
Publicar camera_link → marker_7 en TF2 significa que
el controlador puede preguntar “¿dónde está el marcador, en base_link?”, y la respuesta tiene en
cuenta exactamente cómo está montada tu cámara, incluido el hecho de que está inclinada, que lo
está.
5 — Conduce hacia el marcador. Un controlador proporcional sobre el rumbo: gira hacia él, avanza, para en la distancia de standoff. Esto funciona, y llega con un ángulo, que es precisamente el punto del paso siguiente.
6 — Acércate siguiendo la normal. En vez de dirigir al marcador, calcula un waypoint apartado de la cara del marcador a lo largo de su normal, conduce hasta él, y solo entonces entra recto. Esta es la diferencia entre llegar al muelle y atracar. También es donde empieza a importar la orientación del marcador —la parte de la pose que no necesitabas hasta ahora— y donde te encontrarás con la ambigüedad de pose.
7 — Envuélvelo en una máquina de estados. Buscar, aproximar, alinear, final, hecho, más las transiciones de salida de cada uno cuando se pierde el marcador. Las máquinas de estados finitos para el comportamiento de un robot cubren la estructura; lo concreto que este robot necesita es un tiempo de espera por pérdida de marcador que vuelva a buscar en vez de seguir con la última pose conocida.
Notas de hardware que importan
Monta la cámara rígidamente, y mide cómo. Toda pose que el robot calcula es relativa a la
cámara, y TF2 la convierte en una pose relativa al robot usando la transformada que tú declaras
de base_link a camera_link. Una cámara en un soporte flexible convierte esa transformada
declarada en una mentira que varía con la aceleración.
Inclina la cámara hacia abajo, y dilo. Una cámara apuntando al horizonte pierde el marcador justo cuando el robot se acerca. De diez a quince grados hacia abajo la mantiene en el fotograma durante el acercamiento final, y esa inclinación va en la transformada estática, no en un factor de corrección dentro del controlador.
Mide el marcador con un calibre. La escala de pose es directamente proporcional al tamaño de marcador que le digas al solucionador. Imprimir al 96 % porque la impresora ajustó a la página hace que cada distancia esté un 4 % equivocada, en silencio y de forma consistente.
Alimenta la Pi por separado de los motores. Un motor que se bloquea hunde el raíl, y donde un Arduino se reiniciaría sin daño, una Pi corrompe su sistema de archivos. O un regulador separado o un pack separado: este no es el sitio para ahorrar un componente.
Mantiene el cable plano de la cámara lejos de los cables de motor. Es un enlace de alta velocidad sin blindaje. El ruido de motor acoplado en él aparece como fotogramas corruptos, que aparecen como detecciones que parpadean sin ninguna razón visible.
Qué significa hacerlo bien
| Medida | Típico en una Pi 4 |
|---|---|
| Captura de cámara a 640×480 | 30 fps |
| Detección de ArUco, 640×480 | 25–30 fps, usando el 40–60 % de un núcleo |
| Detección de ArUco, 1920×1080 | 5–8 fps, y cada fotograma está obsoleto |
| Alcance de detección del marcador (marcador de 100 mm, 640×480) | 1.5–2.5 m |
| Precisión de pose a 1 m | ±2–5 cm en posición, ±3–5° en orientación |
| Latencia total de imagen a decisión | 60–120 ms |
| Lazo de control de motores, en el Arduino | 100–200 Hz |
| Latencia de topic ROS 2, de la Pi al Arduino por serie | 5–15 ms |
Dos filas llevan la lección de todo el proyecto.
La resolución no es gratis, y subirla suele empeorar las cosas. Pasar de 640×480 a 1080p cuesta 4–6× el procesamiento para aproximadamente 1.7× el alcance de detección. A menos que necesites ver un marcador más lejos de forma específica, el fotograma más pequeño te da una respuesta más rápida y más fresca, y la frescura importa más que la precisión en un lazo de control.
La fila de latencia es la razón de la división en dos cerebros. A 0.3 m/s, 100 ms de latencia de visión son 3 cm de recorrido; girando a 90°/s son 9° de rotación. Toda medida de visión describe dónde estaba el robot anteriormente. Ciérrala directamente como un lazo rápido y oscilará. La estructura que funciona es la que usa este robot: el Arduino ejecuta el lazo rápido con los encoders, y la visión lo corrige despacio — exactamente la misma forma que fusionar GPS con odometría en el rover de waypoints, y por exactamente el mismo motivo.
Rolling shutter, si el robot se mueve mientras mira
Los módulos de cámara estándar de la Pi tienen obturador rolling: las filas se exponen una tras otra, así que la parte superior de un fotograma se captura unos milisegundos antes que la inferior. Quieto, esto es invisible. Girando a 90°/s, las cuatro esquinas de un marcador ArUco se capturaron en cuatro orientaciones distintas del robot, y la pose resuelta a partir de ellas está equivocada de una manera que la calibración no puede arreglar.
Si el robot tiene que hacer visión mientras se mueve, para eso está el módulo Global Shutter. Si puede permitirse parar, mirar y luego moverse, el módulo más barato es perfectamente suficiente, y parar para mirar es una decisión de diseño legítima, no un apaño.
Cuando va mal
| Síntoma | Causa habitual |
|---|---|
| El portátil no ve ningún topic | Multicast bloqueado por el punto de acceso, o ROS_DOMAIN_ID distinto |
| Marcador detectado, el robot no se mueve | Twist publicado contra un suscriptor de TwistStamped |
| La distancia se desvía siempre en unos pocos puntos porcentuales | Tamaño de marcador equivocado, o la impresora escaló la página |
| La pose tiembla mucho a distancia | Marcador demasiado pequeño en el fotograma: acércate o imprime más grande |
| La normal del marcador se voltea de un lado a otro | Ambigüedad de pose: acércate fuera del eje o usa un tablero ChArUco |
| El robot llega cerca del marcador pero torcido | Está dirigiendo al marcador en vez de a lo largo de su normal |
| Se pasa de largo en el acercamiento final | Está guiándose por una pose de 50–100 ms de antigüedad: reduce al final |
| Sigue avanzando cuando el marcador sale del fotograma | No hay tiempo de espera por pérdida de marcador en la máquina de estados |
La distribución de esa tabla conviene apreciarla antes de empezar: casi nada de ella es visión por computador. Es redes, fotogramas, unidades y control, que es lo que construir un robot ROS 2 te enseña de verdad, y por eso la ruta de fundamentos de ROS 2 dedica su tiempo a patrones de comunicación y marcos de referencia más que a OpenCV.
Si esto es un paso demasiado lejos, el micromouse enseña mapeo y planificación en un microcontrolador sin nada de Linux, y el robot controlado por teléfono cubre la mitad “las órdenes llegan por una red” de este problema por una fracción de las piezas.
Hoja de ruta del proyecto
La ruta de construcción
Sigue el árbol tecnológico desde las piezas hasta un robot que funciona. Cada nodo se desbloquea cuando completas sus requisitos previos, y tu progreso se guarda en este dispositivo.
0 / 19 completados
Componentes
- ControladorRaspberry PiUn ordenador Linux completo del tamaño de una tarjeta: el cerebro para visión artificial y ROS.
- SensorRaspberry Pi Camera ModuleEl sensor óptico de alta definición conectado directamente al bus CSI para visión computacional.
- ControladorArduino UnoLa tolerante placa de 8 bits con la que la mayoría descubre la robótica.
- DriverTB6612FNG Motor DriverPuente en H dual con tecnología MOSFET: alta eficiencia y tamaño ultracompacto para robots móviles.
- ActuadorN20 Micro Gearmotor with EncoderMicromotor con reductora metálica y encoder trasero, para que el robot sepa cuánto ha avanzado realmente.
- Chasis2WD Robot ChassisLa plataforma donde se atornillan dos motores, una rueda loca y toda tu electrónica.
- AlimentaciónBattery Power PackLa fuente de energía determinante: por qué la química y la resistencia interna importan más que los voltios.
Tutoriales de esta ruta
- Principiante · 1 horaInstalar ROS 2 en Raspberry Pi y compilar un espacio de trabajoElige el sistema operativo, instala paquetes ROS 2 con apt, compila tu espacio colcon y conecta el robot con tu portátil.
- Principiante · 19 min de lecturaROS 2: Nodos, Topics, Servicios y AccionesElige el patrón de comunicación adecuado en ROS 2 e inspecciona el intercambio de datos y comandos entre nodos.
- Intermedio · 20 min de lecturaMarcos de coordenadas TF2 en ROS 2 para robots móvilesConstruye y depura un árbol de transformaciones TF2 desde map y odom a través de la base del robot hasta cada sensor.
- Intermedio · 22 min de lecturaCalibración de cámara y pose ArUco con OpenCVCalibra los intrínsecos de la cámara, valida el error de reproyección y estima la pose 3D de un marcador ArUco.
- Intermedio · 45 minDe cmd_vel a velocidades de rueda: tracción diferencial en ROS 2Convierte un Twist en velocidades de rueda izquierda y derecha: cinemática, saturación, banda muerta y un vigilante.
- Principiante · 17 min de lecturaLeer codificadores en cuadratura para distancia y velocidadConvierte los pulsos de un codificador en cuadratura en direccion, distancia y velocidad de rueda fiables.
- Principiante · 17 min de lecturaMaquinas de estados finitos para el comportamiento de robotsSustituye los condicionales enredados de un robot por estados, eventos, transiciones, tiempos de espera y recuperacion explicitos.
Preguntas frecuentes
¿Por qué utilizar ROS 2 en lugar de un único script en Python?
Para una prueba elemental aislada, un script monolítico en Python funcionaría y sería más breve; sin embargo, resulta inviable al escalar el sistema. En el instante en que el procesamiento visual, el lazo de control de tracción y la máquina de estados deben ejecutarse a frecuencias asíncronas sin bloquearse mutuamente, un script único degenera en un complejo problema de concurrencia artesanal. ROS 2 aporta aislamiento de procesos, serialización estandarizada y la capacidad fundamental de inspeccionar cualquier topic desde tu ordenador de desarrollo mediante herramientas como 'ros2 topic echo' mientras el robot opera en tiempo real.
¿Es imprescindible acoplar un Arduino junto a la Raspberry Pi?
No de forma estricta, pero optimiza radicalmente la fiabilidad del control motor. Raspberry Pi opera bajo un núcleo Linux de propósito general donde el planificador de procesos puede demorar la ejecución de los lazos motrices decenas de milisegundos. Esta fluctuación es inocua para el procesamiento de imagen pero perjudicial para un control PID de velocidad en bucle cerrado. Desacoplar la arquitectura (Raspberry Pi para percepción y planificación deliberativa; microcontrolador dedicado para conteo de encoders y generación de PWM determinista) constituye el estándar industrial en robótica móvil.
¿Por qué usar marcadores ArUco en lugar de detección de objetos reales?
Porque un marcador fiducial ArUco proporciona una pose tridimensional completa con 6 grados de libertad a partir de un único fotograma sin requerir redes neuronales pesadas ni introducir ambigüedad semántica. Detectar una silla señala aproximadamente su ubicación espacial; detectar una etiqueta ArUco entrega traslación y orientación exactas en metros y radianes respecto a la cámara. Por este motivo, las bases de recarga autónoma, flotas logísticas en almacenes y plataformas de aterrizaje de drones emplean marcadores fiduciales.
¿Por qué oscila erráticamente la orientación estimada del marcador?
Se debe a la ambigüedad geométrica de pose, inherente a la perspectiva óptica y no a un fallo de software. Un plano cuadrado observado casi frontalmente genera dos proyecciones tridimensionales proyectadas sobre píxeles casi idénticos en el plano focal, por lo que el ruido de discretización hace oscilar al algoritmo entre ambas soluciones. La distancia euclídea permanece estable pero el vector normal estimado salta abruptamente. Se resuelve empleando marcadores de mayor dimensión física, aproximándose con un ligero ángulo oblicuo o recurriendo a tableros ChArUco.
¿Qué tolerancia de precisión se obtiene en el acoplamiento?
Con cámara intrínsecamente calibrada y la dimensión física del marcador medida al milímetro con calibre, se consiguen precisiones de 1 a 2 cm a una distancia de medio metro. Las fuentes principales de desviación son: introducir una medida incorrecta del marcador (que escala proporcionalmente toda la estimación espacial) y la latencia del procesado de imagen (la pose recibida representa la posición del robot de hace 50–100 ms). Reducir la velocidad en los últimos 30 cm de aproximación mitiga este desfase temporal.
¿Puede implementarse en una Raspberry Pi Zero 2 W?
No es aconsejable para este proyecto específico. Aunque una Pi Zero 2 W puede ejecutar ROS 2 y decodificar vídeo, la detección continua de etiquetas ArUco satura completamente sus núcleos reduciendo la tasa de fotogramas, y la compilación del espacio de trabajo de colcon resulta excesivamente lenta. Se recomienda una Raspberry Pi 4 de 4 GB o una Pi 5 para disponer de suficiente memoria RAM y procesamiento.