You are on page 1of 23

TUTORIALES ROS

INTRODUCCIN
ROS es un meta-sistema operativo para robots, es decir, una librera de cdigo que debe ser
instalada en un sistema operativo y que ser invocada desde un programa ejecutable. Entre sus ventajas
destaca que se abstrae del hardware, controla los dispositivos a bajo nivel, implementa las
funcionalidades ms comunes en el manejo de robots, intercambia mensajes entre procesos y es capaz
de administrar paquetes de cdigo. Tambin proporciona libreras y herramientas para obtener,
construir, escribir y ejecutar cdigo a travs de mltiples ordenadores.
ROS engloba una estructura o red del tipo p2p (peer to peer o puesto a puesto) donde los
procesos se comunican entre ellos usando la infraestructura de comunicaciones de ROS. Esta
comunicacin es sncrona cuando se utilizan servicios (comunicacin tipo peticin/respuesta). Es
asncrona cuando se usan topics o temas; un topic es un bus por donde circulan mensajes
intercambiados por nodos, que son pequeos programas que hacen tareas.
Para programar elementos ROS pueden usarse 3 lenguajes: c++, python y Lisp.

SISTEMAS DE FICHEROS ROS


En cuanto a sus archivos, ROS se compone de:
- Paquetes (packages): Un paquete puede contener nodos (procesos ejecutables), libreras,
conjuntos de datos (datasets), archivos de configuracin, etc.
- Manifiestos (manifests): son archivos con extensin .xml que proporcionan informacin
(metadatos), sobre todo de dependencias del paquete.
- Pilas (stacks): Son colecciones de paquetes.
- Manifiestos de Pila: Igual que los de paquetes.
- Tipos de Mensajes: Archivos con extensin .msg. Las descripciones de los mensajes estn
almacenadas en my_package/msg/MyMessageType.msg y describen la estructura de los mensajes
enviados en ROS
- Tipos de Servicios: Archivos con extensin .srv. Las descripciones de los servicios estn
almacenadas en my_package/srv/MyServiceType.srv y definen las peticiones y respuestas de las
estructuras de datos para los servicios en ROS.

ELEMENTOS DE COMPUTACIN DE ROS


- Nodos: Los nodos son procesos ejecutables. ROS est diseado para ser modular. Por
ejemplo, un robot tendr un nodo para controlar el lser, otro nodo para controlar los motores de
desplazamiento, otro nodo para calcular el camino correcto, etc Un nodo se programa utilizando una
librera cliente ROS, como por ejemplo roscpp o rospy, si se va a programar en c++ o pyhton
respectivamente.
- Maestro (master): asigna nombres a todos los elementos que conforman el modelo del robot.
Sin l, los nodos no se encontraran ni podran intercambiar mensajes entre ellos.
- Servidor de Parmetros: Forma parte del Maestro y permite almacenar datos por clave en
una localizacin centralizada.
- Mensajes: Los nodos los utilizan para comunicarse entre ellos. Los mensajes son simples
estructuras de datos compuestas por campos tipificados.
- Temas (topics): Son mensajes transportados mediante semntica de publicacin/subscripcin.
Un nodo publica un mensaje en un topic dado; El topic es un nombre usado para identificar el contenido
del mensaje; Un nodo que est interesado en un cierto tipo de datos, se subscribir al topic apropiado.
Puede haber mltiple publicadores y subscriptores para un nico topic y un nico nodo puede publicar
y/o subscribirse a mltiples topics. La idea es desconectar los proveedores de informacin de los
consumidores.
2

