Instalación y configuración de ROS (26 dic)
Cada versión de ROS soporta un máximo de tres versiones de ubuntu, por lo que conviene tener claro qué versión vamos a instalar. Para Ubuntu 12.10 debemos instalar ROS groovy.
Ubuntu 12.10
Instalación de ROS Groovy
Añadir los repositorios de ros-groovy para ubuntu 12.10 (a 12 dic 2012)
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu quantal main" > /etc/apt/sources.list.d/ros-latest.list' wget http://packages.ros.org/ros.key -O - | sudo apt-key add - sudo apt-get update sudo apt-get upgrade
Instalar con apt-get (todas las dependencias se instalan automáticamente).
sudo apt-get install ros-groovy-desktop-full
Instalar también otras herramientas que facilitan el trabajo con ROS.
sudo apt-get install python-rosinstall python-rosdep
Configuración de ROS Groovy
Configuración inicial:
sudo rosdep init rosdep update source /opt/ros/groovy/setup.bash
Creamos nuestro espacio de trabajo (se recomienda para no ensuciar la instalación base)
cd /opt/ros mkdir rosws sudo chmod -R 775 /opt/ros/rosws sudo chown user:user /opt/ros/rosws rosws init /opt/ros/rosws /opt/ros/groovy
Añadimos el script de configuración al bashrc
echo "source /opt/ros/rosws/setup.bash" >> ~/.bashrc . ~/.bashrc
Instalación de stacks desde repositorios
Para instalar cualquier stack desde repositorios:
roscd roslocate info STACKNAME | rosws merge - source setup.sh rosws update STACKNAME rosmake STACKNAME
Un ejemplo de instalación del stack ROSARIA. Este stack es un wrapper de ARIA para ROS que nos permite acceder al sonar y odometría de todos los robots de MobileRobots/ActivMedia.
roscd roslocate info ROSARIA | rosws merge - source setup.sh rosws update ROSARIA rosmake ROSARIA
Tutoriales de ROS
Crear un paquete ROS
En este tutorial mostraremos cómo crear un paquete de software para ROS. A modo de ejemplo, crearemos un paquete ficticio con un único nodo ROS, que se encargará de las siguientes tareas:
- Abrir un sensor ficticio.
- Leer los datos que proporciona el sensor de forma periódica.
- Publicar los datos a través del sistema de intercambio de mensajes ROS. El programa que se encargue de esto recibirá el nombre de publisher.
Nuestro sensor ficticio proporcionará la posición 3D de un objeto y la marca temporal asociada a cada dato:
timestamp x y z
Antes de comenzar el tutorial, debemos descargarnos los fuentes que utilizaremos en el paquete sensorfakesources.zip
- SensorFake.cpp y SensorFake.h: librería de interacción con el sensor.
- SensorFake_Publisher.cpp: publisher.
Diseño del paquete ROS
Al tratarse de un paquete sencillo, proponemos un diseño que no complique en exceso ni la implementación ni el mantenimiento del mismo. Nuestro paquete constará de los siguientes archivos:
- Librería para el manejo del sensor. Proporcionará las funciones típicas: conexión, lectura, desconexión, etc. Debería ser totalmente independiente de ROS.
- Nodo ROS encargado de comunicarse con el sensor (a través de su librería) y transmitir los datos a través del sistema de mensajes ROS.
Para paquetes más complejos, se recomienda encarecidamente utilizar un diseño más adecuado.
Creación del paquete
Nos situamos en la carpeta donde queramos crear nuestro paquete. Por ejemplo:
${HOME}/ros
Creamos el paquete. El nombre del paquete será sensor_fake y dependerá de roscpp.
roscreate-pkg sensor_fake roscpp
La salida del comando debería ser algo como:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING: current working directory is not on ROS_PACKAGE_PATH! Please update your ROS_PACKAGE_PATH environment variable. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Created package directory /home/citius_robot/ros_pruebas/sensor_fake Created include directory /home/citius_robot/ros_pruebas/sensor_fake/include/sensor_fake Created cpp source directory /home/citius_robot/ros_pruebas/sensor_fake/src Created package file /home/citius_robot/ros_pruebas/sensor_fake/Makefile Created package file /home/citius_robot/ros_pruebas/sensor_fake/manifest.xml Created package file /home/citius_robot/ros_pruebas/sensor_fake/CMakeLists.txt Created package file /home/citius_robot/ros_pruebas/sensor_fake/mainpage.dox Please edit sensor_fake/manifest.xml and mainpage.dox to finish creating your package
Esto nos indica: 1) que el paquete creado no está en la variable de entorno ROS_PACKAGE_PATH (solución en la siguiente sección), 2) que se ha creado correctamente la estructura de directorios y ficheros de configuración del paquete.
Si nos desplazamos a la carpeta correspondiente (${HOME}/ros_pruebas/sensor_fake), observamos la estructura del paquete:
- include: directorio para ficheros “.h”.
- * sensor_fake: directorio para ficheros “.h” de la librería que se encarga de la interacción con el sensor.
- src: directorio para ficheros “.cpp”
- mainpage.dox: fichero para generacion de documentación con Doxygen.
- CMakeLists.txt: configuración de la compilación con CMake (enlace).
- manifest.xml: información sobre el paquete (enlace).
Añadiendo el paquete al workspace
Desde ${HOME}/ros, añadimos el paquete al workspace de ROS.
rosws set sensor_fake
Alternativamente, podemos ejecutar:
rosstack profile && rospack profile
Cerramos el terminal y lo abrimos de nuevo, para que se recarguen las variables de entorno correspondientes. A continuación, ejecutamos:
rospack profile
En este punto, ROS debería ser capaz de encontrar nuestro paquete. Lo comprobamos mediante:
rospack find sensor_fake
Comprobamos que todo funciona correctamente ejecutando una compilación de prueba:
rosmake sensor_fake
Cuya salida debería ser algo como:
[ rosmake ] rosmake starting... [ rosmake ] Packages requested are: ['sensor_fake'] [ rosmake ] Logging to directory /home/david/.ros/rosmake/rosmake_output-20121115-180018 [ rosmake ] Expanded args ['sensor_fake'] to: ['sensor_fake'] [rosmake-0] Starting >>> roslang [ make ] [rosmake-0] Finished <<< roslang No Makefile in package roslang [rosmake-0] Starting >>> roscpp [ make ] [rosmake-0] Finished <<< roscpp No Makefile in package roscpp [rosmake-0] Starting >>> sensor_fake [ make ] [rosmake-0] Finished <<< sensor_fake [PASS] [ 5.56 seconds ] [ rosmake ] Results: [ rosmake ] Built 3 packages with 0 failures. [ rosmake ] Summary output to directory [ rosmake ] /home/david/.ros/rosmake/rosmake_output-20121115-180018
Importación a Eclipse
Si queremos importar este paquete a un proyecto Eclipse, podemos seguir las instrucciones que se encuentran en: http://www.ros.org/wiki/IDEs#Eclipse
Compilación de la librería para interacción con sensor_fake
En primer lugar, copiamos el archivo SensorFake.cpp en ${HOME}/ros/sensor_fake/src y el archivo SensorFake.h en ${HOME}/ros/sensor_fake/include/sensor_fake (fuentes: sensorfakesources.zip). A continuación, modificamos el CMakeLists.txt para que los compile como una librería dinámica.
#common commands for building c++ executables and libraries -> Añadimos el comando debajo de este comentario rosbuild_add_library(${PROJECT_NAME} src/SensorFake.cpp) #Esto indica que queremos compilar SensorFake.cpp como una librería dinámica. Esta librería tendrá el mismo nombre que el proyecto # (sensor_fake)
Compilamos:
rosmake sensor_fake
Nota importante: SensorFake.cpp asume que el SensorFake.h está en include/sensor_fake, al hacer:
#include "sensor_fake/SensorFake.h"
De no se así (por ejemplo, si le hemos dado otro nombre al paquete), debemos modificar este include.
Si la compilación es satisfactoria, rosmake nos habrá creado una nueva carpeta ${HOME}/ros/sensor_fake/lib, que contendrá la librería compilada libsensor_fake.so.
Definición de los mensajes ROS
Ahora debemos definir los mensajes que nuestro paquete va a utilizar para comunicarse con ROS. Para ello, creamos la carpeta ${HOME}/ros/sensor_fake/msg y copiamos en ella el archivo de definición del mensaje (XYZ.msg). A continuación, modificamos el archivo CMakeLists.txt para que compile la definición del mensaje.
#uncomment if you have defined messages rosbuild_genmsg() #---> Descomentamos esta línea
Compilamos:
rosmake sensor_fake
Si la compilación es correcta, rosmake habrá creado dos nuevas carpetas: 1) ${HOME}/ros/sensor_fake/msg_gen y 2) ${HOME}/ros/sensor_fake/src/sensor_fake/. Estas carpetas contienen las clases necesarias para el manejo del mensaje generado.
Compilación del //publisher//
Ahora estamos en disposición de escribir un programa que lea los datos de nuestro sensor_fake y los publique en ROS (utilizando el tipo de mensaje generado en el apartado anterior). En primer lugar, copiamos el archivo SensorFake_Publisher.cpp en ${HOME}/ros/sensor_fake/src (fuentes: sensorfakesources.zip). A continuación, modificamos el CMakeLists.txt para enlazar la librería {HOME}/ros/sensor_fake/lib/libsensor_fake.so y compilar el publisher como ejecutable.
#common commands for building c++ executables and libraries ## -> Ya estaba! rosbuild_add_library(${PROJECT_NAME} src/SensorFake.cpp) ## -> Ya estaba! rosbuild_add_executable(SensorFake_Publisher src/SensorFake_Publisher.cpp) target_link_libraries(SensorFake_Publisher ${PROJECT_NAME})
Si la compilación es satisfactoria, rosmake habrá creado el ejecutable ${HOME}/ros/sensor_fake/bin/SensorFake_Publisher.
Ejecución del nodo ROS
Finalmente, probamos nuestro paquete. Para ello, abrimos un terminal y ejecutamos el servidor ROS:
roscore
En otro terminal, ejecutamos nuestro publisher (nodo ROS):
rosrun sensor_fake SensorFake_Publisher
La salida debería ser algo como:
Hello, I am the SensorFake_Publisher Time 1353001026.799379: Sending x [0] y [5] z [10] Time 1353001026.899426: Sending x [1] y [6] z [11] Time 1353001026.999419: Sending x [2] y [7] z [12]
En otro terminal, ejecutamos un listener de ROS, que recibirá los mensajes de nuestro publisher y los mostrará por pantalla.
rostopic echo /SensorFake_Topic
La salida debería ser algo como:
header: seq: 31 stamp: secs: 1353001134 nsecs: 532552707 frame_id: '' timestamp: secs: 1353001134 nsecs: 532516000 x: 1 y: 6 z: 11 --- header: seq: 32 stamp: secs: 1353001134 nsecs: 632531208 frame_id: '' timestamp: secs: 1353001134 nsecs: 632489000 x: 2 y: 7 z: 12 ---
Compartir el paquete
Si queremos compartir el paquete (por ejemplo, enviarlo por email), debemos borrar la carpeta ${HOME}/ros/sensor_fake/build. En el ordenador destino, copiamos el paquete (por ejemplo, en ${HOME}/ros) y ejecutamos los pasos de la Sección “Añadiendo el paquete al workspace”.
Stage + AMCL + RVIZ
En este tutorial veremos:
- Cómo simular un robot con Stage.
- Cómo ejecutar el algoritmo de localización AMCL. Este algoritmo estimará la posición del robot sobre un mapa en base a la información del simulador.
- Cómo visualizar todos los datos con el rviz.
Para ello, necesitamos instalar:
- Stack Stage: sudo apt-get install ros-groovy-stage
- Nodos AMCL y map_server(stack Navigation): sudo apt-get install ros-groovy-navigation
- Nodo rviz: sudo apt-get install ros-groovy-rviz
Archivos de configuración
En primer lugar, debemos descargar el archivo world.zip. Podemos descomprimir este archivo en cualquier lugar a nuestro gusto (en adelante, llamaremos ${WORLD_PATH} a esta carpeta). En particular, nos van a interesar los siguientes archivos:
- ${WORLD_PATH}/citius/plantabajacitius.yaml: archivo descriptor del mapa que utilizaremos en este tutorial.
- ${WORLD_PATH}/citius/plantabajacitius.pgm: imagen que representa dicho mapa.
- ${WORLD_PATH}/citius/plantabajacitius.world: archivo “world” del Stage (utiliza el archivo plantabajacitius.pgm).
A continuación, descargamos el archivo amcl_diff_stage.launch.zip y lo extraemos en la carpeta “examples” del nodo AMCL. Para localizar la carpeta del nodo AMCL, hacemos:
roscd amcl
Este archivo contiene los parámetros que se le pasarán al AMCL. Podemos modificar los parámetros editando el archivo.
Finalmente, descargamos el archivo stage_amcl.rviz.zip y lo extraemos en una carpeta a nuestro gusto (en adelante, ${RVIZ_CONFIG}). Este archivo contiene parámetros de configuración para adaptar el rviz (visualizador) a las necesidades de este ejemplo.
Ejecución de los nodos (uno por terminal)
Arrancamos el roscore:
roscore
Ejecutamos el simulador Stage con un archivo “world”. Por ejemplo:
rosrun stage stageros ${WORLD_PATH}/citius/plantabajacitius.world
Ejecutamos el map_server:
rosrun map_server map_server ${WORLD_PATH}/citius/plantabajacitius.yaml
Ejecutamos el AMCL con el archivo de configuración descargado:
roslaunch amcl amcl_diff_stage.launch
AMCL expone un servicio (global_localization) mediante el cual se puede activar el proceso de localización global del robot. En otro terminal, hacemos:
rosservice call /global_localization
Comprobamos con la herramienta rxgraph que todos los nodos están: 1) levantados, 2) comunicándose correctamente. A continuación, podemos visualizar el resultado de los diferentes nodos utilizando la herramienta rviz:
rosrun rviz rviz ${RVIZ_CONFIG}/stage_amcl.rviz
Ahora podemos mover el robot (pestaña teleop) por el entorno para que se localice.
Rosbag
Rosbag es una herramienta para grabar, reproducir y modificar logs con los mensajes que recibe el nodo roscore (pose, medidas del láser, transformaciones geométricas, etc.). En terminología ROS, a estos archivos de log se les conoce como bags.
Rosbag record
Rosbag play
Rosbag filter
Rosbag nos permite generar nuevos archivos bag a partir de un bag ya existente. Presentamos aquí algunos ejemplos:
Generar un bag que sólo contenga mensajes “/RosAria/pose”:
rosbag filter original.bag filtrado.bag 'topic == "/RosAria/pose"'
Generar un bag que sólo contenga mensajes “/RosAria/pose” y “/tf”:
rosbag filter original.bag filtrado.bag 'topic == "/RosAria/pose" or topic =="/tf"'
Generar un bag que contenga todos los mensajes excepto el “/RosAria/pose”:
rosbag filter original.bag filtrado.bag 'topic != "/RosAria/pose"'
Creación de un controlador básico
Descargar el siguiente paquete: basicsample.zip. Compilar y ejecutar.
Para probar el código con el Stage necesitamos hacer un re-mapping de los topics como si fuera el robot real:
<launch> <node pkg="stage" type="stageros" name="stage" output="screen" args="$(find stage)/world/citius/plantabajacitius.world">//RUTA AL ARCHIVO WORLD <remap from="/base_scan" to="/scan"/> <remap from="/odom" to="/RosAria/pose"/> <remap from="/base_laser_link" to="/laser"/> </node> <arg name="map_file" default="$(find stage)/world/citius/plantabajacitius.yaml" /> //RUTA AL MAPA <node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)" /> </launch>