Caso práctico: UGV Beast ROS 2 con RPi seguidor de línea

Caso práctico: UGV Beast ROS 2 con RPi seguidor de línea — hero

Objetivo y caso de uso

Qué construirás: Un UGV tipo Beast con Raspberry Pi 4 y cámara Arducam OV5647, ejecutando ROS 2 Humble y un nodo propio ros2-line-follower-camera para seguir una línea negra en el suelo.

Para qué sirve

  • Automatizar un robot de reparto interno que sigue una ruta marcada en el suelo dentro de un almacén.
  • Guiar un vehículo educativo en circuitos de competición de seguidores de línea, con curvas suaves y cambios moderados de iluminación.
  • Implementar rutas predefinidas en laboratorios o fábricas para mover piezas ligeras entre estaciones sin usar sensores adicionales.
  • Prototipar AGVs de logística interna que se orientan únicamente con visión monocular (cámara frontal) y una línea en el piso.
  • Practicar visión artificial básica aplicada a robótica móvil en ROS 2, incluyendo publicación de imágenes y control de velocidad.

Resultado esperado

  • Mantener el centro del robot dentro de un corredor de ±5 cm respecto al centro de la línea durante al menos el 90 % del recorrido en un circuito simple.
  • Publicar imágenes de la cámara en /camera/image_raw a ≥ 15 FPS con carga de CPU < 70 % en la Raspberry Pi 4.
  • Publicar comandos de velocidad en /cmd_vel desde ros2-line-follower-camera a ≥ 10 Hz, con latencia desde captura de imagen hasta comando < 100 ms.
  • Completar un circuito cerrado de prueba (p. ej., 10–20 m con 3–4 curvas amplias) sin salirse de la línea más de 2 veces por vuelta.

Público objetivo: Estudiantes de robótica, makers y desarrolladores que comienzan con ROS 2 en plataformas móviles; Nivel: Inicial–intermedio en ROS 2 y Linux, básico en visión por computador.

Arquitectura/flujo: La cámara Arducam OV5647 se conecta a la Raspberry Pi 4, que ejecuta un nodo de cámara (publica en /camera/image_raw) y el nodo ros2-line-follower-camera; este nodo procesa cada frame, detecta la posición de la línea, calcula el error lateral y el ángulo de la línea, los traduce en comandos de velocidad lineal y angular que publica en /cmd_vel, y el controlador del UGV aplica dichos comandos a los motores en tiempo casi real.

Prerrequisitos (SO, versiones y toolchain concreta)

Sistema operativo y hardware

  • Plataforma principal:
  • Raspberry Pi 4 Model B 4GB (aarch64)
  • Sistema operativo:
  • Ubuntu Server 22.04 LTS 64‑bit para Raspberry Pi (aarch64), sin entorno gráfico.
  • Conectividad:
  • Acceso SSH a la Raspberry Pi desde un PC en la misma red (para editar, compilar y probar).

Toolchain y versiones

En la Raspberry Pi (aarch64):

  • ROS 2:
  • Distribución: ROS 2 Humble Hawksbill
  • Paquetes instalados vía apt:
  • ros-humble-desktop
  • ros-humble-ros2-control
  • ros-humble-diff-drive-controller
  • ros-humble-robot-localization
  • ros-humble-slam-toolbox
  • ros-humble-nav2-bringup
  • ros-humble-nav2-costmap-2d
  • ros-humble-nav2-controller
  • ros-humble-nav2-planner
  • ros-humble-nav2-behavior-tree
  • ros-humble-nav2-lifecycle-manager
  • ros-humble-rviz2
  • Lenguaje principal para el nodo seguidor de línea:
  • Python 3.10 (incluido en Ubuntu 22.04)
  • Compilación:
  • colcon versión instalada desde repositorios de Ubuntu (python3-colcon-common-extensions)
  • Gestión de paquetes:
  • apt (Ubuntu)
  • Control de versiones (opcional pero recomendado):
  • git ≥ 2.34

Materiales