- Servicios: Este sistema atiende al modelo peticin/respuesta. Un nodo ofrece un servicio bajo
un nombre determinado y un nodo cliente usa el servicio enviando un mensaje de peticin y esperando
un mensaje de respuesta.
- Bolsas (bags): La bolsa es un mecanismo para guardar mensajes y reproducirlos
posteriormente. Es de una importancia vital por ejemplo para guardar datos de sensores.
El Maestro acta como un servidor de nombres. Los nodos se comunican con el Maestro para
facilitarle sus informaciones de registro. Como esos nodos se comunican con el maestro, pueden recibir
informacin de otros nodos registrados y establecer comunicacin.
El protocolo ms comn usado para comunicar nodos directamente es TCPROS, basado en los
sockets estndar TCP/IP.
Los nombres son muy importantes en ROS. Todos los elementos computacionales en ROS
tienen nombre: los nodos, los topics, los servicios y los parmetros. Todas las libreras cliente de ROS
soportan el remapeo de nombres por lnea de comandos, lo que permite que un programa ya compilado
pueda ser reconfigurado en tiempo real para operar en una topologa computacional diferente.
Por ejemplo, para controlar un lser Hokuyo, podemos iniciar el nodo-driver hokuyo, el cual
dialoga con el dispositivo lser y publica mensajes del tipo LaserScan en el topic scan. Para procesar
esos datos, debemos programar un nodo usando filtros laser que se suscriben a los mensajes del topic
scan. Tras la subscripcin, nuestro filtro podra automticamente iniciarse recibiendo mensajes desde
el lser.
Observa como los dos extremos estn desconectados. El nodo hokuyo publica datos del lser
sin saber quin est subscrito. El nodo filtro est subscrito al sensor sin saber qu nodo publica sus
datos. Los dos nodos pueden ser iniciados, finalizados y reiniciados, en cualquier orden, sin que se
produzcan errores.
Si ms tarde se aade otro lser a nuestro robot, necesitaremos reconfigurar nuestro sistema.
Todo lo que necesitamos es remapear los nombres que son usados. Cuando iniciamos nuestro primer
nodo hokuyo, podemos indicarle que remapee scan a base_scan y hacer lo mismo con el nodo filtro.
Ahora esos nodos se comunicarn usando el topic base_scan sin escuchar ya mensajes del topic scan.
Hecho esto podemos iniciar un nuevo nodo hokuyo.

COMENZANDO A TRABAJAR CON ROS. ENTORNO DE TRABAJO

En primer lugar nos aseguramos que ROS est correctamente instalado y definido de forma
correcta. Ejecutamos en un terminal la siguiente instruccin:
$ export | grep ROS
Como resultado, debe darnos una serie de definiciones como el path de ROS, el host_name, el
local host, etc
El entorno o espacio de trabajo (Workspace) est definido en la variable de entorno
ROS_PACKAGE_PAT. Podemos ver su valor:
$ echo $ROS_PACKAGE_PATH
En la distribucin OpenQbo ser: /opt/ros/electric/stacks
La estructura de las carpetas en el disco duro parte de la raz del entorno de trabajo
(/opt/ros/electric/stacks) Todas las carpetas que cuelguen de ah, son pilas o stacks. Dentro de cada pila
puede haber varios paquetes (varias subcarpetas) o un solo paquete. En el caso de que la pila contenga
un nico paquete veremos que directamente el directorio tiene carpetas como bin, config, launch o src.
Adems, contendr archivos como manifest.xml, etc. En el caso de la distribucin OpenQbo existe la
carpeta /qbo_stack que cuelga del directorio /stacks de ROS.
Existen varios comandos para moverse entre pilas y paquetes, como rospack, roscd, etc
pero es ms cmodo utilizar la ventana del S.O.
Hablemos ahora de roscore. Para poder usar ROS hay que iniciar su estructura mediante la
instruccin roscore. En la distribucin de OpenQbo, roscore se autoejecuta al iniciar el sistema. Si
intentamos ejecutar roscore, el sistema nos advertir (en rojo) que ya se encuentra en ejecucin (es el
caso de la distribucin OpenQbo).

ENTENDIENDO LOS NODOS


A partir de ahora entendemos que vamos a trabajar en la distribucin de Ubuntu preparada por
TheCorpora, OpenQbo. Bien. Ya tenemos roscore ejecutndose en un terminal. Ahora debemos abrir
otro terminal (sin cerrar el de roscore) para probar el comando rosnode. Ejecutamos:
$ rosnode list
Veremos que hay varios paquetes (no nodos) en ejecucin:
/qbo_arduqbo
/qbo_audio_control
/qbo_listen
/qbo_talk
/qbo_video_record
/qbo_webi
/rosout
/stereo/stereo_proc
/stereo/uvc_camera_stereo
4

