Parte 3: Más Allá de los Fundamentos
Introducción¶
Ejercicios: 5
Tiempo Estimado de Finalización: 3 horas
Nivel de Dificultad: Intermedio
Objetivos¶
En esta parte del curso exploraremos algunos conceptos más avanzados de ROS, y examinaremos otro de los sensores a bordo de nuestro robot: el sensor LiDAR. A partir del trabajo que realizaste en la Parte 2, es posible que hayas comenzado a apreciar las limitaciones asociadas con el uso de datos de odometría como única señal de retroalimentación al intentar controlar la posición de un robot en su entorno. El sensor LiDAR puede proporcionar información adicional sobre el entorno, mejorando así el conocimiento y las capacidades del robot. Sin embargo, primero veremos cómo lanzar aplicaciones ROS de forma más eficiente con launch files, y cómo el comportamiento de los nodes puede modificarse dinámicamente usando parameters.
Resultados de Aprendizaje Esperados¶
Al finalizar esta sesión serás capaz de:
- Crear launch files para permitir la ejecución simultánea de múltiples ROS Nodes con
ros2 launch. - Usar parameters para influir en el comportamiento de los nodes en tiempo real, sin necesidad de reprogramarlos.
- Aprender sobre el sensor LiDAR del robot y las mediciones que se obtienen de él.
- Interpretar los datos
LaserScanque se publican en el topic/scany usar las herramientas existentes de ROS para visualizarlos. - Realizar análisis numérico sobre arreglos de datos (usando la librería Python
numpy) para procesar datosLaserScany usarlos en aplicaciones ROS. - Usar herramientas existentes de ROS para implementar SLAM y construir un mapa de un entorno.
Enlaces Rápidos¶
Ejercicios¶
- Ejercicio 1: Creando un Launch File
- Ejercicio 2: Usando parameters para cambiar el comportamiento del robot en tiempo real
- Ejercicio 3: Usando RViz para Visualizar Datos LaserScan
- Ejercicio 4: Construyendo una Función Callback para LaserScan
- Ejercicio 5: Construyendo un mapa de un entorno con SLAM
Recursos Adicionales¶
Primeros Pasos¶
Paso 1: Inicia tu Entorno ROS
Si aún no lo has hecho, inicia tu entorno ROS ahora:
- Sandbox del Laboratorio (Recomendado): inicia una sesión en rigsa.io — sin instalación local, acceso directo desde el navegador.
- Usando WSL-ROS2 en una computadora del laboratorio: sigue las instrucciones aquí para iniciarlo.
- Ejecutando WSL-ROS2 en tu propia máquina: inicia el Windows Terminal para acceder a una instancia de terminal WSL-ROS2.
- Usuarios de Docker: sigue los pasos correspondientes para iniciar una instancia de terminal con tu instalación local de ROS.
Ahora deberías tener acceso a una instancia de terminal Linux, a la cual nos referiremos como TERMINAL 1.
Paso 2: Restaura tu trabajo (SOLO para usuarios de escritorio administrado con WSL-ROS2)
Recuerda que cualquier trabajo que realices dentro del entorno WSL-ROS2 no se preservará entre sesiones ni entre diferentes computadoras del laboratorio. Al final de la Parte 2 deberías haber ejecutado la herramienta wsl_ros para respaldar tu directorio de inicio en tu unidad U:\. Una vez que WSL-ROS2 esté en funcionamiento, se te pedirá que lo restaures:
It looks like you already have a backup from a previous session:
U:\wsl-ros\ros2-backup-XXX.tar.gz
Do you want to restore this now? [y/n]
Ingresa Y+Enter para restaurar tu trabajo de la sesión anterior. También puedes restaurar tu trabajo en cualquier momento usando el siguiente comando:
Paso 3: Inicia VS Code
También conviene iniciar VS Code ahora, para que esté listo cuando lo necesites más adelante.
Usuarios de WSL...
Es importante iniciar VS Code dentro de tu entorno ROS usando la extensión "WSL". Recuerda siempre verificar esto:
Paso 4: Asegúrate de que el Repositorio del Curso esté Actualizado
En la Parte 1 deberías haber descargado e instalado el Repositorio del Curso en tu entorno ROS. Esperamos que ya lo hayas hecho, pero si no es así, regresa y hazlo ahora (lo necesitarás para algunos ejercicios aquí). Si ya lo hiciste, vale la pena asegurarte de que esté actualizado, así que ejecuta el siguiente comando ahora:
Luego ejecuta colcon build
Y finalmente, recarga tu entorno:
Recuerda
Si tienes otras instancias de terminal abiertas, también deberás ejecutar source ~/.bashrc en ellas para que los cambios se propaguen correctamente.
Launch Files¶
Hasta ahora (en las Partes 1 y 2) hemos usado el comando ros2 run para ejecutar una variedad de ROS nodes, como teleop_keyboard, así como varios nodes que hemos creado nosotros mismos. También habrás notado que hemos usado el comando ros2 launch en algunas ocasiones, principalmente para lanzar simulaciones Gazebo de nuestro robot. Pero, ¿por qué tenemos estos dos comandos y cuál es la diferencia entre ellos?
Las aplicaciones ROS complejas típicamente requieren la ejecución de múltiples nodes al mismo tiempo. El comando ros2 run solo nos permite ejecutar un único node, lo que no es conveniente para aplicaciones complejas donde tendríamos que abrir múltiples terminales, usar ros2 run varias veces y asegurarnos de ejecutar todo en el orden correcto sin olvidar nada. ros2 launch, por otro lado, proporciona una forma de lanzar múltiples ROS nodes simultáneamente al definir exactamente lo que queremos lanzar dentro de los launch files. Esto hace que la ejecución de aplicaciones complejas sea más confiable, repetible y más fácil para que otros las lancen correctamente.
Ejercicio 1: Creando un Launch File¶
Para entender cómo funcionan los launch files, ¡vamos a crear algunos!
En la Parte 1 creamos los nodes publisher.py y subscriber.py que podían comunicarse entre sí a través de un topic llamado /my_topic. Los lanzamos de forma independiente usando el comando ros2 run en dos terminales separadas. ¿No sería conveniente poder lanzarlos ambos al mismo tiempo, desde la misma terminal?
Para empezar, vamos a crear otro nuevo package, esta vez llamado part3_beyond_basics.
-
En TERMINAL 1:
-
Ve a la carpeta
srcdel workspace de ROS 2: -
Clona el Plantilla de Package ROS 2:
-
Ejecuta el script
init_pkg.shdesde dentro de esta plantilla para inicializar un package con el nombre "part3_beyond_basics": -
Y navega hasta la raíz de este nuevo package usando
cd:
-
-
Los launch files deben ubicarse en un directorio
launchen la raíz del directorio del package, así que usamkdirpara crearlo: -
Usa el comando
cdpara entrar a la carpetalaunchque acabas de crear:...y luego usa el comando
touchpara crear un nuevo archivo vacío llamadopubsub.launch.py: -
Abre este launch file en VS Code e ingresa lo siguiente:
pubsub.launch.pyfrom launch import LaunchDescription # (1)! from launch_ros.actions import Node # (2)! def generate_launch_description(): # (3)! return LaunchDescription([ # (4)! Node( # (5)! package='part1_pubsub', # (6)! executable='publisher.py', # (7)! name='my_publisher' # (8)! ) ])- Todo lo que queremos ejecutar con un launch file debe estar encapsulado dentro de un
LaunchDescription, que se importa aquí desde el módulolaunch. - Para ejecutar un node desde un launch file necesitamos definirlo usando la clase
Nodedelaunch_ros.actions(¡no confundir con el método de comunicación ROS Action que se cubre en la Parte 5!). - Encapsulamos una Launch Description dentro de una función
generate_launch_description(). - Aquí definimos todo lo que queremos que ejecute este launch file: en este caso una lista Python
[]que contiene un único elementoNode()(por ahora). - Aquí describimos el node que queremos lanzar.
- El nombre del package al que pertenece el node.
- El nombre del node actual que queremos lanzar desde el package anterior.
-
Un nombre para registrar este node en la red ROS. Aunque esto también se define dentro del node mismo:
...podemos sobreescribirlo aquí con otro nombre.
- Todo lo que queremos ejecutar con un launch file debe estar encapsulado dentro de un
-
Necesitamos asegurarnos de informarle a
colconsobre nuestro nuevo directoriolaunch, para que pueda compilar los launch files dentro de él cuando ejecutemoscolcon build. Para esto, debemos agregar una instrucción de instalación de directorio alCMakeLists.txtde nuestro package:Abre el archivo
CMakeLists.txty agrega el siguiente texto justo arriba de la líneaament_package()al final del archivo: -
Ahora, compilemos el package usando el proceso de tres pasos que ya deberías ir conociendo bien...
-
Navega de regreso a la raíz del workspace de ROS 2:
-
Ejecuta
colcon buildsolo en tu nuevo package: -
Y finalmente, recarga el
.bashrc:
-
-
Usa
ros2 launchpara lanzar este archivo y probarlo tal como está: -
El código (tal como está) lanzará el node
publisher.pydel packagepart1_pubsub, pero no el nodesubscriber.py. Por lo tanto, necesitamos agregar otro objetoNode()a nuestraLaunchDescription:pubsub.launch.pyfrom launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( package='part1_pubsub', executable='publisher.py', name='my_publisher' ), Node( # TODO: define the subscriber.py node... ) ])Usando los mismos métodos anteriores, agrega las definiciones necesarias para el node
subscriber.pyen tu launch file. -
Una vez que hayas realizado estos cambios, necesitarás ejecutar
colcon buildnuevamente.Warning
Necesitarás ejecutar
colcon buildcada vez que realices cambios en un launch file, incluso si usas la opción--symlink-install(ya que esta solo aplica a los nodes en el directorioscripts) -
Una vez que hayas completado esto, debería ser posible lanzar tanto el publisher como el subscriber nodes (de tu package
part1_pubsub) conros2 launchy el archivopubsub.launch.py. Verifica esto en TERMINAL 1 ejecutando el launch file: -
Podemos verificar esto adicionalmente en una nueva terminal (TERMINAL 2), usando comandos que hemos usado en las Partes 1 y 2 para listar todos los nodes y topics activos en nuestra red ROS:
¿Ves lo que esperabas ver en la salida de estos dos comandos?
Launch Files: Avanzado
Para técnicas más avanzadas de launch files, consulta aquí!
Parameters¶
Los parameters se usan para configurar nodes, y también pueden usarse para cambiar su comportamiento dinámicamente durante la ejecución.
Ejercicio 2: Usando parameters para cambiar el comportamiento del robot en tiempo real¶
Pensemos de nuevo en nuestro node move_circle.py de la Parte 2 para ver para qué podría usarse esto. El node que construimos originalmente haría que un robot se moviera en un círculo de 0.5 metros de radio, ¡indefinidamente! ¿No sería conveniente poder cambiar el radio del círculo mientras el node está en ejecución?
-
Cierra tu archivo
pubsub.launch.pyen TERMINAL 1 si aún está en ejecución. -
Ahora, crearemos una nueva versión del node
move_circle.pyde la Parte 2 con la que podemos experimentar. Primero, ve al directorioscriptsde tu packagepart3_beyond_basicsen TERMINAL 1: -
Crea un nuevo node llamado
param_circle.py:y dale permisos de ejecución:
-
Declara esto como un ejecutable del package abriendo el
CMakeLists.txtde tu package en VS Code y agregandoparam_circle.pycomo se muestra a continuación: -
Recompila tu package con
colcon(aunqueparam_circle.pytodavía esté vacío en este punto):-
Primero:
-
Luego:
-
Y finalmente:
-
-
Después de haber completado los Ejercicios 4 y 5 de la Parte 2, deberías tener un node
move_circle.pyfuncional con un procedimiento de apagado adecuado. Copia el código y pégalo en tu nuevo archivoparam_circle.py. Alternativamente, si no lograste terminar esos ejercicios anteriormente, puedes acceder a un ejemplo resuelto aquí. -
Ahora, modifiquemos el código:
-
Primero, en el método
__init__(), cambia el nombre del node:Al lanzarse, el node quedará registrado en la red ROS con el nombre
"param_circle". -
Luego, directamente debajo de esto (aún dentro del método
__init__()), agrega las siguientes líneas nuevas:Aquí estamos declarando un ROS parameter llamado
radiusy asignándole un valor predeterminado de0.5, para representar el radio deseado del círculo (en metros). -
En algún lugar del método
timer_callback(), deberías estar definiendo el radio deseado del círculo. Modifica esto de la siguiente manera:El radio del círculo en el que se moverá el robot ahora se basa en el valor del parameter
radius, en lugar de un valor estático. -
Finalmente, modifica tu declaración
get_logger().info()(al final del métodotimer_callback()) para incluir información sobre el radio objetivo:
-
-
Para probar esto, primero inicia la simulación Empty World en TERMINAL 1:
-
Luego, en TERMINAL 2, ejecuta el node
param_circle.py:El robot debería comenzar a moverse en un círculo. Al principio, el radio de este círculo debería ser de 0.5 metros, basado en el valor predeterminado que asignamos al parameter en nuestro código.
-
A continuación, abre otra instancia de terminal (TERMINAL 3) y ejecuta el siguiente comando para listar todos los parameters que están activos/disponibles actualmente en nuestra red ROS:
Esta puede ser una lista bastante extensa. Los parameters se listan bajo los nodes que los definen, así que para filtrar la lista, proporciona también el nombre del node:
Ahora debería haber solo un pequeño número de parameters listados, incluyendo
radius. -
Ahora podemos cambiar el valor de este parameter mientras nuestro node
param_circle.pyestá en ejecución, y por lo tanto cambiar el tamaño del círculo que el robot está siguiendo actualmente. Podemos hacer esto desde la línea de comandos, sin tener que detener nuestro nodeparam_circle.pyni realizar ningún cambio en él. Nuevamente, en TERMINAL 3:¡Prueba establecer una variedad de valores diferentes y observa cómo cambia el comportamiento del robot en el mundo simulado!
-
Una vez que hayas terminado, cierra el node
param_circle.pyy la simulación Gazebo ingresando Ctrl+C en los terminales 1 y 2 respectivamente.
Resumen¶
Los parameters nos permiten cambiar el comportamiento de las cosas durante la ejecución. También exploraremos otros usos para ellos en la siguiente parte de este curso (Parte 4).
También hemos aprendido algunas técnicas clave de launch files, así que avancemos hacia otro tema más avanzado y muy importante...
Datos de Desplazamiento Láser y el Sensor LiDAR¶
Como recordarás de la Parte 2, la odometría es muy importante para la navegación de robots, pero puede estar sujeta a deriva y error acumulado a lo largo del tiempo. Es posible que hayas observado esto en la simulación durante el Ejercicio 5 de la Parte 2, y definitivamente lo notarías si hicieras lo mismo en un robot real. Afortunadamente, el robot de simulación tiene otro sensor a bordo que proporciona información aún más rica sobre el entorno, y podemos usarlo para complementar la información de odometría y mejorar las capacidades de navegación del robot.
Introduciendo la Interfaz LaserScan¶
Ejercicio 3: Usando RViz para Visualizar Datos LaserScan¶
Ahora vamos a colocar el robot en un entorno más interesante que el "empty world" con el que hemos estado trabajando hasta ahora...
-
En TERMINAL 1 ingresa el siguiente comando para lanzarlo:
Ahora debería lanzarse una simulación Gazebo con el robot de simulación en un nuevo entorno:
-
En TERMINAL 2 ingresa lo siguiente:
Al ejecutar el comando debería abrirse una nueva ventana:
Esto es RViz, una herramienta de ROS que nos permite visualizar los datos que está midiendo un robot en tiempo real.
Los puntos verdes dispersos alrededor del robot representan datos de desplazamiento láser medidos por el sensor LiDAR ubicado en la parte superior del robot, lo que le permite medir la distancia a cualquier obstáculo en sus alrededores.
El sensor LiDAR gira continuamente, emitiendo pulsos láser mientras lo hace. Estos pulsos láser son reflejados por los objetos y devueltos al sensor. La distancia puede determinarse entonces basándose en el tiempo que tardan los pulsos en completar el recorrido completo (desde el sensor, al objeto, y de regreso), mediante un proceso llamado "tiempo de vuelo" (time of flight). Dado que el sensor LiDAR gira y realiza este proceso continuamente, se puede generar un escaneo completo de 360° del entorno.
En este caso (ya que estamos trabajando en simulación) los datos representan los objetos que rodean al robot en su entorno simulado, así que deberías notar que los puntos verdes producen un contorno que se parece a los objetos del mundo que se está simulando en Gazebo (o al menos parcialmente).
-
Los datos de desplazamiento láser del sensor LiDAR son publicados por el robot en el topic
/scan. Podemos usar el comandoros2 topic infopara obtener más información sobre los nodes que publican y se suscriben a este topic, así como el tipo de interfaz utilizado para transmitir los datos de este topic. En TERMINAL 3 ingresa lo siguiente: -
Como podemos ver arriba, los datos del topic
/scanson del tiposensor_msgs/msg/LaserScan, y podemos obtener más información sobre esta interfaz usando el comandoros2 interface show:# Single scan from a planar laser range-finder std_msgs/Header header # timestamp in the header is the acquisition time of builtin_interfaces/Time stamp int32 sec uint32 nanosec string frame_id # the first ray in the scan. # # in frame frame_id, angles are measured around # the positive Z axis (counterclockwise, if Z is up) # with zero angle being forward along the x axis float32 angle_min # start angle of the scan [rad] float32 angle_max # end angle of the scan [rad] float32 angle_increment # angular distance between measurements [rad] float32 time_increment # time between measurements [seconds] - if your scanner # is moving, this will be used in interpolating position # of 3d points float32 scan_time # time between scans [seconds] float32 range_min # minimum range value [m] float32 range_max # maximum range value [m] float32[] ranges # range data [m] # (Note: values < range_min or > range_max should be discarded) float32[] intensities # intensity data [device-specific units]. If your # device does not provide intensities, please leave # the array empty.
Interpretando los Datos LaserScan¶
La interfaz LaserScan es una interfaz de mensaje ROS estandarizada (del package sensor_msgs) que cualquier robot ROS puede usar para publicar los datos que obtiene de un sensor de desplazamiento láser como el LiDAR del robot de simulación.
ranges es un arreglo de valores float32 (los tipos de datos de arreglo tienen el sufijo []). Esta es la parte del mensaje que contiene todas las mediciones de distancia reales que está obteniendo el sensor LiDAR (en metros).
Considera un ejemplo simplificado aquí, tomado de un robot de simulación en un entorno diferente:
Como se ilustra en la figura, podemos asociar cada punto de datos del arreglo ranges a una posición angular usando los valores angle_min, angle_max y angle_increment que también se proporcionan dentro del mensaje LaserScan. Podemos usar el comando ros2 topic echo para averiguar cuáles son sus valores:
Question
¿Qué representan estos valores? (Compáralos con la figura anterior)
Tip
¿Notaste cómo pudimos acceder a variables específicas dentro de los datos del topic /scan usando el flag --field, y pedirle al comando que solo nos proporcionara un único mensaje usando --once?
El arreglo ranges contiene 360 valores en total, es decir, una medición de distancia cada 1° (un angle_increment de 0.0175 radianes) alrededor del robot. El primer valor del arreglo ranges (ranges[0]) es la distancia al objeto más cercano directamente frente al robot (es decir, en θ = 0 radianes, o angle_min). El último valor del arreglo ranges (ranges[359]) es la distancia al objeto más cercano a 359° (es decir, θ = 6.283 radianes, o angle_max) desde el frente del robot, es decir: 1 grado a la derecha del eje X. ranges[65], por ejemplo, representaría la distancia al objeto más cercano a un ángulo de 65° (1.138 radianes) desde el frente del robot (en sentido antihorario), como se muestra en la figura.
El mensaje LaserScan también contiene los parámetros range_min y range_max, que representan las distancias mínima y máxima (nuevamente, en metros) que puede detectar el sensor LiDAR, respectivamente. Usa el comando ros2 topic echo para reportar estos directamente también.
Preguntas
- ¿Cuál es el rango máximo y mínimo del sensor LiDAR? Usa la misma técnica que usamos anteriormente para averiguarlo.
-
Considera la nota junto a
rangesen la salida deros2 interface showanterior:(esto puede valer la pena tenerlo en cuenta).
Finalmente, usa el comando ros2 topic echo nuevamente para mostrar la porción ranges de los datos LaserScan. Hay mucha información aquí (¡360 puntos de datos por mensaje, como ya sabes!):
Ahora omitimos la opción --once, para poder ver los datos tal como llegan, en tiempo real. Es posible que necesites expandir la ventana del terminal para poder ver todos los puntos de datos; los datos estarán delimitados por corchetes [], y debería haber un --- al final de cada mensaje para ayudarte a confirmar que estás viendo el mensaje completo.
Lo principal que notarás aquí es que hay mucha información, ¡y cambia rápidamente! Sin embargo, como ya has visto, son los números que aparecen aquí los que están representados por los puntos verdes en RViz. Regresa a la pantalla de RViz para echar otro vistazo ahora. Como sin duda estarás de acuerdo, esta es una forma mucho más útil de visualizar los datos ranges, e ilustra cuán útil puede ser RViz para interpretar lo que tu robot puede ver en tiempo real.
También puedes notar varios valores inf dispersos por el arreglo. Estos representan lecturas del sensor que están fuera del rango de medición del sensor (es decir, mayores que range_max o menores que range_min), por lo que el sensor no puede reportar una medición de distancia en esos casos. Recuerda lo mencionado anteriormente:
Note
¡Este comportamiento es diferente en los robots reales! ¡Ten esto en cuenta cuando desarrolles código para robots reales!
Detén el comando ros2 topic echo en la ventana del terminal ingresando Ctrl+C en TERMINAL 3. También cierra el proceso RViz que se ejecuta en TERMINAL 2 ahora, pero deja la simulación (en TERMINAL 1) en funcionamiento.
Ejercicio 4: Construyendo una Función Callback para LaserScan¶
Los datos LaserScan nos presentan un nuevo desafío: procesar grandes conjuntos de datos. En este ejercicio veremos algunos enfoques básicos que se pueden tomar para trabajar con estos datos y obtener algo significativo que pueda usarse en tus aplicaciones robóticas.
-
En TERMINAL 2, navega a la carpeta
scriptsde tu packagepart3_beyond_basics: -
Crea un nuevo archivo llamado
lidar_subscriber.py(usandotouch), hazlo ejecutable (usandochmod) y luego decláralo como ejecutable del package en tu archivoCMakeLists.txt(si necesitas ayuda con alguno de estos pasos, consulta el ejercicio anterior). -
Abre el archivo en VS Code, luego consulta a continuación las instrucciones sobre cómo construirlo:
Construyendo un Subscriber para LaserScan -
Regresa al terminal y compila con
colcon: -
Con todo eso hecho, estás listo para comenzar. Ejecuta el node usando
ros2 run: -
Abre otra terminal (para que aún puedas ver las salidas de tu node
lidar_subscriber.py). Lanza el nodeteleop_keyboard, conduce el robot alrededor y observa cómo cambian las salidas de tu nodelidar_subscriber.pymientras lo haces. -
Cierra todo ahora (incluida la simulación en TERMINAL 1). Luego lanza la simulación "empty world" nuevamente:
-
Regresa a TERMINAL 2 y lanza tu node
lidar_subscriber.pynuevamente:¿Qué salida ves ahora?
Deberías notar que tu node
lidar_subscriber.pyreportanan metersahora. Esto se debe a que no hay nada en el entorno para que el sensor LiDAR detecte, por lo que todas las lecturas están fuera de rango y, por tanto, nuestro análisis del arco de 40° de lecturas LiDAR en la parte frontal del robot ha filtrado todo y por ello devuelvenan(no es un número). -
Usa la herramienta Box en Gazebo para colocar una caja en el entorno.
-
Haz clic en la herramienta Translate para mover la caja hasta que el node
lidar_subscriber.pydevuelva algunas lecturas que no seannan. -
Mueve la caja un poco más para observar qué puede detectar nuestro análisis de los datos
LaserScan, y dónde la caja queda fuera del rango detectable. -
Piensa en cómo podrías adaptar la función callback del node
lidar_subscriber.pypara que detecte más de un subconjunto deLaserScan, de modo que pueda detectar situaciones como esta (por ejemplo):
Localización y Mapeo Simultáneo (SLAM)¶
En conjunto, los datos del sensor LiDAR y la odometría del robot (específicamente la pose del robot) son muy poderosos, y permiten extraer conclusiones muy útiles sobre el entorno en el que opera un robot. Una de las aplicaciones clave de estos datos es la "Localización y Mapeo Simultáneo" (Simultaneous Localisation and Mapping), o SLAM. Esta es una herramienta integrada en ROS que permite a un robot construir un mapa de su entorno y localizarse dentro de ese mapa al mismo tiempo. ¡Ahora veremos cuán fácil es aprovechar esto en ROS!
Ejercicio 5: Construyendo un mapa de un entorno con SLAM¶
-
Cierra todos los procesos ROS que estén en ejecución ahora ingresando Ctrl+C en cada terminal.
-
Ahora vamos a lanzar nuestro robot en otro nuevo entorno simulado, ¡del cual crearemos un mapa usando SLAM! Para lanzar la simulación ingresa el siguiente comando en TERMINAL 1:
El entorno que se lanza debería verse así:
-
Ahora lanza SLAM para comenzar a construir un mapa de este entorno. En TERMINAL 2, lanza SLAM de la siguiente manera:
Esto lanzará RViz nuevamente, donde deberías ver una vista desde arriba de un entorno con un modelo del robot, rodeado de algunos puntos que representan los datos LiDAR en tiempo real.
SLAM ya ha comenzado a construir un mapa de los límites que actualmente son visibles para el robot, basándose en su posición inicial en el entorno.
Si dejas esto por un minuto, las paredes del espacio comenzarán a hacerse visibles en RViz, y el suelo comenzará a tornarse de un gris más claro. A medida que pase el tiempo, los algoritmos SLAM se volverán más seguros sobre lo que se está observando en el entorno, lo que permitirá definir los límites y el espacio libre.
-
En TERMINAL 3 lanza el node
teleop_keyboard(ya deberías saber cómo hacer esto). Reorganiza y redimensiona tus ventanas para que puedas ver Gazebo, RViz y las instancias de terminal delteleop_keyboardal mismo tiempo. -
Conduce el robot alrededor del espacio lentamente, usando el node
teleop_keyboard, y observa cómo el mapa se actualiza y expande constantemente en la ventana de RViz mientras lo haces. -
Mientras haces esto, abre otra instancia de terminal (TERMINAL 4) y ejecuta el node
odom_subscriber.pyque creaste en la Parte 2:Esto te proporcionará las coordenadas
XeYdel robot (en metros) dentro del entorno mientras lo conduces, y puedes usar esto para determinar las coordenadas del centro de los cuatro círculos (A, B, C y D) que están marcados en el suelo del espacio.Conduce tu robot hacia cada una de estas zonas circulares y detén el robot dentro de ellas.
Registra las coordenadas de cada marcador de zona en una tabla como la siguiente.
Zona Posición X (m) Posición Y (m) START 0.5 -0.04 A B C D -
Continúa conduciendo el robot hasta que se haya generado un mapa completo del entorno.
-
Una vez que hayas construido un mapa completo del entorno (y hayas obtenido las coordenadas de todos los círculos), puedes guardar tu mapa para usarlo más adelante. Para esto usamos el package
map_serverde ROS. Primero, detén el robot presionando S en TERMINAL 3 y luego ingresa Ctrl+C para cerrar el nodeteleop_keyboard. -
Luego, permaneciendo en TERMINAL 3, navega a la raíz del directorio de tu package
part3_beyond_basicsy crea una nueva carpeta llamadamaps: -
Navega hacia este nuevo directorio:
-
Luego, ejecuta el node
Reemplazandomap_saver_clidel packagemap_serverpara guardar una copia de tu mapa:MAP_NAMEcon un nombre de tu elección.Esto creará dos archivos: un archivo
MAP_NAME.pgmy un archivoMAP_NAME.yaml, ambos con datos relacionados al mapa que acabas de crear. El archivo.pgmcontiene un Mapa de Cuadrícula de Ocupación (Occupancy Grid Map, OGM), que se usa para la navegación autónoma en ROS. Observa el mapa lanzándolo en una aplicación de visualización de imágenes llamadaeog:Debería abrirse una nueva ventana con el mapa que acabas de crear con SLAM y el node
map_saver_cli:Las regiones blancas representan el área que tu robot ha determinado como espacio abierto en el que puede moverse libremente. Las regiones negras, por otro lado, representan límites u objetos que han sido detectados. Cualquier área gris en el mapa representa regiones que permanecen sin explorar o que eran inaccesibles para el robot.
-
Compara el mapa generado por SLAM con el entorno simulado real (en Gazebo).
Preguntas
- ¿Con qué precisión mapeó tu robot el entorno?
- ¿Qué podría afectar esto al trabajar en un entorno del mundo real?
-
Cierra la imagen usando el botón en el lado derecho de la ventana eog.
Resumen de SLAM¶
¿Ves qué fácil fue mapear un entorno en el ejercicio anterior? Esto funciona igual de bien en un robot real en un entorno real también (como observarás en el laboratorio).
Esto ilustra el poder de ROS: tener acceso a herramientas como SLAM, integradas en el framework ROS, hace que sea muy rápido y fácil para un ingeniero en robótica comenzar a desarrollar aplicaciones robóticas sobre esta base. Nuestro trabajo fue aún más fácil aquí ya que usamos algunos packages pre-configurados para ayudarnos a lanzar SLAM con las configuraciones correctas para el robot de simulación en particular. Si estuvieras desarrollando un robot por tu cuenta, o trabajando con un tipo diferente de robot, podrías necesitar hacer un poco más de trabajo para configurar y ajustar las herramientas SLAM para que funcionen con tu propia aplicación.
Conclusión¶
Como aprendimos en la Parte 2, la odometría de un robot se determina mediante la estimación por avance (dead-reckoning) y los algoritmos de control basados únicamente en esto (como el node move_square.py) pueden estar sujetos a deriva y error acumulado.
En última instancia, un robot necesita información adicional para determinar con precisión su ubicación dentro de un entorno, y así mejorar su capacidad para navegar de manera efectiva y evitar colisiones.
Esta información adicional puede provenir de un sensor LiDAR, del cual hablamos anteriormente. Exploramos dónde se publican estos datos, cómo accedemos a ellos y qué nos dicen sobre el entorno inmediato de un robot. Luego analizamos algunas formas en que los datos de odometría y desplazamiento láser pueden combinarse para realizar funciones robóticas avanzadas, como el mapeo de un entorno. Todo esto es complicado, pero usando ROS podemos aprovechar estas herramientas con relativa facilidad, lo que ilustra cuán poderoso puede ser ROS para desarrollar aplicaciones robóticas de manera rápida y efectiva, ¡sin tener que reinventar la rueda!
¡Guarda tu trabajo!¶
Sandbox del Laboratorio (rigsa.io)
Tu código se guarda en /home/student/ros2_ws/src dentro de la sesión.
Antes de cerrar la sesión, descárgalo para no perderlo:
- En VS Code, haz clic derecho sobre la carpeta
srcen el explorador de archivos → Descargar… - O desde la terminal integrada:
Luego descarga el archivo
mi_codigo_parte3.zipdesde el explorador de VS Code.
WSL-ROS2 (Computadoras del laboratorio con escritorio administrado)
Ejecuta el siguiente script en cualquier instancia de terminal WSL-ROS2 que no esté en uso:
Esto exportará tu directorio de inicio a tu unidad U:\, lo que te permitirá restaurarlo en otra computadora del laboratorio la próxima vez que inicies WSL-ROS2.