Lista de materiales principales

  • 1 × Raspberry Pi 4 Model B 4GB + Arducam 5MP OV5647 Camera Module (modelo exacto solicitado).
  • 1 × Tarjeta microSD (32 GB o más, clase 10), con Ubuntu Server 22.04 64‑bit instalado.
  • 1 × Chasis de robot tipo UGV Beast con:
  • 2 motores DC con encoder (tracción diferencial).
  • 2 ruedas motrices + rueda loca.
  • Controlador de motores (por ejemplo, un driver tipo L298N o un hat específico para la plataforma Beast).
  • 1 × Fuente de alimentación/batería adecuada para el UGV (por ejemplo, LiPo 2S–3S con BEC o banco de baterías con regulación).
  • 1 × Cable USB para depuración (si el chasis incluye microcontrolador adicional).
  • 1 × Conexión a red (Ethernet o Wi-Fi configurado en la Raspberry Pi).
  • Cables Dupont macho-macho / macho-hembra para la conexión GPIO (si el driver de motores se controla desde la Pi).

Material opcional (pero útil)

  • Regla o metro para medir desplazamientos reales y calibrar el robot.
  • Cinta aislante negra para marcar la línea en el suelo.
  • Cartulina blanca o espuma EVA blanca como fondo de alto contraste.

Preparación y conexión

1. Preparación del sistema operativo y ROS 2 Humble

  1. Instala Ubuntu Server 22.04 64‑bit (aarch64) en la microSD (por ejemplo con Raspberry Pi Imager).
  2. Arranca la Raspberry Pi 4 con la microSD y conéctala a red.
  3. Actualiza el sistema:

bash
sudo apt update
sudo apt upgrade -y

  1. Instala ROS 2 Humble y paquetes necesarios:

bash
sudo apt install -y \
ros-humble-desktop \
ros-humble-ros2-control \
ros-humble-diff-drive-controller \
ros-humble-robot-localization \
ros-humble-slam-toolbox \
ros-humble-nav2-bringup \
ros-humble-nav2-costmap-2d \
ros-humble-nav2-controller \
ros-humble-nav2-planner \
ros-humble-nav2-behavior-tree \
ros-humble-nav2-lifecycle-manager \
ros-humble-rviz2 \
python3-colcon-common-extensions \
python3-argcomplete \
git

  1. Añade el setup.bash de ROS 2 a tu .bashrc:

bash
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc

2. Habilitar la cámara Arducam 5MP OV5647 en Raspberry Pi 4

En Ubuntu Server 22.04 para Raspberry Pi, la cámara se habilita mediante:

  1. Editar /boot/firmware/config.txt:

bash
sudo nano /boot/firmware/config.txt

  1. Asegúrate de tener estas líneas (y sin #):

text
start_x=1
gpu_mem=128
dtoverlay=imx219 # En algunas imágenes se usa este overlay genérico para cámaras; revisar documentación Arducam

Nota: Algunas versiones de firmware usan dtoverlay=ov5647. Si tu módulo Arducam 5MP OV5647 tiene documentación que especifica este overlay, usa:

text
dtoverlay=ov5647

  1. Guarda y reinicia:

bash
sudo reboot

  1. Verifica que el dispositivo de cámara está presente (según kernel/driver, puede ser /dev/video0):

bash
ls /dev/video*

Debe aparecer algo como /dev/video0.

3. Conexión física de la cámara al Raspberry Pi 4

La Arducam 5MP OV5647 Camera Module se conecta mediante el conector CSI:

  • En la Raspberry Pi 4 hay un conector FPC (flex cable) cerca del conector HDMI.
  • Pasos (sin electricidad):
  • Apaga la Raspberry Pi y desconecta la alimentación.
  • Levanta suavemente la pestaña negra del conector CSI.
  • Inserta el cable plano de la Arducam con los contactos metálicos apuntando hacia los contactos del conector de la Pi.
  • Vuelve a bajar la pestaña hasta fijar el cable.
  • Conecta la alimentación y arranca.

4. Conexión del controlador de motores al Raspberry Pi 4

No dibujaremos esquema, pero describimos la conexión lógica típica (ejemplo con driver tipo L298N y motores DC):

Elemento Conexión en Raspberry Pi 4 Descripción breve
IN1 driver motor GPIO 17 (pin físico 11) Dirección rueda izquierda (bit 1)
IN2 driver motor GPIO 27 (pin físico 13) Dirección rueda izquierda (bit 2)
IN3 driver motor GPIO 22 (pin físico 15) Dirección rueda derecha (bit 1)
IN4 driver motor GPIO 23 (pin físico 16) Dirección rueda derecha (bit 2)
ENA (PWM izquierda) GPIO 18 (pin físico 12, PWM) Control velocidad izquierda
ENB (PWM derecha) GPIO 13 (pin físico 33, PWM) Control velocidad derecha
GND driver GND Raspberry Pi (ej: pin 6) Referencia común
+12 V (o según motores) Batería / fuente externa Alimentación motores (no desde la Pi)
5 V lógica driver (si hay) 5 V Pi (pin 2 o 4, según driver) Solo lógica, revisa que no back-feed 5 V

Importante: Asegúrate de que la masa (GND) de la Raspberry Pi y la del driver de motores está unida. Si tu chasis UGV Beast trae su propia placa controladora, adapta estos pines según la documentación del fabricante, pero mantén la lógica de “2 GPIO de dirección + 1 PWM por motor”.


Código completo del seguidor de línea con cámara

Crearemos un paquete ROS 2 en Python dentro de un workspace ~/ros2_ws. Este paquete:

  • Se llamará ros2_line_follower_camera.
  • Tendrá un nodo line_follower_node.py que:
  • Suscribe al tópico de la cámara /camera/image_raw.
  • Usa OpenCV para procesar la imagen, detectar la línea negra en el suelo.
  • Calcula un error horizontal (distancia del centro de la línea al centro de la imagen).
  • Genera comandos de velocidad (lineal y angular) en /cmd_vel para un robot diferencial controlado por diff_drive_controller.

1. Crear el workspace y el paquete

mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src

ros2 pkg create --build-type ament_python ros2_line_follower_camera

Instala dependencias necesarias para procesamiento de imágenes:

sudo apt install -y python3-opencv python3-numpy

Edita el archivo package.xml del paquete (~/ros2_ws/src/ros2_line_follower_camera/package.xml) y asegúrate de incluir dependencias:

<exec_depend>rclpy</exec_depend>
<exec_depend>sensor_msgs</exec_depend>
<exec_depend>geometry_msgs</exec_depend>
<exec_depend>cv_bridge</exec_depend>

Instala ros-humble-cv-bridge:

sudo apt install -y ros-humble-cv-bridge

2. Nodo Python line_follower_node.py

Crea el archivo ~/ros2_ws/src/ros2_line_follower_camera/ros2_line_follower_camera/line_follower_node.py:

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node

from sensor_msgs.msg import Image
from geometry_msgs.msg import Twist

from cv_bridge import CvBridge
import cv2
import numpy as np


class LineFollowerNode(Node):
    def __init__(self):
        super().__init__('line_follower_node')

        # Parámetros configurables
        self.declare_parameter('camera_topic', '/camera/image_raw')
        self.declare_parameter('linear_speed', 0.15)   # m/s
        self.declare_parameter('kp_angular', 0.0025)   # ganancia proporcional
        self.declare_parameter('view_height_ratio', 0.3)  # zona inferior de la imagen a usar

        camera_topic = self.get_parameter('camera_topic').get_parameter_value().string_value
        self.linear_speed = self.get_parameter('linear_speed').get_parameter_value().double_value
        self.kp_angular = self.get_parameter('kp_angular').get_parameter_value().double_value
        self.view_height_ratio = self.get_parameter('view_height_ratio').get_parameter_value().double_value

        # Puente ROS 2 <-> OpenCV
        self.bridge = CvBridge()

        # Suscriptor a la cámara
        self.image_sub = self.create_subscription(
            Image,
            camera_topic,
            self.image_callback,
            10
        )

        # Publicador de velocidad
        self.cmd_vel_pub = self.create_publisher(Twist, '/cmd_vel', 10)

        self.get_logger().info(f'Line follower node iniciado. Suscrito a {camera_topic}')

    def image_callback(self, msg: Image):
        # Convertir a imagen OpenCV
        try:
            frame = self.bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8')
        except Exception as e:
            self.get_logger().error(f'Error al convertir imagen: {e}')
            return

        height, width, _ = frame.shape

        # Usar solo la franja inferior de la imagen para buscar la línea
        roi_height = int(height * self.view_height_ratio)
        y_start = height - roi_height
        roi = frame[y_start:height, 0:width]

        # Convertir a escala de grises
        gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

        # Suavizar para reducir ruido
        blur = cv2.GaussianBlur(gray, (5, 5), 0)

        # Umbral binario: asumimos línea negra sobre fondo claro
        _, binary = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

        # Encontrar contornos
        contours, _ = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        if contours:
            # Tomar el contorno más grande como la línea principal
            largest_contour = max(contours, key=cv2.contourArea)
            M = cv2.moments(largest_contour)

            if M['m00'] > 0:
                cx = int(M['m10'] / M['m00'])  # centroide x
                cy = int(M['m01'] / M['m00'])  # centroide y (en ROI)

                # Error de posición (positivo si la línea está a la derecha)
                error_x = cx - width // 2

                # Control proporcional para la velocidad angular
                angular_z = -self.kp_angular * float(error_x)

                # Crear mensaje Twist
                cmd = Twist()
                cmd.linear.x = self.linear_speed
                cmd.angular.z = angular_z

                self.cmd_vel_pub.publish(cmd)

                self.get_logger().debug(
                    f'Linea detectada: cx={cx}, error_x={error_x}, ang_z={angular_z:.3f}'
                )
            else:
                # No se pudo calcular el centroide: para el robot
                self.stop_robot('Moment zero area (m00=0)')

        else:
            # Sin contornos: línea no encontrada, parar robot
            self.stop_robot('No se encontraron contornos para la línea')

    def stop_robot(self, reason: str):
        cmd = Twist()
        cmd.linear.x = 0.0
        cmd.angular.z = 0.0
        self.cmd_vel_pub.publish(cmd)
        self.get_logger().warn(f'Robot detenido: {reason}')


def main(args=None):
    rclpy.init(args=args)
    node = LineFollowerNode()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.stop_robot('Nodo finalizado')
        node.destroy_node()
        rclpy.shutdown()


if __name__ == '__main__':
    main()

Dale permisos de ejecución:

chmod +x ~/ros2_ws/src/ros2_line_follower_camera/ros2_line_follower_camera/line_follower_node.py

3. Ajustar setup.py del paquete

Edita ~/ros2_ws/src/ros2_line_follower_camera/setup.py:

from setuptools import setup

package_name = 'ros2_line_follower_camera'

setup(
    name=package_name,
    version='0.0.1',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
         ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='tu_nombre',
    maintainer_email='tu_email@example.com',
    description='Nodo seguidor de línea usando cámara OV5647 en Raspberry Pi 4 con ROS 2 Humble',
    license='Apache License 2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'line_follower_node = ros2_line_follower_camera.line_follower_node:main',
        ],
    },
)