Si queremos tener ms informacin sobre un paquete concreto escribimos rosnode info


/nombre_paquete:
$ rosnode info /qbo_audio_control
Podremos ver sus publicaciones, subscripciones, servicios, etc
Para ejecutar un nodo se utiliza el comando rosrun [paquete] [nodo]. Se puede ejecutar un
nodo sin conocer la ruta de su paquete mediante el comando rosrun.
NOTA: Para poder practicar con los ejemplos de ROS hay que instalarlos:
$ sudo apt-get install ros-electric-ros-tutorials
Con esto habremos instalado los tutoriales de la versin electric de ROS desde los repositorios
de ROS. Podemos comprobarlo testeando la existencia del directorio /ros_tutorials colgando de la
carpeta /stacks. Ahora, para probar rosrun [paquete] [nodo] ejecutamos:
$ rosrun turtlesim turtlesim_node
Veremos una ventana con una tortuga. Si abrimos un nuevo terminal y ejecutamos en l
rosnode list, veremos que el paquete turtlesim se ha aadido a la lista de procesos en ejecucin.
Veamos ahora cmo se trabaja con topics.

ENTENDIENDO LOS TOPICS

Para comprender el funcionamiento de los topics, abrimos 2 terminales nuevos. En uno


ejecutamos un nodo:
$ rosrun turtlesim turtlesim_node
Y en el otro ejecutamos otro nodo:
$ rosrun turtlesim turtle_teleop_key
El primero presenta una ventana con una tortuga y el segundo nodo permite mover dicha
tortuga por la ventana con las teclas de flecha (este terminal debe estar activo).
Los dos nodos se comunican mediante un topic: el nodo turtle_teleop_key publica las
pulsaciones de teclas en un topic. A su vez, el nodo turtlesim recibe dichas pulsaciones de ese topic al
que est subscrito.
ROS tiene una herramienta muy til para ver grficamente los nodos y topics en ejecucin.
$ rxgraph

El esquema inicial de OpenQbo es el siguiente:

Otra herramienta es rostopic.

Si al ejecutar lo anterior no ocurre nada, es porque no se est emitiendo ningn mensaje en el


topic. En caso contrario se visualizan los mensajes en pantalla mostrando los valores lineales y angulares
del movimiento de la tortuga. Esto funciona porque rostopic echo es en realidad un nodo que se ha
subscrito al topic y visualiza sus mensajes:

El comando de la figura superior visualiza una lista de todos los topics actuales

Veamos ahora el comando rostopic type utilizado para ver el tipo de un topic:

Otro comando es rosmsg show que visualiza los campos de un mensaje:

La combinacin de ambos comandos muestra los mensajes de un topic.


$ rostopic type /turtle1/command_velocity | rosmsg show

ENTENDIENDO LOS SERVICIOS Y LOS PARMETROS

Un servicio es otra forma en la que un nodo puede comunicarse con el resto. Los servicios
permiten a los nodos enviar una peticin y recibir una respuesta.
Veamos el comando rosservice:

El comando list muestra los servicios que proporciona un nodo. En el caso del nodo turtlesim
son 9:

Veamos de qu tipo es el servicio clear:

Al ejecutar el comando type sobre el servicio clear, rosservice devuelve que el servicio est
vaco. Esto ocurre cuando la llamada a un servicio se hace sin argumentos (no enva datos al hacer una
8

peticin y no recibe datos al recibir una respuesta). Simplemente el servicio acta como un programa
que hace una determinada tarea sin necesidad de recibir argumentos y sin devolver datos.
Para ejecutar un servicio se usa el siguiente comando:

Veamos un servicio con parmetros, por ejemplo spawn. Este es un servicio utilizado por el
nodo turtlesim_node, as que vamos a ejecutarlo primero en un terminal:
$ rosrun turtlesim turtlesim_node
Ahora vamos a ver cules son sus parmetros o argumentos (teclear en otro terminal):

Obsrvese que este servicio tiene 4 parmetros de entrada y uno de salida. Al hacer:

Hemos llamado al servicio spawn indicando sus 4 argumentos. La llamada al servicio devuelve
el parmetro name (que es el nombre de una nueva tortuga):
Veamos ahora el comando rosparam:

Este comando permite almacenar y manipular datos en el servidor de parmetros ROS. El


servidor de parmetros puede almacenar enteros, flotantes, booleanos, diccionarios y listas. Un
diccionario se representa como {a: b, c: d}. Una lista se representa como [1, 2, 3].
NOTA: El servidor de parmetros es un diccionario compartido accesible por todos los nodos ROS. Los
nodos usan este servidor para almacenar y recuperar datos en tiempo real. Suele utilizarse como
parmetros de configuracin. Hemos comentado que el servidor de parmetros es un diccionario.
Veamos un ejemplo de cmo funciona:

Arriba vemos 4 parmetros con sus correspondientes valores. Los parmetros, de la misma
forma que ocurre con los nodos y topics, se ordenan por jerarquas:
9

El parmetro /camera/left/name tiene un valor de leftcamera.


El parmetro/camera/left tiene un valor (en forma de diccionario) de:

Y el parmetro /camera tiene un valor (en forma de rbol) de:

Sigamos con el comando rosparam.

En el ejemplo superior observamos que hay 3 parmetros (los 3 primeros). Vamos a modificar
el valor de uno de ellos:

Con esto hemos modificado el valor del parmetro. Si queremos ver el contenido del servidor
de parmetros al completo, escribimos:

Finalmente, decir que podemos guardar el servidor de parmetros en un archivo y recuperarlo


despus.

Arriba hemos guardado el servidor de parmetros en el archivo params.yaml. Abajo, cargamos


el archivo en un nuevo espacio de nombres (copy):

10

CREANDO UN PAQUETE ROS

Un paquete ROS se compone de diferentes archivos: archivos de manifiesto .xml,


CMakeLists.txt, Makefiles, mainpage.dox, Existe un comando ROS que automatiza la tarea de
compilacin de un paquete: roscreate-pkg.
Para crear un paquete en el directorio actual se utiliza:

Si dicho paquete tiene dependencias de otros paquetes se utiliza:

Como ejemplo, vamos a crear un paquete llamado beginner_tutorials que tendr


dependencias de std_msgs, roscpp y rospy.
Por defecto, la distribucin OpenQbo no permite modificar la carpeta /ros. Debemos por tanto
habilitar esta funcin. Lo primero es permitir a nuestro usuario el acceso a dicha carpeta:
$ sudo chown R nombredeUsuario /opt/ros/electric/stacks
Nos desplazamos a la carpeta /stacks:
$ cd /opt/ros/electric/stacks
Y creamos el paquete:

Veremos una ventana que nos informar de la creacin de los directorios y archivos que forman
el paquete:

11

Al final recomienda echar una mirada al archivo manifest.xml que es donde se describe la
estructura del paquete.
Si nos desplazamos al directorio del paquete recin creado podemos ver que ha creado una
estructura como la de la siguiente figura:

Ahora vamos a asegurarnos que ROS puede ver el paquete. A menudo es til ejecutar rospack
profile para que se reflejen los cambios de directorios en nuestro PATH. Luego podemos buscar el
paquete:

Respecto a las dependencias, se denominan dependencias de primer orden a las que hemos
indicado en el momento de creacin del paquete:

Estas dependencias quedan reflejadas en el archivo manifest.xml.


Tambin existen las llamadas dependencias indirectas, que son las dependencias de otras
dependencias. Por ejemplo, nuestro paquete ha heredado las dependencias del paquete rospy.

As, si testeamos las dependencias de nuestro paquete, se vern las directas e indirectas:

12

