Entrando a picar más profundo en ROS

Si leyeron el artículo anterior, quizás les dieron ganas de profundizar más en ROS. Como el tutorial anterior era una introducción, no entré en tantos detalles. Ahora pretendo explicar más sobre los elementos fundamentales a entender cuando se trabaja con ROS.

Dentro de ROS existen ciertos conceptos clave que entender y algunas aplicaciones asociadas a estos elementos que nos harán la vida más sabrosa al trabajar. Dentro de esos elementos están los nodos, los tópicos, los servicios, los mensajes, el servidor de parámetros, y otros más. Más abajo iré explicándolos paso a paso y escribiendo las referencias oficiales de cada tema.

Logo ROS

ROS como un sistema distribuido

Como mencioné en el otro artículo, ROS es un framework distribuido. Su idea principal es que los robots son sistemas en los que una falla en un componente no debe dañar el funcionamiento de la máquina completa. Para esto, se pensó para funcionar implementado en programas con funciones puntuales, los nodos, que se comunican entre sí para obtener el funcionamiento completo del robot. Análogo a lo que en otros sistemas distribuidos hace la labor de coordinar el trabajo global, como el namenode en Hadoop, en ROS existe una aplicación que coordina la ejecución de todos los otros nodos: el roscore.

Roscore

El roscore [1] es un conjunto de herramientas necesarias para hacer funcionar los demás nodos de ROS. Es la primera aplicación que se debe ejecutar para que el resto funcione. Esta aplicación se encarga de llamar al nodo Master [2], que se encarga de hacer que los nodos se puedan encontrar unos a otros y de gestionar las llamadas a tópicos y servicios. También se encarga de llamar al servidor de parámetros [3], que se utiliza para almacenar variables que deben estar disponibles para todos los nodos mediante APIs. Por último, roscore abre un nodo que sirve como la salida estándar de ROS para generar logs e impresiones por consola que se publican en el tópico “/rosout”, el nodo rosout [4].

Para lanzar el roscore, basta llamarlo desde la consola y quedará funcionando. La mayoría de las aplicaciones incluidas al instalar ROS dependen de que el roscore esté funcionando.

roscore
... logging to /home/bruno/.ros/log/1976e978-2e49-11e5-aa44-b803058568da/roslaunch-cronidea-2483.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://cronidea:51918/
ros_comm version 1.11.13

SUMMARY
========

PARAMETERS
 * /rosdistro: indigo
 * /rosversion: 1.11.13

NODES

auto-starting new master
process[master]: started with pid [2497]
ROS_MASTER_URI=http://cronidea:11311/

setting /run_id to 1976e978-2e49-11e5-aa44-b803058568da
process[rosout-1]: started with pid [2510]
started core service [/rosout]

También existe otra forma de ejecutar aplicaciones, que es mediante roslaunch. Al ejecutar roslaunch, se ejecutará un archivo .launch que especifica mediante una notación XML una serie de parámetros y nodos a lanzar. Al usar roslaunch, si no está corriendo el roscore, se ejecuta automáticamente antes de ejecutar los contenidos del archivo .launch.

ROS también puede ejecutarse usando varias máquinas, de las que sólo una estará corriendo el roscore. Pero como aún no he trabajado con ROS en varias máquinas, prefiero hablar de eso cuando tenga más experiencia.

Paquetes y Nodos

Como ya mencioné varias veces, ROS está pensado para funcionar con programas puntuales llamados nodos [5]. Los nodos se organizan en paquetes (packages [6]) que generalmente incluyen varios nodos de funciones similares o complementarias. Los paquetes también se puede organizar en stacks, pero eso ya es irse por las ramas para el alcance de este tutorial. Lo habitual es que el sistema de un robot utilice distintos nodos para ejecutar las tareas necesarias. Por ejemplo, un nodo puede encargarse de recibir imágenes de la cámara y publicarlas en un tópico particular, otro nodo puede leer las imágenes desde ese tópico y aplicar algún proceso de detección de objetos. Otro nodo puede leer los resultados de la detección de objetos y planificar una ruta, mientras que otro nodo leerá la ruta y aplicará los comandos de movimiento que seguirán esa ruta.

Para ejecutar un nodo, se llama la instrucción rosrun seguida del nombre del paquete y el nombre del nodo. Por ejemplo, cuando en el tutorial anterior se ejecutó el simulador de tortuga, se llamó:

rosrun turtlesim turtlesim_node

y se comenzó a ejecutar el simulador.

También se pueden pasar argumentos a los nodos que se ejecuten, por ejemplo en el nodo “image_view” del paquete “image_view” que se encarga de mostrar imágenes, se puede especificar el tópico en el que se están publicando las imágenes usando la forma:

rosrun image_view image_view image:=/camera/image

Rosnode

Rosnode [7] es una herramienta para obtener información de los nodos en ejecución. Imaginemos que está funcionando el nodo del simulador de tortuga. Si ejecutamos “rosnode list” podemos ver la lista de nodos en ejecución. En este caso mostraría:

/rosout
/turtlesim

(Nótese que el nombre con el que se registra un nodo no es necesariamente el mismo nombre con el que se ejecuta el nodo)

Ahora podemos usar “rosnode info turtlesim” y obtener información sobre los tópicos a los que publica el nodo, a los que está suscrito y los servicios que tiene abiertos.

--------------------------------------------------------------------------------
Node [/turtlesim]
Publications:
 * /turtle1/color_sensor [turtlesim/Color]
 * /rosout [rosgraph_msgs/Log]
 * /turtle1/pose [turtlesim/Pose]

Subscriptions:
 * /turtle1/cmd_vel [unknown type]

Services:
 * /turtle1/teleport_absolute
 * /turtlesim/get_loggers
 * /turtlesim/set_logger_level
 * /reset
 * /spawn
 * /clear
 * /turtle1/set_pen
 * /turtle1/teleport_relative
 * /kill

contacting node http://cronidea:36697/ ...
Pid: 8877
Connections:
 * topic: /rosout
    * to: /rosout
    * direction: outbound
    * transport: TCPROS

Existen otras opciones más con las que se puede usar rosnode. Para verlas todas, basta con escribir “rosnode” en la terminal.

Tópicos

Dentro de un robot (o una simulación), son muchos los datos que fluyen de manera constante. Imágenes, datos de acelerómetros, nubes de puntos, estados de motores, necesitan estar siendo publicados continuamente para que el sistema funcione en tiempo real. Especificar canales de comunicación cada vez que un nodo quiere enviarle datos de este tipo a otro nodo no sería eficiente por varias razones: habría que saber de antemano desde donde y hasta donde hay que enviar los datos, hay que controlar la sincronía de los envíos… Para evitar estos problemas, ROS posee una forma de comunicación del estilo Publish/Subscribe [9] en el que un elemento envía mensajes (los publica) y otro elemento recibe mensajes (se suscribe a ellos). En ROS esto se hace a través de tópicos [8]. Los tópicos son un medio de comunicación pensado en la transmisión asíncrona de mensajes. Todos los datos que tengan que ser publicados constantemente y estar disponibles para que otros nodos se publican a través de tópicos.

Los nodos son quienes abren y leen tópicos. Para poder leer o publicar en un tópico, el mensaje entregado tiene que tener un cierto tipo. Existen tipos predefinidos para comunicar distintos datos, como el “geometry_msgs/Twist” que es el mensaje estándar para comandos de movimiento, y también se pueden definir tipos de mensajes de acuerdo a las necesidades de la aplicación.

Rostopic

Rostopic [10] es la herramienta para interactuar con los tópicos de ROS. Tiene funciones similares a las de “rosnode” y otras que son propias de la naturaleza de los tópicos. Una de las funciones más comunes es “rostopic list” que nos muestra la lista de los tópicos abiertos. En este caso la ejecuté habiendo lanzado el simulador de tortuga y me mostró lo siguiente:

/rosout
/rosout_agg
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

“rostopic info” puede mostrar información de un tópico en particular, por ejemplo “rostopic info /turtle1/cmd_vel” muestra:

Type: geometry_msgs/Twist

Publishers: None