Modelado del robot (URDF + ros2_control + diff_drive_controller)

Aunque el foco es el seguidor de línea, necesitamos que el UGV Beast se expose en ROS 2 como robot diferencial. Crearemos un URDF sencillo con diff_drive_controller.

1. Parámetros geométricos del UGV Beast

Debes medir tu robot:

  • Radio de rueda (wheel_radius): por ejemplo, 0.03 m (ruedas de 6 cm de diámetro).
  • Distancia entre centros de ruedas (wheel_separation o track width): por ejemplo, 0.18 m.

Añade estos valores a un archivo YAML de parámetros del controlador.

2. URDF simplificado

Crea un paquete de descripción ugv_beast_description:

cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake ugv_beast_description

Dentro crea urdf/ugv_beast.urdf.xacro. Para no alargar excesivamente, indicamos los elementos clave que deben existir:

  • base_link
  • left_wheel_link y right_wheel_link
  • Juntas left_wheel_joint y right_wheel_joint de tipo continuous
  • Plugin ros2_control con hardware y diff_drive_system.

En este caso práctico básico asumiremos que el control bajo nivel (GPIO/PWM) está gestionado fuera de ros2_control (por ejemplo, por un nodo propio o por firmware de la placa del Beast). Lo importante es que el diff_drive_controller publique/consuma /cmd_vel y odom.


Compilación, instalación y ejecución

1. Compilar el workspace con colcon

cd ~/ros2_ws
colcon build

Una vez completado:

echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc
source ~/.bashrc

2. Nodo de la cámara

Dependiendo del driver utilizado, puedes exponer la cámara como un nodo ROS 2. Una opción ligera en Ubuntu es usar un nodo genérico tipo v4l2_camera (si lo instalas). Para mantener el caso práctico sencillo, puedes usar un nodo ejemplo como image_tools (incluido en ros-humble-desktop) adaptado, pero lo más realista es:

Instalar v4l2_camera:

sudo apt install -y ros-humble-v4l2-camera

Lanzar el nodo de cámara:

ros2 run v4l2_camera v4l2_camera_node --ros-args -p video_device:=/dev/video0 -p image_size:="[640,480]"

Este nodo publicará en /image_raw. Ajusta el parámetro de tu line_follower_node para usar ese tópico, o remapea.

Ejemplo ejecutando el seguidor de línea con remapeo:

ros2 run ros2_line_follower_camera line_follower_node \
  --ros-args -p camera_topic:=/image_raw

3. Lanzar el controlador diferencial (diff_drive_controller)

Asumiendo que tienes un ros2_control configurado y un archivo de parámetros YAML, lanzarías algo como:

ros2 launch ugv_beast_bringup ugv_beast_diff_drive.launch.py

En este caso práctico básico, si aún no tienes implementada la parte ros2_control real con hardware, puedes:

  • Probar el nodo line_follower_node sin movimiento, sólo examinando /cmd_vel.
  • Implementar posteriormente el puente /cmd_vel → GPIO/PWM según tu hardware.

Validación paso a paso

1. Verificar que la cámara funciona

  1. Asegúrate de que /dev/video0 existe:

bash
ls /dev/video0

  1. Lanza el nodo v4l2_camera:

bash
ros2 run v4l2_camera v4l2_camera_node --ros-args -p video_device:=/dev/video0

  1. Comprueba que el tópico de imagen está activo:

bash
ros2 topic list

Debes ver algo como:

  • /image_raw
  • /camera_info

  • Comprueba el tipo de mensaje:

bash
ros2 topic echo /image_raw --qos-reliability best_effort --qos-durability volatile

Verás muchos datos binarios/imprimibles. Para medir tasa de publicación:

bash
ros2 topic hz /image_raw

Criterio de éxito: ≥ 15 Hz.

2. Verificar el nodo ros2-line-follower-camera

  1. Abre otra terminal (con source ~/ros2_ws/install/setup.bash).
  2. Lanza el nodo:

bash
ros2 run ros2_line_follower_camera line_follower_node \
--ros-args -p camera_topic:=/image_raw

  1. Comprueba que se crea el tópico /cmd_vel:

bash
ros2 topic list | grep cmd_vel

  1. Mide la frecuencia de publicación de /cmd_vel:

bash
ros2 topic hz /cmd_vel

Criterio de éxito: ≥ 10 Hz mientras haya imágenes entrantes.

  1. Coloca delante de la cámara una superficie blanca con una línea negra (cinta aislante). Asegúrate de que la línea cruza la parte inferior del campo de visión de la cámara.

  2. Cuando la línea esté centrada, espera ver que:

  3. linear.x ≈ valor del parámetro linear_speed (0.15).

  4. angular.z ≈ 0.

  5. Desplaza la línea hacia la izquierda/derecha; deberías observar:

  6. Si la línea se mueve hacia la derecha en la imagen (error positivo), angular.z será negativo (gira hacia la derecha, según la convención de tu robot).

  7. Si la línea se mueve hacia la izquierda, angular.z será positivo.

Puedes comprobarlo con:

bash
ros2 topic echo /cmd_vel

3. Validar en el UGV Beast en movimiento

  1. Coloca el UGV Beast en el suelo sobre una pista con línea negra sobre blanco (recta de al menos 2–3 m).
  2. Lanza los nodos:
  3. Cámara:

    bash
    ros2 run v4l2_camera v4l2_camera_node --ros-args -p video_device:=/dev/video0 -p image_size:="[640,480]"

  4. Seguidor de línea:

    bash
    ros2 run ros2_line_follower_camera line_follower_node \
    --ros-args -p camera_topic:=/image_raw -p linear_speed:=0.10 -p kp_angular:=0.003

  5. Si el puente cmd_vel → motores está funcional (por diff_drive_controller o nodo propio), el robot empezará a moverse hacia adelante y ajustar su dirección.

  6. Criterios de validación medibles:

  7. El robot no se sale de la línea más de 5 cm lateralmente en la mayoría del recorrido.
  8. En curvas suaves, el robot desacelera el giro adecuadamente y no “zigzaguea” de manera extrema.
  9. El movimiento responde en menos de 0.3 s al mover la línea manualmente.