CREANDO ARCHIVOS MSG Y ARCHIVOS SRV

Estos archivos de texto se utilizan para describir los elementos y parmetros de los mensajes y
servicios. Si por ejemplo programamos un nodo servicio con 2 parmetros de entrada y uno de salida,
estos parmetros hay que definirlos en un archivo .srv asociado a dicho servicio.
Los archivos msg son simples archivos de texto que describen los campos de un mensaje ROS.
Estos archivos son utilizados para generar cdigo fuente de los mensajes en diferentes lenguajes
durante el proceso de compilacin.
Los archivos srv describen un servicio. Se componen de dos partes separadas por guiones: una
peticin y una respuesta.
Los archivos msg se almacenan en el directorio /msg dentro del paquete y los archivos srv
dentro del directorio /srv
Dentro de un archivo msg se pueden utilizar los tipos int8, int16, int32, int64, uint8, uint16,
Tambin los float32, float64, string, time, duration, array[] as como otros archivos msg.
Se comienza por el tipo especial de ROS llamado Header.
Un ejemplo de archivo msg:

Los archivos srv son similares a los msg, excepto que tienen dos partes: una peticin al principio
y una respuesta tras los tres guiones. Veamos un ejemplo:

13

Para crear un mensaje se crea un fichero .msg en la carpeta /msg del paquete con el contenido
deseado. Para nuestro ejemplo creamos el archivo Num.msg con el siguiente contenido:
int64 num
Podemos crear el archivo utilizando nuestro editor favorito o bien desde un terminal de la
siguiente forma:

