Está en la página 1de 23

TUTORIALES ROS

INTRODUCCIÓN
ROS es un meta-sistema operativo para robots, es decir, una librería de código 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 más comunes en el manejo de robots, intercambia mensajes entre procesos y es capaz
de administrar paquetes de código. También proporciona librerías y herramientas para obtener,
construir, escribir y ejecutar código a través de múltiples 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
comunicación es síncrona cuando se utilizan servicios (comunicación tipo petición/respuesta). Es
asíncrona cuando se usan topics o temas; un topic es un bus por donde circulan mensajes
intercambiados por nodos, que son pequeños 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), librerías,
conjuntos de datos (datasets), archivos de configuración, etc.
- Manifiestos (manifests): son archivos con extensión .xml que proporcionan información
(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 extensión .msg. Las descripciones de los mensajes están
almacenadas en my_package/msg/MyMessageType.msg y describen la estructura de los mensajes
enviados en ROS
- Tipos de Servicios: Archivos con extensión .srv. Las descripciones de los servicios están
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 COMPUTACIÓN DE ROS
- Nodos: Los nodos son procesos ejecutables. ROS está diseñado para ser modular. Por
ejemplo, un robot tendrá un nodo para controlar el láser, otro nodo para controlar los motores de
desplazamiento, otro nodo para calcular el camino correcto, etc… Un nodo se programa utilizando una
librería 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 “encontrarían” ni podrían intercambiar mensajes entre ellos.
- Servidor de Parámetros: Forma parte del Maestro y permite almacenar datos por clave en
una localización 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 semántica de publicación/subscripción.
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 múltiple publicadores y subscriptores para un único topic y un único nodo puede publicar
y/o subscribirse a múltiples topics. La idea es desconectar los proveedores de información de los
consumidores.
2

Como esos nodos se comunican con el maestro. Por ejemplo. sin que se produzcan errores. debemos programar un nodo usando filtros laser que se suscriben a los mensajes del topic ‘scan’. Si más tarde se añade otro láser a nuestro robot. finalizados y reiniciados. Todos los elementos computacionales en ROS tienen nombre: los nodos. el cual dialoga con el dispositivo láser y publica mensajes del tipo ‘LaserScan’ en el topic ‘scan’. los topics. Los nodos se comunican con el Maestro para facilitarle sus informaciones de registro.. pueden recibir información de otros nodos registrados y establecer comunicación. Tras la subscripción. podemos indicarle que remapee ‘scan’ a ‘base_scan’ y hacer lo mismo con el nodo filtro. los servicios y los parámetros. necesitaremos reconfigurar nuestro sistema. lo que permite que un programa ya compilado pueda ser reconfigurado en tiempo real para operar en una topología computacional diferente. Los dos nodos pueden ser iniciados. 3 . El Maestro actúa como un servidor de nombres. Los nombres son muy importantes en ROS. Todas las librerías cliente de ROS soportan el remapeo de nombres por línea de comandos. . Cuando iniciamos nuestro primer nodo hokuyo. Es de una importancia vital por ejemplo para guardar datos de sensores. Ahora esos nodos se comunicarán usando el topic ‘base_scan’ sin escuchar ya mensajes del topic ‘scan’. Hecho esto podemos iniciar un nuevo nodo hokuyo. El nodo hokuyo publica datos del láser sin saber quién está subscrito. El protocolo más común usado para comunicar nodos directamente es TCPROS. Observa como los dos extremos están desconectados. en cualquier orden. El nodo filtro está subscrito al sensor sin saber qué nodo publica sus datos. podemos iniciar el nodo-driver hokuyo. Un nodo ofrece un servicio bajo un nombre determinado y un nodo cliente usa el servicio enviando un mensaje de petición y esperando un mensaje de respuesta. Para procesar esos datos. nuestro filtro podría automáticamente iniciarse recibiendo mensajes desde el láser.Bolsas (bags): La bolsa es un mecanismo para guardar mensajes y reproducirlos posteriormente. Todo lo que necesitamos es remapear los nombres que son usados.Servicios: Este sistema atiende al modelo petición/respuesta. para controlar un láser Hokuyo. basado en los sockets estándar TCP/IP.

Además. Ya tenemos roscore ejecutándose en un terminal.xml. Dentro de cada pila puede haber varios paquetes (varias subcarpetas) o un solo paquete. etc… pero es más cómodo utilizar la ventana del S. Ejecutamos: $ rosnode list Veremos que hay varios paquetes (no nodos) en ejecución: /qbo_arduqbo /qbo_audio_control /qbo_listen /qbo_talk /qbo_video_record /qbo_webi /rosout /stereo/stereo_proc /stereo/uvc_camera_stereo 4 . ENTORNO DE TRABAJO En primer lugar nos aseguramos que ROS está correctamente instalado y definido de forma correcta. OpenQbo. contendrá archivos como manifest. ENTENDIENDO LOS NODOS A partir de ahora entendemos que vamos a trabajar en la distribución de Ubuntu preparada por TheCorpora. En la distribución de OpenQbo. Si intentamos ejecutar roscore. el sistema nos advertirá (en rojo) que ya se encuentra en ejecución (es el caso de la distribución OpenQbo). roscore se autoejecuta al iniciar el sistema. En el caso de la distribución OpenQbo existe la carpeta /qbo_stack que cuelga del directorio /stacks de ROS. etc… El entorno o espacio de trabajo (Workspace) está definido en la variable de entorno ROS_PACKAGE_PAT. roscd. son pilas o stacks. como rospack. config.O. En el caso de que la pila contenga un único paquete veremos que directamente el directorio tiene carpetas como bin. el local host. el host_name. Ejecutamos en un terminal la siguiente instrucción: $ export | grep ROS Como resultado.COMENZANDO A TRABAJAR CON ROS. debe darnos una serie de definiciones como el path de ROS. Existen varios comandos para “moverse” entre pilas y paquetes. Bien. etc. Hablemos ahora de roscore. Podemos ver su valor: $ echo $ROS_PACKAGE_PATH En la distribución OpenQbo será: /opt/ros/electric/stacks La estructura de las carpetas en el disco duro parte de la raíz del entorno de trabajo (/opt/ros/electric/stacks) Todas las carpetas que cuelguen de ahí. Ahora debemos abrir otro terminal (sin cerrar el de roscore) para probar el comando rosnode. launch o src. Para poder usar ROS hay que iniciar su estructura mediante la instrucción roscore.

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 versión electric de ROS desde los repositorios de ROS. $ rxgraph 5 . etc… Para ejecutar un nodo se utiliza el comando “rosrun [paquete] [nodo]”. el nodo turtlesim recibe dichas pulsaciones de ese topic al que está subscrito. A su vez. Ahora. ENTENDIENDO LOS TOPICS Para comprender el funcionamiento de los topics. veremos que el paquete turtlesim se ha añadido a la lista de procesos en ejecución. Los dos nodos se comunican mediante un topic: el nodo turtle_teleop_key publica las pulsaciones de teclas en un topic. Veamos ahora cómo se trabaja con topics. Se puede ejecutar un nodo sin conocer la ruta de su paquete mediante el comando rosrun. servicios. ROS tiene una herramienta muy útil para ver gráficamente los nodos y topics en ejecución. Si abrimos un nuevo terminal y ejecutamos en él “rosnode list”. subscripciones. Podemos comprobarlo testeando la existencia del directorio /ros_tutorials colgando de la carpeta /stacks. abrimos 2 terminales nuevos.Si queremos tener más información sobre un paquete concreto escribimos “rosnode info /nombre_paquete”: $ rosnode info /qbo_audio_control Podremos ver sus publicaciones. para probar “rosrun [paquete] [nodo]” ejecutamos: $ rosrun turtlesim turtlesim_node Veremos una ventana con una tortuga. 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).