Subscribers:
 * /turtlesim (http://cronidea:49932/)

Como sabemos que el tópico cmd_vel de la tortuga recibe comandos del tipo geometry_msgs/Twist (también podríamos haberlo sabido llamando directamente a “rostopic type /turtle1/cmd_vel”), podemos publicar un mensaje en este tópico para que la tortuga se mueva. Para publicar un mensaje usamos “rostopic pub”.
Escribimos:

rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '[2.0, 0.0, 0.0]' '[0.0, 0.0, 1.8]'

y verificamos que la tortuga del simulador se movió en la dirección indicada.

Figura 1: Tortuga moviéndose luego de un mensaje publicado en /turtle1/cmd_vel
Figura 1: Tortuga moviéndose luego de un mensaje publicado en /turtle1/cmd_vel

Para monitorear los mensajes publicados en un tópico, podemos usar “rostopic echo”. Antes de enviar el mensaje al simulador de la tortuga, ejecuté “rostopic echo /turtle1/cmd_vel” en una terminal y me mostró esto:

linear:
  x: 2.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 1.8
---

Existen varias opciones más con las que se puede ejecutar rostopic. Para verlas todas basta con escribir “rostopic” en la consola.

Servicios

Existe otra forma de comunicación en la que sólo en ciertas ocasiones necesitamos que se ejecute un procedimiento o necesitamos que la llamada venga acompañada de una respuesta. Esto en ciertos contextos se llama Remote Procedure Call o RPC, que permite que procesos intercambien información de manera directa. En ROS esta forma de comunicación se lleva a cabo mediante los servicios.

Los servicios se definen mediante un nombre y dos tipos de servicio: uno de consulta y otro de respuesta.

Rosservice

Una de las formas en las que se puede llamar un servicio es mediante rosservice. Imaginemos que estamos corriendo el simulador de tortuga y que queremos añadir una tortuga más a la simulación. Si ejecutamos “rosservice list” podemos ver que hay un servicio “/spawn” abierto.

/clear
/kill
/reset
/rosout/get_loggers
/rosout/set_logger_level
/spawn
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/get_loggers
/turtlesim/set_logger_level

Ejecutando “rosservice info /spawn” podemos ver información sobre este servicio:

Node: /turtlesim
URI: rosrpc://cronidea:59998
Type: turtlesim/Spawn
Args: x y theta name

Ahí se puede ver que este servicio requiere 4 argumentos para llamarse, así que para generar una nueva tortuga podemos escribir:

rosservice call /spawn 5 7 1.57 William

Y tendremos una nueva tortuga llamada William en la simulación.

Figura 2: William, “el musculoso”, ha entrado en escena

Ahora, si llamamos a “rosservice list” podemos ver que se han habilitado servicios nuevos:

/William/set_pen
/William/teleport_absolute
/William/teleport_relative
/clear
/kill
/reset
/rosout/get_loggers
/rosout/set_logger_level
/spawn
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/get_loggers
/turtlesim/set_logger_level

Podemos llamar a uno de ellos para cambiar la posición de William.

rosservice call /William/teleport_absolute 1 1 2.5

Y William juntará su Ki y se teletransportará.

Figura 3: William teletransportado
Figura 3: William teletransportado (It’s over 9000!)

Para ver todas las opciones de rosservice hay que llamarlo en la terminal.

Servidor de Parámetros

El servidor de parámetros es un espacio común para almacenar variables para todos los nodos. Es gestionado por el Master. Para ejemplificar el uso del servidor de parámetros es conveniente usar ejemplos más avanzados, por lo que los detalles pueden quedar para otra ocasión. Un ejemplo a grandes rasgos puede ser el lanzar un robot en simulación. Un robot se puede especificar en un archivo .xacro que es una sintaxis simplificada del estándar .urdf. Un nodo puede procesar el archivo .xacro y generar el .urdf correspondiente. Este archivo quedará en el servidor de parámetros, desde donde un nodo puede enviarlo al simulador. Así mismo en el servidor de parámetros se pueden guardar valores como por ejemplo las constantes PID del controlador de un motor.

Rosparam

Rosparam [12] es la herramienta estándar para interactuar con el servidor de parámetros desde la línea de comandos. Si llamamos a “rosparam list” vemos todos los parámetros almacenados. Al abrir el roscore se muestra algo así:

/rosdistro
/roslaunch/uris/host_cronidea__36626
/rosversion
/run_id

Lo mismo que antes: si queremos ver todas las opciones, escribimos rosparam en la consola.

Para ir cerrando

Así como para ir terminando el tutorial, estos son los elementos principales con los que se desarrollan las aplicaciones de ROS. Cuando se quieren desarrollar aplicaciones nuevas, generalmente el proceso consiste en implementar un paquete y programar sus nodos usando las bibliotecas disponibles de ROS (hasta donde sé, lo más común es trabajar con C++ y Python). Espero que a alguien le sea de utilidad este paseo por los elementos principales y que se motive a seguir aprendiendo. En tal caso, yo me motivaré a hacer más tutoriales.

Referencias

  1. Roscore: http://wiki.ros.org/roscore
  2. ROS Master: http://wiki.ros.org/Master
  3. ROS Parameter Server: http://wiki.ros.org/Parameter%20Server
  4. Rosout: http://wiki.ros.org/rosout
  5. ROS Nodes: http://wiki.ros.org/Nodes
  6. ROS Packages: http://wiki.ros.org/rosbuild/Packages
  7. Rosnode: http://wiki.ros.org/rosnode
  8. ROS Topics: http://wiki.ros.org/Topics
  9. Publish Subscribe Pattern: https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern
  10. Rostopic: http://wiki.ros.org/rostopic
  11. ROS Parameter Server: http://wiki.ros.org/Parameter%20Server
  12. Rosparam: http://wiki.ros.org/rosparam
Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s