Para asegurarnos que se generar el mensaje cuando compilemos el paquete, hay que abrir el
archivo CMakeLists.txt en un editor y quitar el smbolo de comentario (#) de la siguiente lnea:
# rosbuild_genmsg()
Creado el mensaje, podemos comprobar que ROS lo ve utilizando el comando rosmsg show

Ejemplo:

Si no sabemos el nombre del paquete donde est el mensaje podemos hacer:

Pasemos ahora a los servicios. Para crear un servicio generamos previamente un archivo dentro
de la carpeta /srv con el contenido de los parmetros a utilizar por dicho servicio. Para nuestro ejemplo,
creamos un archivo llamado AddTwoInts.srv con el siguiente contenido:
int64 a
int64 b
--int64 sum
Finalmente tenemos que quitar del archivo CMakeLists.txt el # de la lnea:
# rosbuild_gensrv()
Al igual que antes podemos asegurarnos que ROS lo ve.

Finalmente, al haber creado un archivo .msg y/o un archivo .srv, hay que volver a compilar el
paquete:
$ rosmake beginner_tutorials
14

Tras la compilacin, ya tenemos introducido en el paquete los dos archivos creados.

ESCRIBIENDO UN NODO PUBLICADOR EN C++

Nodo es el trmino ROS para un ejecutable que conecta a la red ROS. Vamos a crear un nodo
publicador que emitir continuamente un mensaje a dicha red.
Lo primero que debemos hacer es desplazarnos con roscd al directorio de nuestro paquete:

Ahora, dentro de la carpeta /src, vamos a crear un archivo (para este ejemplo, talker.cpp) con el
siguiente contenido:

#include "ros/ros.h"
#include "std_msgs/String.h"

//Obligatorio ponerlo para trabajar con ROS


//El tipo String de ROS

#include <sstream>
/**
* Este tutorial muestra cmo enviar mensajes al sistema ROS
*/
int main(int argc, char **argv)
{
/**
* La funcin ros::init() inicializa el nodo talker en el sistema ROS. Le pasamos los argumentos para la lnea de comandos
* y un tercer argumento con el nombre del nodo.
*/
ros::init(argc, argv, "talker");
/**
* NodeHandle es el principal punto de acceso para comunicarse con el sistema ROS
*/
ros::NodeHandle n;
/**
* La funcin advertise() sirve para decirle a ROS que queremos publicar en un topic determinado.
* (en este caso el topic se llama chatter y estamos indicando que el mensaje ser de tipo String)
* Con esto hacemos una llamada al nodo maestro de ROS, el cual lleva un registro de qu nodos estn
* publicando y qu nodos estn subscritos. advertise() devuelve un objeto publicador que te permite
* publicar mensajes en el topic mediante una llamada a la funcin publish().
*
* El segundo parmetro de advertise() es el tamao de la cola del mensaje usada para publicar mensajes.
* Si los mensajes son publicados ms deprisa de lo que puedan enviarse, se guardarn en la cola.
*/
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
ros::Rate loop_rate(10); //Define la frecuencia en hercios de polling (10 veces por segundo).
/**
* Contador con el nmero de mensajes enviados. Se usa para crear un nic string por cada mensaje.
*/
int count = 0;
while (ros::ok()) //Mientras el sistema ROS est operativo
{
/**
* Objeto mensaje donde cargamos los datos para despus publicarlo.
*/

15

std_msgs::String msg;
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str(); //data es un miembro del tipo String. String es un archivo .msg
ROS_INFO("%s", msg.data.c_str()); //este es el equivalente ROS a printf y cout
/**
* Con la funcin publish() enviamos los mensajes. El parmetro es el objeto mensaje
* El tipo del objeto debe coincidir con el que pusimos en advertise()
*/
chatter_pub.publish(msg);
/**
* Aqu no es necesaria, pero spinOnce() se pone para atender a las funciones callback.
* Si hubisemos aadido una subscripcin en esta aplicacin, no funcionara sin esta llamada.
*/
ros::spinOnce();
loop_rate.sleep(); //Aplica el sleep que definimos antes. Publica 10 veces/seg
++count;
}

return 0;
}

NOTA FINAL: Para crear este nodo en el paquete, debemos editar el archivo CMakeLists.txt del
directorio y aadir al final la siguiente lnea:
Rosbuild_add_executable(talker src/talker.cpp)
Esto crear un ejecutable talker, que por defecto se ubicar en la carpeta /bin.
Ahora, ejecutar:
$ make

ESCRIBIENDO UN NODO SUBSCRIPTOR EN C++

Al igual que antes, nos desplazamos al directorio de nuestro paquete usando roscd y creamos el
archivo listener.cpp dentro de la carpeta /src.
#include "ros/ros.h"
#include "std_msgs/String.h"

//Obligatorio ponerlo para trabajar con ROS


//El tipo String de ROS

/**
* Este tutorial muestra un simple nodo receptor de mensajes.
*/
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
/**
* init() inicializa el nodo listener en el sistema ROS
*/
ros::init(argc, argv, "listener");

16

/**
* n es el manejador del nodo.
*/
ros::NodeHandle n;
/**
* Mediante la funcin subscribe() indicamos a ROS que queremos recibir los mensajes del topic chatter
* Los mensajes se pasan a una funcin de callback (aqu llamada chatterCallback)
* El nmero 1000 indica el tamao de la cola de mensajes recibidos.
*/
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
/**
* ros::spin() hace que se entre en un polling buscando mensajes. Cuando llega un mensaje al topic, se llama a la funcin
* chatterCallback() indicada antes.
* Hay otras formas de hacer esto.
*/
ros::spin();
return 0;
}

NOTA FINAL: Para crear este nodo en el paquete, debemos editar el archivo CMakeLists.txt del
directorio y aadir al final la siguiente lnea:
rosbuild_add_executable(listener src/listener.cpp)
Esto crear un ejecutable listener, que por defecto se ubicar en la carpeta /bin.
Ahora, ejecutar:
$ make

ESCRIBIENDO UN NODO PUBLICADOR EN PYTHON