Troubleshooting (errores típicos y soluciones)

1. No aparece /dev/video0

Síntoma: ls /dev/video* no muestra /dev/video0.

Causas y soluciones:
– La cámara no está bien conectada:
– Apaga la Pi, revisa el cable plano FPC, verifica orientación y que la pestaña CSI está bien fijada.
– Configuración en config.txt incorrecta:
– Asegúrate de tener:

```text
start_x=1
gpu_mem=128
dtoverlay=ov5647   # o el recomendado por Arducam para OV5647
```
  • Reinicia después de modificarlo.
  • Firmware/overlay no soporta esa cámara:
  • Revisa la documentación de Arducam 5MP OV5647 para Ubuntu 22.04 en Raspberry Pi 4; puede requerir un overlay distinto o actualización de firmware.

2. line_follower_node falla al convertir la imagen

Síntoma: En la consola, mensajes: Error al convertir imagen.

Causas y soluciones:
– Tipo de codificación no soportado:
– Asegúrate de que el nodo de cámara publica en un formato compatible (bgr8 o convertible).
– Con ros2 topic echo /image_raw -n 1, revisa el campo encoding.
– Si es yuyv o similar, modifica:

```python
frame = self.bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8')
```

por

```python
frame = self.bridge.imgmsg_to_cv2(msg)
```

y prueba.

3. Proceso de detección no encuentra contornos

Síntoma: El robot se mantiene parado con alertas Robot detenido: No se encontraron contornos para la línea.

Causas y soluciones:
– Contraste insuficiente entre línea y fondo:
– Usa fondo blanco brillante (cartulina) y cinta negra muy oscura.
– Aumenta iluminación.
– Umbral inadecuado:
– En lugar de umbral automático OTSU, prueba con un valor fijo:

```python
_, binary = cv2.threshold(blur, 100, 255, cv2.THRESH_BINARY_INV)
```
  • Ajusta 100 a tu entorno.
  • La línea está fuera de la región de interés:
  • Cambia view_height_ratio (por ejemplo, 0.5 para usar media imagen).

4. El robot oscila mucho (zigzag)

Síntoma: El UGV empeora la trayectoria, corrigiendo en exceso la dirección.

Causas y soluciones:
– Ganancia kp_angular demasiado alta:
– Reduce el valor: por ejemplo, de 0.003 a 0.0015.
– Velocidad lineal demasiado alta:
– Baja linear_speed a 0.08 o 0.05 m/s para principiantes.
– Retardo elevado de cámara:
– Reduce resolución (image_size:="[320,240]") para aumentar FPS.

5. Tópico /cmd_vel no llega al controlador de motores

Síntoma: Ves datos en /cmd_vel pero las ruedas no se mueven.

Causas y soluciones:
diff_drive_controller no está configurado:
– Asegúrate de haber creado y lanzado un controller_manager con diff_drive_controller.
– Puente hardware no implementado:
– Este caso práctico no entra al detalle de GPIO/PWM; necesitás un nodo que subscribe /cmd_vel y maneje los pines o que tu placa Beast haga de interfaz.
– Espacio de nombres (namespace) diferente:
– Verifica que tu controlador espera /cmd_vel y no otro tópico como /diff_drive_controller/cmd_vel_unstamped.

6. ros2 topic hz /image_raw muestra tasas muy bajas (≤ 5 Hz)

Síntoma: La cámara publica a muy baja frecuencia, el robot reacciona tarde.

Causas y soluciones:
– Resolución demasiado alta:
– Reduce image_size a [320,240] en v4l2_camera.
– Exceso de carga de CPU:
– Verifica con top que no haya otros procesos pesados.
– Desactiva nodos innecesarios durante pruebas.

7. Error al construir el workspace con colcon

Síntoma: colcon build falla en ros2_line_follower_camera con errores de dependencias.

Causas y soluciones:
– Falta alguna dependencia en package.xml:
– Asegúrate de incluir rclpy, sensor_msgs, geometry_msgs, cv_bridge.
– No instalaste ros-humble-cv-bridge o python3-opencv:
– Instálalos con:

```bash
sudo apt install -y ros-humble-cv-bridge python3-opencv
```
  • No ejecutaste source /opt/ros/humble/setup.bash antes de compilar:
  • Asegúrate de que lo tienes en el .bashrc.

