Contenido detallado
🧠 Qué es ROS 2 y por qué usarlo
Hasta la Ruta 3, el robot era uno o dos programas que escribías completos. Cuando se incorporan LiDAR, mapas, cámara y navegación, un solo programa se vuelve imposible de mantener. El ROS 2 (Robot Operating System 2) resuelve esto: cada tarea se convierte en un programa pequeño y todos intercambian datos por nombre, sin saber quién está del otro lado ni en qué computadora. A pesar de su nombre, no es un sistema operativo: funciona sobre Linux, como un conjunto de bibliotecas y herramientas.
🌱 ¿Eres nuevo aquí?
Middleware es el software «intermedio»: está entre tus programas y la red y se encarga de entregar los mensajes. En ROS 2, esa función la cumple DDS (Data Distribution Service), un estándar industrial que descubre automáticamente quién publica y quién se suscribe a cada dato. Un paquete es la unidad de código que instalas o escribes: un controlador de LiDAR, Nav2, tu robot.
Cómo leer: cada recuadro ámbar es un programa independiente (un nodo). Ninguno se comunica directamente con otro: todos se conectan a la franja cian. La navegación solicita «/scan» y lo recibe del controlador de LiDAR sin saber quién es. El recuadro punteado está en otra computadora de la red y participa de la misma manera.
✓ Usa ROS 2 cuando
- ✓El robot tiene LiDAR, mapas o navegación.
- ✓Hay más de una computadora (Pi, PC, ESP32) trabajando en conjunto.
- ✓Quieres simular antes de construir.
✗ No necesitas ROS 2 para
- ✗Un seguidor de línea o un rover que esquiva obstáculos (Rutas 1 y 2).
- ✗Un ESP32 por sí solo, sin una computadora cerca.
- ✗Un prototipo para un fin de semana con un solo sensor.
Por qué aprender
ROS 2 es el lenguaje común de la robótica de investigación y de buena parte de la industria. Al aprender lo básico, puedes usar gratis controladores de sensores, slam_toolbox para crear mapas y Nav2 para la navegación, en vez de escribirlo todo desde cero.
Conceptos clave
📅 Qué distro elegir: Lyrical o Jazzy
ROS 2 se publica en distribuciones (distros), con nombres de tortugas, una por año. Las de número par, que se publican en mayo, son LTS (soporte prolongado, cinco años) y corresponden a una versión LTS de Ubuntu. En octubre de 2026 hay dos buenas opciones: Lyrical Luth, publicada el 22/05/2026 para Ubuntu 26.04 y con soporte hasta mayo de 2031, y Jazzy Jalisco, la LTS anterior, para Ubuntu 24.04, con soporte hasta 2029 y más tutoriales y paquetes listos para usar.
Cómo leer: cada barra representa el período en el que la distro recibe correcciones. La línea cian indica el día de hoy. Humble (línea gris punteada) termina en menos de un año: no empieces con esa versión. Jazzy y Lyrical te servirán por años; cada una incluye Ubuntu y Gazebo de la misma pareja.
| Si tú... | Elige |
|---|---|
| vas a empezar desde cero hoy, en una PC nueva | Lyrical (Ubuntu 26.04, Gazebo Jetty) |
| sigues un tutorial, libro o robot que requiere Jazzy | Jazzy (Ubuntu 24.04, Gazebo Harmonic) |
| necesitas un paquete que aún no está disponible para Lyrical | Jazzy, o Lyrical en Docker para probar |
| tienes un proyecto antiguo en Humble | Planea migrar a Jazzy antes de mayo/2027 |
🌱 ¿Eres nuevo aquí?
En este curso, los comandos usan <distro> como parte variable: reemplázala por lyrical o jazzy, siempre en minúsculas. Ejemplo: source /opt/ros/jazzy/setup.bash. El resto del comando es igual en ambas.
Por qué aprender
La mayoría de los «no funciona» en ROS se deben a mezclas: un tutorial de una distro, un paquete de otra y Gazebo de una tercera. Elegir la distro al principio y mantener la combinación Ubuntu ↔ ROS ↔ Gazebo evita este tipo de fallas.
Conceptos clave
📦 Instalar (Ubuntu, Docker o Pi)
Hay tres opciones. En Ubuntu (en la PC o en una máquina virtual), instalas paquetes listos para usar y obtienes el mejor rendimiento en Gazebo. Con Docker, ejecutas un contenedor que ya incluye ROS, en cualquier Linux (y en Windows o macOS, aunque configurar las ventanas gráficas requiere más ajustes). En Raspberry Pi 5, lo más directo es instalar Ubuntu de la misma versión que la distro; en Raspberry Pi OS, usa Docker.
Paso a paso en Ubuntu
Comprueba Ubuntu
Lyrical requiere Ubuntu 26.04; Jazzy requiere 24.04. Compruébalo con lsb_release -a.
Agrega el repositorio de ROS
Sigue la sección «Setup Sources» de la página oficial de instalación de tu distro en docs.ros.org. Este paso cambia de vez en cuando; copia las instrucciones de ahí, no de tutoriales antiguos.
Instala y activa
Ejecuta el bloque de abajo. El paquete desktop incluye RViz2, ejemplos y herramientas; ros-dev-tools incluye colcon y rosdep.
Objetivo: instalar ROS 2 y dejarlo activado automáticamente en cada terminal nueva.
# después de configurar el repositorio desde la página oficial
sudo apt update && sudo apt upgrade -y
sudo apt install -y ros-<distro>-desktop ros-dev-tools
# activa ROS en cada terminal nueva
echo "source /opt/ros/<distro>/setup.bash" >> ~/.bashrc
source ~/.bashrc
# prueba: dos nodos de ejemplo, uno en cada terminal
ros2 run demo_nodes_cpp talker
ros2 run demo_nodes_py listener
Cómo verificar
- ✓talker imprime "Publishing: 'Hello World: 1'", "...: 2"; listener imprime "I heard: [Hello World: 1]".
- ✓printenv ROS_DISTRO muestra lyrical o jazzy.
- ✗¿«ros2: command not found»? Falta ejecutar source en esta terminal.
Opción rápida con Docker: la imagen oficial osrf/ros:<distro>-desktop ya incluye todo. Las opciones de DISPLAY permiten que el contenedor abra ventanas (RViz, turtlesim) en tu Linux. Revisa las etiquetas disponibles en Docker Hub antes de descargar.
# permite que el contenedor use la pantalla (ejecútalo una vez por sesión)
xhost +local:docker
docker run -it --rm --net=host \
-e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \
-v ~/ros2_ws:/root/ros2_ws \
osrf/ros:<distro>-desktop
# dentro del contenedor, ROS ya está activado:
ros2 run turtlesim turtlesim_node
Cómo verificar: abre una ventana azul con una tortuga en el centro. La carpeta ~/ros2_ws de tu PC aparece dentro del contenedor en /root/ros2_ws, así que el código que escribas no desaparece cuando se cierre el contenedor.
💡 ¿Y en Raspberry Pi 5?
Graba Ubuntu Server de la versión correspondiente (26.04 para Lyrical, 24.04 para Jazzy) con Raspberry Pi Imager e instala ros-<distro>-ros-base (sin las herramientas gráficas). Visualiza en la PC: RViz y Gazebo son demasiado pesados para la Pi. Si quieres conservar Raspberry Pi OS de la Ruta 3, usa la imagen ros:<distro>-ros-base en Docker.
Por qué aprender
Instalarlo correctamente una vez te ahorra horas después. Docker también es la solución para el aula: todos los estudiantes ejecutan exactamente la misma imagen, sin diferencias entre máquinas.
Conceptos clave
🔗 Nodos, tópicos, mensajes
Un nodo es un proceso que hace una cosa: leer el LiDAR, girar los motores, planificar la ruta. Los nodos se comunican por tópicos, canales con nombres como /cmd_vel o /scan. Quien envía es el publisher; quien recibe es el subscriber. Un tópico puede tener varios de cada lado. El contenido tiene un formato fijo; el mensaje: /cmd_vel usa geometry_msgs/msg/Twist, con velocidad lineal y angular.
🌱 ¿Eres nuevo aquí?
Twist es el mensaje de «quiero moverme así»: linear.x en metros por segundo (hacia adelante) y angular.z en radianes por segundo (girar; positivo es en sentido antihorario visto desde arriba). Un robot diferencial ignora los otros cuatro campos. QoS (calidad de servicio) es el acuerdo de entrega de cada tópico, como «guardar los últimos 10 mensajes».
Cómo leer: los rectángulos son nodos (programas); las cápsulas cian son tópicos (canales). La flecha sale de quien publica y llega a quien se suscribe. Observa que /scan tiene dos suscriptores: el mismo dato del láser alimenta el mapa y la pantalla sin ningún código adicional.
Objetivo: inspeccionar un grafo real con turtlesim. Abre tres terminales (todas con ROS activado).
# terminal 1: el simulador de la tortuga
ros2 run turtlesim turtlesim_node
# terminal 2: conduce con las flechas del teclado
ros2 run turtlesim turtle_teleop_key
# terminal 3: observa el grafo
ros2 node list
ros2 topic list -t
ros2 topic info /turtle1/cmd_vel
ros2 interface show geometry_msgs/msg/Twist
ros2 topic echo /turtle1/pose
# publica tú mismo: la tortuga se mueve en círculo
ros2 topic pub --rate 2 /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 1.0}, angular: {z: 0.8}}"
Cómo verificar
- ✓ros2 node list muestra /turtlesim e /teleop_turtle.
- ✓topic info dice «Publisher count: 1, Subscription count: 1» (2 publishers cuando topic pub esté en ejecución).
- ✓O echo imprime x, y y theta mientras cambian cuando la tortuga se mueve. Para ver el grafo dibujado, ejecuta rqt_graph.
Por qué aprender
Cuando el robot no se mueve, el primer paso siempre es el mismo: ros2 topic echo /cmd_vel. Si el comando llega, la falla está en el motor; si no llega, está en quien publica. Leer el grafo desde la terminal es la herramienta de diagnóstico más usada de toda la ruta.
Conceptos clave
🔁 Servicios, acciones y parámetros
El tópico es un flujo continuo, sin respuesta. Para los otros casos, ROS 2 tiene tres elementos más. Un servicio es una pregunta y respuesta rápida: «crea una tortuga aquí», «guarda el mapa». Una acción es una tarea prolongada con progreso y posibilidad de cancelarla: «ve a la cocina» (todo Nav2 funciona así). Un parámetro es un ajuste del nodo que cambias sin volver a compilar: velocidad máxima, nombre del puerto serial, color del fondo.
Cómo leer: las líneas verticales son los dos lados de la conversación, y el tiempo avanza hacia abajo. En el tópico, A solo envía. En el servicio, el cliente espera una única respuesta. En la acción, el servidor envía avances (línea discontinua) mientras trabaja y, al final, el resultado.
# servicio: crea una segunda tortuga
ros2 service list
ros2 service call /spawn turtlesim/srv/Spawn "{x: 2.0, y: 2.0, theta: 0.0, name: 'robo2'}"
# parámetro: cambia el color del fondo sin reiniciar
ros2 param list /turtlesim
ros2 param set /turtlesim background_r 150
# acción: gira hasta 90 grados (1,57 rad) y muestra el progreso
ros2 action list
ros2 action send_goal --feedback /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"
Cómo verificar: aparece una tortuga nueva en (2, 2); el fondo se vuelve violáceo; la terminal de la acción imprime varias líneas «Feedback: remaining: ...» y termina con «Goal finished with status: SUCCEEDED».
✓ Patrón correcto
- ✓Lectura de sensor y velocidad: tópico.
- ✓Activar un relé, guardar el mapa: servicio.
- ✓Ir a un punto, girar el brazo: acción.
✗ Solución improvisada común
- ✗Servicio que tarda 30 s (bloquea a quien lo llamó).
- ✗Tópico «/pronto» para simular una respuesta.
- ✗Constante en el código que debería ser un parámetro.
Por qué aprender
En el módulo 4.5 enviarás el robot hasta un punto mediante una acción de Nav2 y, en el 4.4, guardarás el mapa mediante un servicio. Reconocer el patrón hace que la documentación de estos paquetes sea fácil de entender.
Conceptos clave
🐍 Tu primer nodo en Python (rclpy) publicando y escuchando
Ahora escribes tus nodos. En Python, la biblioteca es rclpy. Cada nodo sigue el mismo patrón: inicia rclpy, crea un objeto Node, registra publishers, subscribers y timers, y entrega el control a spin, que espera eventos y llama a tus funciones. Vas a crear un paquete meu_robo con dos nodos: falante publica una frase dos veces por segundo; ouvinte recibe e imprime.
Cómo leer: el reloj (timer) del falante llama a publicar(), que envía una String al tópico. El ouvinte no pregunta nada: ROS llama a ao_receber() cada vez que llega un mensaje. Ese «tú no llamas, te llaman» es el callback.
Objetivo: crear el workspace y el paquete. El comando ros2 pkg create genera la estructura; después solo tienes que reemplazar los archivos por los bloques de abajo.
mkdir -p ~/ros2_ws/src && cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python --license MIT meu_robo --dependencies rclpy std_msgs
# crea los dos nodos dentro de la carpeta de código del paquete
touch meu_robo/meu_robo/falante.py meu_robo/meu_robo/ouvinte.py
# Nodo que publica una frase en el tópico /conversa dos veces por segundo
import rclpy
from rclpy.node import Node
from rclpy.executors import ExternalShutdownException
from std_msgs.msg import String
class Falante(Node):
def __init__(self):
super().__init__('falante')
self.pub = self.create_publisher(String, 'conversa', 10) # cola de 10 mensajes
self.contador = 0
self.timer = self.create_timer(0.5, self.publicar) # llama a publicar() cada 0,5 s
def publicar(self):
msg = String()
msg.data = f'¡Hola desde el robot #{self.contador}'
self.pub.publish(msg)
self.get_logger().info(f'Publicado: {msg.data}')
self.contador += 1
def main(args=None):
rclpy.init(args=args)
no = Falante()
try:
rclpy.spin(no)
except (KeyboardInterrupt, ExternalShutdownException):
pass
finally:
no.destroy_node()
rclpy.try_shutdown()
if __name__ == '__main__':
main()
# Nodo que se suscribe a /conversa e imprime cada mensaje recibido
import rclpy
from rclpy.node import Node
from rclpy.executors import ExternalShutdownException
from std_msgs.msg import String
class Ouvinte(Node):
def __init__(self):
super().__init__('ouvinte')
self.sub = self.create_subscription(String, 'conversa', self.ao_receber, 10)
def ao_receber(self, msg):
self.get_logger().info(f'Escuché: {msg.data}')
def main(args=None):
rclpy.init(args=args)
no = Ouvinte()
try:
rclpy.spin(no)
except (KeyboardInterrupt, ExternalShutdownException):
pass
finally:
no.destroy_node()
rclpy.try_shutdown()
if __name__ == '__main__':
main()
O setup.py indica a ROS qué comandos ofrece el paquete (los entry_points), e o package.xml enumera las dependencias. Reemplaza los dos archivos generados por las versiones mínimas de abajo.
from setuptools import find_packages, setup
package_name = 'meu_robo'
setup(
name=package_name,
version='0.1.0',
packages=find_packages(exclude=['test']),
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
],
install_requires=['setuptools'],
zip_safe=True,
maintainer='voce',
maintainer_email='voce@exemplo.com',
description='Primeros nodos del curso de robótica',
license='MIT',
entry_points={
'console_scripts': [
'falante = meu_robo.falante:main',
'ouvinte = meu_robo.ouvinte:main',
],
},
)
<?xml version="1.0"?>
<package format="3">
<name>meu_robo</name>
<version>0.1.0</version>
<description>Primeiros nos do curso de robotica</description>
<maintainer email="voce@exemplo.com">voce</maintainer>
<license>MIT</license>
<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<export>
<build_type>ament_python</build_type>
</export>
</package>
cd ~/ros2_ws
colcon build --symlink-install
source install/setup.bash
ros2 run meu_robo falante # terminal 1
ros2 run meu_robo ouvinte # terminal 2 (vuelve a ejecutar source en esa terminal)
Cómo verificar
- ✓colcon termina con "Summary: 1 package finished".
- ✓Terminal 1: "[falante]: Publicado: ¡Hola desde el robot #0", "#1"... Terminal 2: "[ouvinte]: Escuché: ¡Hola desde el robot #3".
- ✓En una tercera terminal, ros2 topic hz /conversa muestra cerca de 2 Hz.
- ✗¿"Package 'meu_robo' not found"? Te faltó ejecutar source install/setup.bash en esa terminal.
💡 Desafío
Cambia el falante para que publique geometry_msgs/msg/Twist en /turtle1/cmd_vel (agrega geometry_msgs a package.xml) y haz que la tortuga dibuje un cuadrado: avanza 2 s, gira 90 grados y repite. Eso es exactamente lo que hace un nodo de navegación con tu robot.
Por qué aprender
Este patrón (clase Node, publisher, subscriber, timer, spin) es la base de todos los nodos de la ruta: el que calcula la odometría en el 4.3 y el que envía el robot a un punto en el 4.5. Cambian los tipos de mensaje y la lógica del callback; la estructura es la misma.
Conceptos clave
✅ Resumen del módulo
Para profundizar
- Documentación de ROS 2 Lyrical — instalación y tutoriales oficiales
- Documentación de ROS 2 Jazzy — la misma estructura para la LTS anterior
- Tutoriales de línea de comandos — nodos, tópicos, servicios, acciones y parámetros con turtlesim
- Imágenes osrf/ros en Docker Hub — consulta las etiquetas de cada distro
Siguiente módulo
4.2 · Describir y simular el robot: URDF, marcos TF, RViz2 y el robot en movimiento en Gazebo.