A diferencia de C++, el cdigo fuente escrito en python se denomina script. Hay que guardarlo
en la carpeta /scripts del paquete.
Creamos el archivo talker.py con el siguiente contenido:
#!/usr/bin/env python
#Esta linea asegura que el script ser ejecutable
import roslib; roslib.load_manifest('beginner_tutorials')
#importa las libreras
import rospy #imprescindible para un nodo python
from std_msgs.msg import String
#importa el tipo String
def talker():
#describe el interfaz de talker
pub = rospy.Publisher('chatter', String) #declara que el nodo publicar un String en el topic chatter
rospy.init_node('talker') #indica el nombre del nodo
while not rospy.is_shutdown():
#mientras el sistema est en funcionamiento
str = "hello world %s" % rospy.get_time()
#construye el mensaje
rospy.loginfo(str)
pub.publish(String(str))
#publica el mensaje
rospy.sleep(1.0)
#Hace una pausa

if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:

#Para finalizar la ejecucin tras un Ctrl-C o finalizacin

17

pass

Para hacer ejecutable un nodo escrito en python:


$ chmod +x scripts/talker.py
$ make

ESCRIBIENDO UN NODO SUBSCRIPTOR EN PYTHON

Creamos el archivo scripts/listener.py:


#!/usr/bin/env python
import roslib; roslib.load_manifest('beginner_tutorials')
import rospy
from std_msgs.msg import String

def callback(data):
rospy.loginfo(rospy.get_name() + ": I heard %s" % data.data)

def listener():
rospy.init_node('listener', anonymous=True)
#declara el nodo. Con anonymous podemos tener varios listener
rospy.Subscriber("chatter", String, callback)
#se suscribe al topic chatter para recibir un string
rospy.spin() #hace que el nodo permanezca a la escucha infinitamente (no funciona como en c++)

if __name__ == '__main__':
listener()

Para hacer ejecutable un nodo escrito en python:


$ chmod +x scripts/listener.py
$ make

FUNCIONAMIENTO DE PUBLICADORES Y SUBSCRIPTORES

Lo primero es ejecutar el sistema ROS:

Ejecutamos el publicador:

18

Lo que estamos viendo es el mensaje que el nodo publica en el topic chatter.


Ahora vamos a ver cmo funciona el nodo subscriptor. Escribir en otro terminal:

ESCRIBIENDO UN NODO SERVICIO Y UN NODO CLIENTE EN C++

El nodo que vamos a programar recibe 2 nmeros enteros y devuelve la suma de ellos. Para
que funcione este ejemplo, debemos tener en la carpeta /srv un fichero llamado AddTwoInst.srv con
el contenido siguiente (y haberlo compilado en el paquete mediante rosmake):

NOTA: Al compilar el archivo srv, se genera automticamente un archivo include (.h) asociado.
Nos desplazamos al directorio de nuestro paquete con roscd y creamos add_two_ints_server.cpp en la
carpeta /src con el siguiente contenido:
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"

// Esta funciona recoge los argumentos de la peticin (req) y de la respuesta (res) para trabajar con ellos
bool add(beginner_tutorials::AddTwoInts::Request &req,
beginner_tutorials::AddTwoInts::Response &res)
{
res.sum = req.a + req.b;
ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
ROS_INFO("sending back response: [%ld]", (long int)res.sum);
return true;
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "add_two_ints_server"); //Inicializa el nodo servicio
ros::NodeHandle n; //manejador del nodo

19

ros::ServiceServer service = n.advertiseService("add_two_ints", add); //anuncia el servicio a ROS y su funcin asociada


ROS_INFO("Ready to add two ints.");
ros::spin();
return 0;
}

El nodo servicio est a disposicin de los nodos denominados cliente. Para programar un
nodo cliente, creamos en /src el archivo add_two_ints_client.cpp:
#include "ros/ros.h"
#include "beginner_tutorials/AddTwoInts.h"
#include <cstdlib>
int main(int argc, char **argv)
{
ros::init(argc, argv, "add_two_ints_client");
if (argc != 3)
{
ROS_INFO("usage: add_two_ints_client X Y");
return 1;
}
ros::NodeHandle n;
// Lo siguiente crea un cliente add_two_ints para el servicio AddTwoInts
ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints");
beginner_tutorials::AddTwoInts srv; //Instanciamos la estructura del archivo srv
srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);
if (client.call(srv)) //llamada al nodo servicio con los argumentos definidos justo arriba
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum);
}
else
{
ROS_ERROR("Failed to call service add_two_ints");
return 1;
}
return 0;
}