Mejoras y variantes

Una vez tengas el caso básico funcionando, puedes plantear las siguientes mejoras:

  1. Control más avanzado (PID)
    En lugar de sólo control proporcional (kp_angular), añade términos integral y derivativo para suavizar y anticipar correcciones.

  2. Cálculo de la línea como recta
    En vez de usar solo el centroide del contorno, usa técnicas como:

  3. Ajuste de línea (regresión) a partir de puntos de la línea.
  4. Hough transform para detectar segmentos.

  5. Seguimiento de intersecciones
    Extiende el algoritmo para reconocer cruces en T o intersecciones y tomar decisiones:

  6. Girar a la izquierda o derecha según bandera.
  7. Parar en un cruce y esperar orden externa (ej. topic de alto nivel).

  8. Integrar con Nav2 y SLAM
    Aunque aquí sólo usamos la línea, tu UGV Beast puede:

  9. Mapear el entorno con slam_toolbox.
  10. Usar nav2 para navegación global cuando no haya línea.
  11. Combinar modos “seguimiento de línea” y “navegación libre”.

  12. Publicar imágenes procesadas
    Crea un tópico /line_follower/debug_image para ver por RViz o herramientas de visualización la binarización y contornos, ayudando a depurar.

  13. Parámetros dinámicos
    Usa parámetros ROS 2 dinámicos para ajustar kp_angular, linear_speed y view_height_ratio en tiempo real sin reiniciar el nodo.


Checklist de verificación (para el alumno)

Marca cada ítem al completarlo:

  • [ ] Ubuntu Server 22.04 64‑bit instalado y actualizado en Raspberry Pi 4 Model B 4GB.
  • [ ] ROS 2 Humble y paquetes (ros-humble-desktop, ros-humble-ros2-control, ros-humble-diff-drive-controller, ros-humble-robot-localization, ros-humble-slam-toolbox, ros-humble-nav2-*, ros-humble-rviz2) instalados con apt.
  • [ ] Cámara Arducam 5MP OV5647 Camera Module conectada al puerto CSI y habilitada en /boot/firmware/config.txt.
  • [ ] /dev/video0 visible tras el arranque de la Raspberry Pi.
  • [ ] Nodo v4l2_camera funcionando y publicando en /image_raw a ≥ 15 Hz (ros2 topic hz /image_raw).
  • [ ] Workspace ~/ros2_ws creado, con paquete ros2_line_follower_camera y dependencias instaladas (cv_bridge, python3-opencv).
  • [ ] colcon build se ejecuta sin errores y source ~/ros2_ws/install/setup.bash está en .bashrc.
  • [ ] Nodo line_follower_node se ejecuta correctamente y crea el tópico /cmd_vel.
  • [ ] Con la línea negra en el campo de visión, /cmd_vel publica valores razonables de linear.x y angular.z.
  • [ ] El puente /cmd_vel → controlador de motores del UGV Beast funciona y las ruedas reaccionan.
  • [ ] En una pista de al menos 5 m, el UGV Beast sigue la línea sin desviarse más de ±5 cm la mayor parte del tiempo.

Si todos los ítems están marcados, has completado con éxito el caso práctico ros2-line-follower-camera para el UGV Beast (ROS 2) – Raspberry Pi 4 Model B 4GB + Arducam 5MP OV5647 Camera Module a nivel básico.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Qué tipo de robot se está construyendo en el proyecto?




Pregunta 2: ¿Cuál es el propósito principal del robot mencionado?




Pregunta 3: ¿Qué cámara se utiliza en el proyecto?




Pregunta 4: ¿Qué software se está utilizando para controlar el robot?




Pregunta 5: ¿Cuál es la frecuencia mínima a la que debe publicar comandos de velocidad?




Pregunta 6: ¿Qué se espera lograr en un circuito simple?




Pregunta 7: ¿Cuál es el objetivo de utilizar visión monocular en el robot?




Pregunta 8: ¿Qué carga de CPU se debe mantener por debajo en la Raspberry Pi 4?




Pregunta 9: ¿Cuál es el público objetivo del proyecto?




Pregunta 10: ¿Qué tipo de circuito se menciona como ejemplo para la prueba?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:
Scroll to Top