6 .El esquema inicial de OpenQbo es el siguiente: Otra herramienta es rostopic.

En caso contrario se visualizan los mensajes en pantalla mostrando los valores lineales y angulares del movimiento de la tortuga.Si al ejecutar lo anterior no ocurre nada. es porque no se está emitiendo ningún mensaje en el topic. 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: 7 .

Otro comando es “rosmsg show” que visualiza los campos de un mensaje: La combinación de ambos comandos muestra los mensajes de un topic. 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. Los servicios permiten a los nodos enviar una petición y recibir una respuesta. rosservice devuelve que el servicio está vacío. Esto ocurre cuando la llamada a un servicio se hace sin argumentos (no envía datos al hacer una 8 . $ rostopic type /turtle1/command_velocity | rosmsg show ENTENDIENDO LOS SERVICIOS Y LOS PARÁMETROS Un servicio es otra forma en la que un nodo puede comunicarse con el resto. Veamos el comando rosservice: El comando list muestra los servicios que proporciona un nodo.

flotantes. se ordenan por jerarquías: 9 .petición y no recibe datos al recibir una respuesta). de la misma forma que ocurre con los nodos y topics. booleanos. Para ejecutar un servicio se usa el siguiente comando: Veamos un servicio con parámetros. 2. por ejemplo “spawn”. NOTA: El servidor de parámetros es un diccionario compartido accesible por todos los nodos ROS. La llamada al servicio devuelve el parámetro 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 parámetros ROS. Veamos un ejemplo de cómo funciona: Arriba vemos 4 parámetros con sus correspondientes valores. Simplemente el servicio actúa como un programa que hace una determinada tarea sin necesidad de recibir argumentos y sin devolver datos. Suele utilizarse como parámetros de configuración. diccionarios y listas. 3]. Al hacer: Hemos llamado al servicio spawn indicando sus 4 argumentos. El servidor de parámetros puede almacenar enteros. Los parámetros. Una lista se representa como [1. Hemos comentado que el servidor de parámetros es un diccionario. así que vamos a ejecutarlo primero en un terminal: $ rosrun turtlesim turtlesim_node Ahora vamos a ver cuáles son sus parámetros o argumentos (teclear en otro terminal): Obsérvese que este servicio tiene 4 parámetros de entrada y uno de salida. c: d}. Este es un servicio utilizado por el nodo turtlesim_node. Un diccionario se representa como {a: b. Los nodos usan este servidor para almacenar y recuperar datos en tiempo real.

Abajo. En el ejemplo superior observamos que hay 3 parámetros (los 3 primeros). Arriba hemos guardado el servidor de parámetros en el archivo params.yaml. escribimos: Finalmente. Si queremos ver el contenido del servidor de parámetros al completo.El parámetro /camera/left/name tiene un valor de leftcamera. cargamos el archivo en un nuevo espacio de nombres (copy): 10 . Vamos a modificar el valor de uno de ellos: Con esto hemos modificado el valor del parámetro. decir que podemos guardar el servidor de parámetros en un archivo y recuperarlo después. El parámetro/camera/left tiene un valor (en forma de diccionario) de: Y el parámetro /camera tiene un valor (en forma de árbol) de: Sigamos con el comando “rosparam”.

Makefiles. Debemos por tanto habilitar esta función. Por defecto.txt.xml. … Existe un comando ROS que automatiza la tarea de compilación 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.CREANDO UN PAQUETE ROS Un paquete ROS se compone de diferentes archivos: archivos de manifiesto . vamos a crear un paquete llamado “beginner_tutorials” que tendrá dependencias de std_msgs. la distribución OpenQbo no permite modificar la carpeta /ros. 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 creación de los directorios y archivos que forman el paquete: 11 . mainpage.dox. CMakeLists. roscpp y rospy.

si testeamos las dependencias de nuestro paquete. que son las dependencias de otras dependencias.Al final recomienda echar una mirada al archivo manifest.xml que es donde se describe la estructura del paquete. Así. nuestro paquete ha heredado las dependencias del paquete rospy. Luego podemos buscar el paquete: Respecto a las dependencias. se verán las directas e indirectas: 12 . se denominan dependencias de primer orden a las que hemos indicado en el momento de creación del paquete: Estas dependencias quedan reflejadas en el archivo manifest. Si nos desplazamos al directorio del paquete recién 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.xml. También existen las llamadas dependencias indirectas. Por ejemplo.

srv asociado a dicho servicio. time. Los archivos srv describen un servicio. Un ejemplo de archivo msg: Los archivos srv son similares a los msg. Si por ejemplo programamos un nodo servicio con 2 parámetros de entrada y uno de salida. array[] así como otros archivos msg.CREANDO ARCHIVOS MSG Y ARCHIVOS SRV Estos archivos de texto se utilizan para describir los elementos y parámetros de los mensajes y servicios. uint8. Veamos un ejemplo: 13 . int16. string. Estos archivos son utilizados para generar código fuente de los mensajes en diferentes lenguajes durante el proceso de compilación. Se comienza por el tipo especial de ROS llamado Header. estos parámetros hay que definirlos en un archivo . Se componen de dos partes separadas por guiones: una petición y una respuesta. excepto que tienen dos partes: una petición al principio y una respuesta tras los tres guiones. int32. 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. … También los float32. uint16. float64. int64. duration. Los archivos msg son simples archivos de texto que describen los campos de un mensaje ROS.

srv con el siguiente contenido: int64 a int64 b --int64 sum Finalmente tenemos que quitar del archivo CMakeLists. hay que volver a compilar el paquete: $ rosmake beginner_tutorials 14 . al haber creado un archivo .msg en la carpeta /msg del paquete con el contenido deseado. creamos un archivo llamado AddTwoInts.txt en un editor y quitar el símbolo de comentario (#) de la siguiente línea: # rosbuild_genmsg() Creado el mensaje.msg y/o un archivo .srv.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 el # de la línea: # rosbuild_gensrv() Al igual que antes podemos asegurarnos que ROS lo ve. 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 nuestro ejemplo. Finalmente. Para crear un servicio generamos previamente un archivo dentro de la carpeta /srv con el contenido de los parámetros a utilizar por dicho servicio. Para nuestro ejemplo creamos el archivo “Num.Para crear un mensaje se crea un fichero .

* * El segundo parámetro de advertise() es el tamaño de la cola del mensaje usada para publicar mensajes. Se usa para crear un únic string por cada mensaje. ya tenemos introducido en el paquete los dos archivos creados. */ 15 . vamos a crear un archivo (para este ejemplo. /** * NodeHandle es el principal punto de acceso para comunicarse con el sistema ROS */ ros::NodeHandle n.cpp) con el siguiente contenido: #include "ros/ros. Vamos a crear un nodo publicador que emitirá continuamente un mensaje a dicha red. dentro de la carpeta /src. el cual lleva un registro de qué nodos están * publicando y qué nodos están subscritos. 1000). ESCRIBIENDO UN NODO PUBLICADOR EN C++ Nodo es el término ROS para un ejecutable que conecta a la red ROS. /** * Contador con el número de mensajes enviados. Le pasamos los argumentos para la línea de comandos * y un tercer argumento con el nombre del nodo. advertise() devuelve un objeto publicador que te permite * publicar mensajes en el topic mediante una llamada a la función publish(). //Define la frecuencia en hercios de polling (10 veces por segundo). /** * La función advertise() sirve para decirle a ROS que queremos publicar en un topic determinado. */ ros::init(argc. ros::Rate loop_rate(10). argv. se guardarán en la cola. talker. */ int count = 0.advertise<std_msgs::String>("chatter". */ ros::Publisher chatter_pub = n.h" #include "std_msgs/String. Lo primero que debemos hacer es desplazarnos con roscd al directorio de nuestro paquete: Ahora.h" //Obligatorio ponerlo para trabajar con ROS //El tipo String de ROS #include <sstream> /** * Este tutorial muestra cómo enviar mensajes al sistema ROS */ int main(int argc. while (ros::ok()) //Mientras el sistema ROS esté operativo { /** * Objeto mensaje donde cargamos los datos para después publicarlo. * (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.Tras la compilación. * Si los mensajes son publicados más deprisa de lo que puedan enviarse. "talker"). char **argv) { /** * La función ros::init() inicializa el nodo “talker” en el sistema ROS.

} int main(int argc. debemos editar el archivo “CMakeLists.data = ss. #include "ros/ros. que por defecto se ubicará en la carpeta /bin.msg ROS_INFO("%s". /** * Aquí no es necesaria. argv.h" //Obligatorio ponerlo para trabajar con ROS //El tipo String de ROS /** * Este tutorial muestra un simple nodo receptor de mensajes.c_str()). */ ros::spinOnce(). String es un archivo .h" #include "std_msgs/String. //este es el equivalente ROS a printf y cout /** * Con la función publish() enviamos los mensajes. nos desplazamos al directorio de nuestro paquete usando roscd y creamos el archivo “listener.c_str()). //Aplica el sleep que definimos antes. 16 .cpp” dentro de la carpeta /src.data.sleep(). msg. */ void chatterCallback(const std_msgs::String::ConstPtr& msg) { ROS_INFO("I heard: [%s]".cpp) Esto creará un ejecutable “talker”. pero spinOnce() se pone para atender a las funciones callback. } NOTA FINAL: Para crear este nodo en el paquete.txt” del directorio y añadir al final la siguiente línea: Rosbuild_add_executable(talker src/talker. msg. msg->data. std::stringstream ss. ss << "hello world " << count.str(). no funcionaría sin esta llamada. //data es un miembro del tipo String. Publica 10 veces/seg ++count. ejecutar: $ make ESCRIBIENDO UN NODO SUBSCRIPTOR EN C++ Al igual que antes. loop_rate. Ahora. } return 0. "listener").std_msgs::String msg. char **argv) { /** * init() inicializa el nodo “listener” en el sistema ROS */ ros::init(argc. * Si hubiésemos añadido una subscripción en esta aplicación.publish(msg). El parámetro es el objeto mensaje * El tipo del objeto debe coincidir con el que pusimos en advertise() */ chatter_pub.

/** * ros::spin() hace que se entre en un polling buscando mensajes. debemos editar el archivo “CMakeLists.init_node('talker') #indica el nombre del nodo while not rospy. */ ros::NodeHandle n.loginfo(str) pub.ROSInterruptException: #Para finalizar la ejecución tras un Ctrl-C o finalización 17 .get_time() #construye el mensaje rospy. Ahora. el código fuente escrito en python se denomina script. */ ros::Subscriber sub = n. chatterCallback). que por defecto se ubicará en la carpeta /bin.load_manifest('beginner_tutorials') #importa las librerías import rospy #imprescindible para un nodo python from std_msgs. } NOTA FINAL: Para crear este nodo en el paquete.subscribe("chatter". Hay que guardarlo en la carpeta /scripts del paquete.publish(String(str)) #publica el mensaje rospy. /** * Mediante la función subscribe() indicamos a ROS que queremos recibir los mensajes del topic “chatter” * Los mensajes se pasan a una función de callback (aquí llamada chatterCallback) * El número 1000 indica el tamaño de la cola de mensajes recibidos.txt” del directorio y añadir al final la siguiente línea: rosbuild_add_executable(listener src/listener.msg import String #importa el tipo String def talker(): #describe el interfaz de talker pub = rospy. 1000. se llama a la función * chatterCallback() indicada antes. Creamos el archivo “talker. roslib./** * n es el manejador del nodo.cpp) Esto creará un ejecutable “listener”. * Hay otras formas de hacer esto. String) #declara que el nodo publicará un String en el topic chatter rospy. ejecutar: $ make ESCRIBIENDO UN NODO PUBLICADOR EN PYTHON A diferencia de C++. Cuando llega un mensaje al topic.0) #Hace una pausa if __name__ == '__main__': try: talker() except rospy.py” con el siguiente contenido: #!/usr/bin/env python #Esta linea asegura que el script será ejecutable import roslib.is_shutdown(): #mientras el sistema esté en funcionamiento str = "hello world %s" % rospy.sleep(1.Publisher('chatter'. return 0. */ ros::spin().

py: #!/usr/bin/env python import roslib.pass Para hacer ejecutable un nodo escrito en python: $ chmod +x scripts/talker. callback) #se suscribe al topic chatter para recibir un string rospy.init_node('listener'. String. anonymous=True) #declara el nodo.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.Subscriber("chatter".msg import String def callback(data): rospy.get_name() + ": I heard %s" % data.py $ make FUNCIONAMIENTO DE PUBLICADORES Y SUBSCRIPTORES Lo primero es ejecutar el sistema ROS: Ejecutamos el publicador: 18 . roslib.data) def listener(): rospy. Con anonymous podemos tener varios listener rospy.py $ make ESCRIBIENDO UN NODO SUBSCRIPTOR EN PYTHON Creamos el archivo scripts/listener.load_manifest('beginner_tutorials') import rospy from std_msgs.loginfo(rospy.

Escribir en otro terminal: ESCRIBIENDO UN NODO SERVICIO Y UN NODO CLIENTE EN C++ El nodo que vamos a programar recibe 2 números enteros y devuelve la suma de ellos.a + req.b. Para que funcione este ejemplo. Ahora vamos a ver cómo funciona el nodo subscriptor. (long int)res. (long int)req.Lo que estamos viendo es el mensaje que el nodo publica en el topic chatter. char **argv) { ros::init(argc.srv” con el contenido siguiente (y haberlo compilado en el paquete mediante rosmake): NOTA: Al compilar el archivo srv. debemos tener en la carpeta /srv un fichero llamado “AddTwoInst.cpp en la carpeta /src con el siguiente contenido: #include "ros/ros. se genera automáticamente un archivo include (.sum). (long int)req. //Inicializa el nodo servicio ros::NodeHandle n. return true.h" // Esta funciona recoge los argumentos de la petición (req) y de la respuesta (res) para trabajar con ellos bool add(beginner_tutorials::AddTwoInts::Request &req. argv. Nos desplazamos al directorio de nuestro paquete con roscd y creamos add_two_ints_server.h" #include "beginner_tutorials/AddTwoInts. beginner_tutorials::AddTwoInts::Response &res) { res. //manejador del nodo 19 . y=%ld". ROS_INFO("sending back response: [%ld]".sum = req. ROS_INFO("request: x=%ld. } int main(int argc.b). "add_two_ints_server").h) asociado.a.

request.b = atoll(argv[2]).txt de nuestro paquete y añadimos las siguientes líneas al final: Esto creará dos ejecutables en la carpeta /bin. (long int)srv.sum). srv. Para programar un nodo cliente.").request. } return 0.h" #include <cstdlib> int main(int argc.py en la carpeta /scripts del paquete. // Lo siguiente crea un cliente add_two_ints para el servicio AddTwoInts ros::ServiceClient client = n. "add_two_ints_client").serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints"). creamos el archivo add_two_ints_server.h" #include "beginner_tutorials/AddTwoInts. return 0.advertiseService("add_two_ints".ros::ServiceServer service = n. return 1. editamos el archivo CMakeLists. 20 . if (client. //anuncia el servicio a ROS y su función asociada ROS_INFO("Ready to add two ints. return 1. beginner_tutorials::AddTwoInts srv.cpp”: #include "ros/ros. argv. //Instanciamos la estructura del archivo srv srv. char **argv) { ros::init(argc. if (argc != 3) { ROS_INFO("usage: add_two_ints_client X Y").call(srv)) //llamada al nodo servicio con los argumentos definidos justo arriba { ROS_INFO("Sum: %ld". } El nodo servicio está a disposición de los nodos denominados “cliente”. ros::spin(). } else { ROS_ERROR("Failed to call service add_two_ints"). } Para construir estos nodos. 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. add). } ros::NodeHandle n.a = atoll(argv[1]). creamos en /src el archivo “add_two_ints_client.response.

spin() if __name__ == "__main__": add_two_ints_server() Para hacer el nodo ejecutable: $ chmod +x scripts/add_two_ints_server.sum except rospy. (req. roslib. y) return resp1.a.load_manifest('beginner_tutorials') from beginner_tutorials.py #!/usr/bin/env python import roslib.ServiceProxy('add_two_ints'.#!/usr/bin/env python import roslib." rospy.b. y)) Para hacer el nodo ejecutable: $ chmod +x scripts/add_two_ints_client. roslib.py $ make Ahora.b)) return AddTwoIntsResponse(req. AddTwoInts.wait_for_service('add_two_ints') try: add_two_ints = rospy.argv) == 3: x = int(sys. y) print "%s + %s = %s"%(x.srv import * import rospy def handle_add_two_ints(req): print "Returning [%s + %s = %s]"%(req.ServiceException. handle_add_two_ints) print "Ready to add two ints.argv[0] if __name__ == "__main__": if len(sys. AddTwoInts) resp1 = add_two_ints(x.argv[1]) y = int(sys. req.argv[2]) else: print usage() sys.exit(1) print "Requesting %s+%s"%(x.srv import * def add_two_ints_client(x. add_two_ints_client(x.init_node('add_two_ints_server') s = rospy.Service('add_two_ints'.py $ make FUNCIONAMIENTO DE LOS NODOS SERVICIO Y CLIENTE 21 .b) def add_two_ints_server(): rospy.a + req. para escribir un nodo cliente llamado scripts/add_two_ints_client.load_manifest('beginner_tutorials') import sys import rospy from beginner_tutorials. y): rospy.a + req. y. e: print "Service call failed: %s"%e def usage(): return "%s [x y]"%sys.

escribimos en un terminal: Ahora creamos un archivo llamado turtlemimic. Se guardan en el directorio /launch del paquete.Primero ejecutamos el nodo servicio: Debes ver algo similar a esto: Ahora ejecutamos el nodo cliente en otro terminal con los argumentos en la línea de comandos: Debes ver algo similar a esto: USANDO ROSLAUNCH Este tutorial explica el uso de roslaunch para iniciar varios nodos al mismo tiempo. Siguiendo con nuestro paquete-tutorial.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 . Lo primero es crear un archivo de lanzamiento.

En una nueva ventana en viamos el comando rostopic siguiente: 23 . 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. cada uno llamado de forma distinta. Vemos también que se inician dos grupos con espacio de nombres denominado “turtlesim1” y “turtlesim2”. Con estas definiciones iniciaremos dos simuladores sin conflictos de nombres.</launch> La etiqueta <launch> identifica el archivo xml como de tipo launch. En realidad se están lanzando 2 nodos turtlesim.