Para construir estos nodos, editamos el archivo CMakeLists.txt de nuestro paquete y aadimos
las siguientes lneas al final:

Esto crear dos ejecutables en la carpeta /bin.


Finalmente ejecutar:
$ make

ESCRIBIENDO UN NODO SERVICIO Y UN NODO CLIENTE EN PYTHON

De forma similar a c++ y teniendo creado y empaquetado el archivo .srv, creamos el archivo
add_two_ints_server.py en la carpeta /scripts del paquete.
20

#!/usr/bin/env python
import roslib; roslib.load_manifest('beginner_tutorials')
from beginner_tutorials.srv import *
import rospy
def handle_add_two_ints(req):
print "Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b))
return AddTwoIntsResponse(req.a + req.b)
def add_two_ints_server():
rospy.init_node('add_two_ints_server')
s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
print "Ready to add two ints."
rospy.spin()
if __name__ == "__main__":
add_two_ints_server()

Para hacer el nodo ejecutable:


$ chmod +x scripts/add_two_ints_server.py
$ make

Ahora, para escribir un nodo cliente llamado scripts/add_two_ints_client.py


#!/usr/bin/env python
import roslib; roslib.load_manifest('beginner_tutorials')
import sys
import rospy
from beginner_tutorials.srv import *
def add_two_ints_client(x, y):
rospy.wait_for_service('add_two_ints')
try:
add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
resp1 = add_two_ints(x, y)
return resp1.sum
except rospy.ServiceException, e:
print "Service call failed: %s"%e
def usage():
return "%s [x y]"%sys.argv[0]
if __name__ == "__main__":
if len(sys.argv) == 3:
x = int(sys.argv[1])
y = int(sys.argv[2])
else:
print usage()
sys.exit(1)
print "Requesting %s+%s"%(x, y)
print "%s + %s = %s"%(x, y, add_two_ints_client(x, y))

Para hacer el nodo ejecutable:


$ chmod +x scripts/add_two_ints_client.py
$ make

FUNCIONAMIENTO DE LOS NODOS SERVICIO Y CLIENTE


21

Primero ejecutamos el nodo servicio:

Debes ver algo similar a esto:

Ahora ejecutamos el nodo cliente en otro terminal con los argumentos en la lnea de
comandos:

Debes ver algo similar a esto:

USANDO ROSLAUNCH

Este tutorial explica el uso de roslaunch para iniciar varios nodos al mismo tiempo.

Lo primero es crear un archivo de lanzamiento. Se guardan en el directorio /launch del paquete.


Siguiendo con nuestro paquete-tutorial, escribimos en un terminal:

Ahora creamos un archivo llamado turtlemimic.launch en el directorio /launch de nuestro


paquete con el siguiente contenido:
<launch>
<group ns="turtlesim1">
<node pkg="turtlesim" name="sim" type="turtlesim_node"/>
</group>
<group ns="turtlesim2">
<node pkg="turtlesim" name="sim" type="turtlesim_node"/>
</group>
<node pkg="turtlesim" name="mimic" type="mimic">
<remap from="input" to="turtlesim1/turtle1"/>
<remap from="output" to="turtlesim2/turtle1"/>
</node>

22

</launch>

La etiqueta <launch> identifica el archivo xml como de tipo launch. Vemos tambin que se
inician dos grupos con espacio de nombres denominado turtlesim1 y turtlesim2. En realidad se
estn lanzando 2 nodos turtlesim, cada uno llamado de forma distinta. Con estas definiciones
iniciaremos dos simuladores sin conflictos de nombres. El ltimo bloque del archivo inicia el nodo
mimic con los topics de entrada y salida renombrados a turtlesim1 y turtlesim2
Ahora lanzamos el archivo mediante roslaunch:

Veremos que se abren dos ventanas con las tortugas. En una nueva ventana en viamos el
comando rostopic siguiente:

23

You might also like