Difference between revisions of "YARP ROS Interoperation Past and Future But Not Now"

From Wiki for iCub and Friends
Jump to navigation Jump to search
Line 7: Line 7:
* See http://wiki.icub.org/yarpdoc/yarp_with_ros.html for how to use ROS with YARP.
* See http://wiki.icub.org/yarpdoc/yarp_with_ros.html for how to use ROS with YARP.
* This page is historical, and contains layer after layer of improving methods which will just confuse you.
* This page is historical, and contains layer after layer of improving methods which will just confuse you.
* From time to time this page contains development information for a new, otherwise undocumented layer that will
* From time to time this page contains development information for a new, otherwise undocumented layer that will also confuse you.
also confuse you.
* Might we suggest you visit http://wiki.icub.org/yarpdoc/yarp_with_ros.html
* Might we suggest you visit http://wiki.icub.org/yarpdoc/yarp_with_ros.html

Revision as of 19:00, 2 May 2014

This page gives historical steps in YARP/ROS interoperation. You probably want http://wiki.icub.org/yarpdoc/yarp_with_ros.html which gives the current steps needed for interoperation.

This Is Not the Page You Are Looking For


ROS/YARP compatibility work has proceeded as follows:

  • Phase 1 - wire support
    • Added the basic network protocols used by ROS (XML/RPC, TCPROS) to YARP.
    • Added a code generator for converting .msg/.srv files to YARP serialization code.
  • Phase 2 - name support
    • Added support for the ROS name server (rosmaster/roscore) to YARP.
    • Mapped YARP ports to closest analogue, hybrid node/topic pairs.
  • Phase 3 - node support
    • Add ROS-like nodes to YARP.
    • Fully support ROS slave API so nodes written with YARP are indistinguishable on
    • network form nodes written with ROS.

Setup: Compiling YARP to support ROS

You'll need to turn the following flags on in CMake before (re-)compiling YARP:

* CREATE_OPTIONAL_CARRIERS (for support of ROS wire protocols)
* CREATE_IDLS (for support of ROS .msg/.srv files)

Those flags in turn create extra options, and the following should be turned on:

* ENABLE_yarpcar_tcpros_carrier (the usual protocol for topics)
* ENABLE_yarpcar_rossrv_carrier (tcpros with minor tweaks for services)
* ENABLE_yarpcar_xmlrpc_carrier (used by ros nameserver and node interfaces)
* ENABLE_yarpidl_rosmsg (a program to convert .msg/.srv files into YARP-usable form)

At some point, all these will become available by default, but that is not yet the case.

Setup: directing YARP clients to use the ROS name-server

To start with, it is simplest to configure YARP clients to use the ROS name server. Stop any yarpserver process you may have, and do the following:

  # optional - this avoids overwriting "normal" yarp configuration files
  yarp namespace /ros
  # find ROS name server, respecting ROS_MASTER_URI
  yarp detect --ros --write  

Just to describe in a little detail what happens here. YARP has a little configuration file (stored in the location reported by yarp conf) that lets all YARP-using programs know how to contact any name servers they need. For a ROS name server running on port 11311 (the default for ROS) on a machine with IP address, the configuration file should hold the following: 11311 ros

The "ros" tag tells the client what protocol to speak (if this is missing, a yarp-native protocol will be used by default). If the standard ROS_MASTER_URI environment variable is set correctly, then yarp detect --ros --write should prepare exactly this configuration for you.

One more step is desirable. ROS has its own type-system that depends on .msg/.srv files scattered around a ROS installation. To make those types available to YARP when needed, without having to have a working ROS installation on all machines, we can run a special "type server" on any one machine with a ROS installation:

  # give access to ROS type info to ROS-less machines
  yarpidl_rosmsg --name /typ@/yarpros

In fact, you can run this server on a machine *without* a ROS installation, and it will fall back on interrogating the http://docs.ros.org website for type information. This will work for types used in ROS packages documented on that site.

Trying things out: reading ROS topics

Let's start with a simple test reader:

 yarp read /msg@/test_node

For someone familiar with ROS, the "/msg@/test_node" syntax can be read as "use a topic name of /msg, and a node name of /test_node". We can check that everything looks familiar with rosnode and rostopic:

 $ rosnode list
 $ rostopic info /msg
 Type: unknown type
 Publishers: None
 * /test_node (... address ...)

As invoked, we didn't assign any particular type to the port/topic - this can be picked up from the sender. Try any of:

 rostopic pub /msg std_msgs/String "hello yarp"
 rostopic pub /msg turtlesim/Pose 0 5 10 15 20  

And you should see the messages print out on yarp read's console.

Trying things out: publishing to ROS topics

Let's start a ROS program to print out strings:

  $ rosrun roscpp_tutorials listener 

This program subscribes to a topic called "/chatter". Let's publish something there from YARP:

  $ yarp write /chatter@/yarp_writer
  yarp: Port /yarp_writer active at tcp://
  yarp: Port /chatter+@/yarp_writer active at tcp://
  yarp: Sending output from /chatter+@/yarp_writer to /listener using tcpros

Once we type a message (here "hello?") and hit return, we should see it echoed on the listener's console:

  [ INFO] [1386605949.838711935]: I heard: [hello?]

Under the hood, the yarp port has found the type of data expected (from the listener) and is matching what you enter with that type. If you try to send a number, you'll get a message like this:

  yarp: Structure of message is unexpected (expected std_msgs/String)

(If you actually want to send a string that looks like an integer, just put it in quotes). In this case, the listener is expecting a message of type std_msgs/String.

Trying things out: using ROS services

Let's start a ROS service that adds two integers:

 rosrun rospy_tutorials add_two_ints_server

This creates a service named /add_two_ints that expects two integers and gives back an integer. We can use it from yarp rpc, for example:

 $ yarp rpc /add_two_ints
 22 20
 Response: 42
 1 -10
 Response: -9

This looks straightforward, but it relies critically on YARP being able to determine ROS types. If you were to shut down the yarpidl_rosmsg server, here is what you would see:

 $ yarp rpc /add_two_ints
 Do not know anything about type 'rospy_tutorials/AddTwoInts'
 Could not connect to a type server to look up type 'rospy_tutorials/AddTwoInts'

With the type server running, YARP can make the needed translations. Let's try the opposite direction, setting up a ROS-style rpc server, for example this:

 $ yarp rpcserver /add_two_ints@/my_int_server --type rospy_tutorials/AddTwoInts

Notice that we specify a node name for the server here, and also we give the type of data it expects and returns (ROS-style clients expect us to know that). Now from ROS we can do:

 $ rosrun roscpp_tutorials add_two_ints_client 3 4

On the "yarp rpcserver" terminal we will now see:

 Waiting for a message...
 yarp: Receiving input from /add_two_ints_client to /add_two_ints-1@/my_int_server using tcpros
 Message: 3 4

It is waiting for us to reply. We can type in whatever number we like ("7" if we are feeling constructive), and it will be reported on the "roscpp_tutorials" terminal:

 [ INFO] [1386793386.003997149]: Sum: 7

Trying things out: sending/receiving simple messages from code

Please see "example/ros" in the YARP source code for full examples. For simple cases, we can just use YARP Bottles whose content matches ROS types. For example, to call a ROS service that adds two integers, we could do this (error checking abbreviated, see example/ros directory for full code):

 #include <stdio.h>
 #include <stdlib.h>
 #include <yarp/os/all.h>
 using namespace yarp::os;
 int main(int argc, char *argv[]) {
   if (argc!=3) return 1; // expect two integer arguments
   Network yarp;
   RpcClient client;
   if (!client.open("/add_two_ints@/yarp_add_int_client")) return 1;
   Bottle msg, reply;
   if (!client.write(msg,reply)) return 1;
   printf("Got %d\n", reply.get(0).asInt());
   return 0;

An example CMakeLists.txt file to compile this and link with YARP would be:

 cmake_minimum_required(VERSION 2.8.7)
 find_package(YARP REQUIRED)
 add_executable(add_int_client_v1 add_int_client_v1.cpp)
 target_link_libraries(add_int_client_v1 ${YARP_LIBRARIES})

On the ROS side we'd do:

 rosrun rospy_tutorials add_two_ints_server

Then on the YARP side we can try it out (assume the above program is compiled as add_int_client_v1):

 $ ./add_int_client_v1 4 6
 yarp: Port /yarp_add_int_client active at tcp://
 yarp: Port /add_two_ints+1@/yarp_add_int_client active at tcp://
 Got 10

Now looking at the code, there are some things to note. We use an RpcClient. This is a regular yarp Port, configured for writing to a single target. Equivalently we could have used this:

 Port client;

If we try to use a regular port without telling YARP how we'll be using it (by calling one of setRpcClient(), setRpcServer(), setWriteOnly(), setReadOnly()), YARP will complain because it won't know how to describe it to ROS. However, if you have a YARP-using program that you can't easily modify to add such a call, you can sneak the needed information into the port name.

ROS idea Call needed to specialize a Port/BufferedPort Or add this decoration before "@" in port name Pre-specialized class
Topic Subscriber port.setWriteOnly() - (none)
Topic Publisher port.setReadOnly() + (none)
Service port.setRpcServer() -1 yarp::os::RpcServer
Client port.setRpcClient() +1 yarp::os::RpcClient

For new code, it may be convenient to create ROS-like nodes explicitly rather than having names that bundles node and topic/service names together. YARP now has a yarp::os::Node class that can be used like this (modifying our example for adding two integers):

 #include <stdio.h>
 #include <stdlib.h>
 #include <yarp/os/all.h>
 using namespace yarp::os;
 int main(int argc, char *argv[]) {
   if (argc!=3) return 1; // expect two integer arguments
   Network yarp;
   Node node("/yarp_add_int_client");
   RpcClient client;
   if (!client.open("add_two_ints")) return 1;  // names that omit leading "/" belong to node
   Bottle msg, reply;
   if (!client.write(msg,reply)) return 1;
   printf("Got %d\n", reply.get(0).asInt());
   return 0;

Here's a YARP equivalent of the ROS listener/talker tutorial:

 // listener
 #include <stdio.h>
 #include <yarp/os/all.h>
 using namespace yarp::os;
 int main(int argc, char *argv[]) {
   Network yarp;
   Node node("/yarp/listener");
   Port port;
   if (!port.open("chatter")) return 1;
   while (true) {
     Bottle msg;
     if (!port.read(msg)) continue;
     printf("Got [%s]\n", msg.get(0).asString().c_str());
   return 0;
 // talker
 #include <stdio.h>
 #include <yarp/os/all.h>
 using namespace yarp::os;
 int main(int argc, char *argv[]) {
   Network yarp;
   Port port;
   if (!port.open("/chatter@/yarp/talker")) return 1;
   for (int i=0; i<1000; i++) {
     char buf[256];
     sprintf(buf,"hello ros %d", i);
     Bottle msg;
     printf("Wrote: [%s]\n", buf);
   return 0;

One thing to watch out for is that if you stop a program using ^C or if it crashes, YARP will not yet unregister your ports with ROS. If this bothers you, either add a signal handler, or run "rosnode cleanup" from time to time - and my apologies.

Trying things out: sending/receiving complicated messages from code

When dealing with larger, more complex messages (e.g point clouds), Bottles get awkward and it is desirable to be able to access parts of the message in a more structured way. For this case, you can use the yarpidl_rosmsg program. We met this program before when we ran it as a type server. We can also use it as a utility to translate ROS .msg/srv files into YARP-compatible header files. Given a .msg file (or a type name that rosmsg can find), yarpidl_rosmsg will produce a C++ class that implements the yarp::os::Portable interface and so can be written to or read from a YARP port. Likewise for a .srv file. If the file uses nested types, a header file will be generated for each type needed.

As a very simple example, to translate the AddTwoInts type we've been using in examples, we could do:

  yarpidl_rosmsg --web true rospy_tutorials/AddTwoInts

(I use --web true because I'm testing on a machine without a full ROS install; if you have all the needed packages then that could be omitted). This would generate the following header file:

 class rospy_tutorials_AddTwoInts : public yarp::os::Portable {
   // ...
   yarp::os::NetInt64 a;
   yarp::os::NetInt64 b;
   bool read(yarp::os::ConnectionReader& connection) { ... }
   bool write(yarp::os::ConnectionWriter& connection) { ... }

Note we can directly access to 64-bit integers, a and b, and have read/write serialization methods that YARP ports can use. We also get a class for the reply:

 class rospy_tutorials_AddTwoIntsReply : public yarp::os::Portable {
   // ...
   yarp::os::NetInt64 sum;
   bool read(yarp::os::ConnectionReader& connection) { ... }
   bool write(yarp::os::ConnectionWriter& connection) { ... }

In code, we could use an AddTwoInts service as follows:

 rospy_tutorials_AddTwoInts msg;
 rospy_tutorials_AddTwoIntsReply reply;
 msg.a = 20;
 msg.b = 22;
 printf("Sum: %d\n", reply.sum);  // should print 42

Code generation can be automated using the yarp_idl_to_dir macro, for example:

 set(generated_libs_dir "${CMAKE_CURRENT_BINARY_DIR}")
 yarp_idl_to_dir(Demo.msg ${generated_libs_dir})

See src/idls/rosmsg/tests/demo/ in the YARP source code for examples of usage.

Phase 3

Prerequisites - YARP configured with these flags turned on in CMake:


Those flags in turn create extra options, and the following should be turned on:

* ENABLE_yarpcar_tcpros_carrier
* ENABLE_yarpcar_rossrv_carrier
* ENABLE_yarpcar_xmlrpc_carrier
* ENABLE_yarpidl_rosmsg

YARP (master) has been extended to give ports slots for storing type information, data direction, and other properties that ROS cares about. Simple ports that transmit a fixed type of data in a particular direction (input or output) now look a lot more familiar to ROS. An equivalent of a ROS node has been added to YARP, rather than making every port a node as in Phase 2.

Nodes can be used in YARP in two ways. The first is a backwards-compatible way, relying on a new naming convention for ports (this way is implemented). The second uses a few new methods (this way is under development).

If a port name contains the "@" character, then that name is interpreted as a node-name and topic/service-name pair. For example:

   yarp read /msg@/reader

will create a node called "/reader" that subscribes to a topic called "/msg". On a machine with ROS installed, you can check this with:

   rosnode list
   rosnode info /reader
   rostopic list
   rostopic info /msg

We could send a message to this port from ROS (assuming we are using a ROS nameserver) as follows:

   rostopic pub /msg std_msgs/String "hello world"


  yarp write /msg@/writer

will create a node called "/writer" that publishes to a topic called "/msg". For this to communicate with ROS programs, we'd also need to specify a type, for example:

  yarp write /msg@/writer --type std_msgs/String

YARP has a direct understanding of a small number of ROS types, but for more it needs a "type server" to run on a computer with ROS installed. Run this (the "/typ" service name is important, the node name is not):

  yarpidl_rosmsg --name /typ@/ros/type/server

The following demos should now work:

  # DEMO: image stream from YARP to ROS
  # Should see red line scrolling down image_view viewer
  yarpdev --device test_grabber --name /test_grabber=/camera/image
  rosrun image_view image_view image:=/camera/image
  # DEMO: image stream from ROS to YARP
  # I just wrote a quick program...
  yarpview /whatever/the/image/topic/is@/yarpview
  # DEMO: basic read/write
  rosrun rospy_tutorials listener
  yarp write /chatter@/ros/check/write --type std_msgs/String
  # DEMO: basic write/read
  rosrun rospy_tutorials talker
  yarp read /chatter@/ros/check/read
  # DEMO: manipulating turtle demo
  rosrun turtlesim turtlesim_node
  yarp read /turtle1/pose@/foo  # should show a stream of poses
  yarp rpc /turtle1/teleport_absolute # give x y theta e.g. "6.0 3.0 0.5"
  yarp rpc /reset  # hit enter to send a blank message and do reset

Possible examples for an API for when writing new code:

  Node node("/producer");
  Publisher<Vector> data("readings");  // "readings" acts as a topic name
  // "data" is written to just like a BufferedPort
  Node node("/consumer");
  Subscriber<Vector> data("readings");
  // "data" is read from like a BufferedPort

Phase 2



ROS vs roscore

"ROS" is a framework, aggregating a lot of stuff. The ROS middleware is called "roscore", and is just one part of ROS. It is the component of ROS most comparable to YARP. It will be referred to in the rest of this document as ROSCORE.

Using YARP and ROSCORE in the same program

There is no obstacle to using YARP and ROSCORE in the same program. Programs that use ROSCORE are in practice likely to be built using ROS's own build system, which is layered on CMake. Since YARP can be linked to like any regular library, and has good support for doing so from CMake, there is no problem integrating at this level. A frequent source of conflict between middleware can be in automatic code-generation steps (e.g. for generating functions/classes encoding message types). YARP has historically refrained from having such code-generation, specifically so that it remains "just a library" from the perspective of integration. YARP has been packaged as a library within the ROS package management system:


When using two types of middleware in one program, an importance concern is whether they can work together efficiently. For example, translation between data types could be complicated. This matters most for large objects such as images. YARP has deliberately designed large data types with an eye to this problem. For images, the YARP image type is structured to match the format of an "IplImage", a venerable format that has longe since been propagated to the popular OpenCV library. OpenCV is the image processing library adopted by ROS, and so YARP and ROS images share a common underlying format. This fact is used in this package (in fact the conversion here is a sub-optimal, containing an avoidable copy):


Note that the use of YARP and ROSCORE in the same program strongly implies use of the ROS build system. This has consequences. That program will be a lot less portable than if it used YARP alone (ROS developers concentrate on Ubuntu Linux) and will be less usable from frameworks that are incompatible with ROS.

Using YARP and ROSCORE on the same network

YARP and ROSCORE provide for inter-process communication. If they had compatible protocols, then programs using YARP and programs using ROSCORE could communicate with each other. For example, one use case for this would be to make the iCub robot (whose software is written with YARP) directly accessible from programs written using the ROS framework. More generally, a non-ROS-using program (e.g. on an unsupported OS or using an incompatible framework) could be made to communicate with ROS programs via YARP.

YARP has been deliberately designed with interoperability in mind, with a plugin system of "carriers" (network protocols) that allows for great variety in how logical data flow translates into network traffic. Some preliminary work has been done to add "carriers" for ROSCORE traffic into YARP. This is done *without* linking to ROS libraries, since doing so would reduce the portability of YARP.

The XML/RPC carrier

Administrative messages in ROSCORE are transmitted using XML/RPC. Specifically, this protocol is used by ROSCORE when communicating with the roscore "master" entity, and with "slave" entities associated with each node. These messages do not carry user data, but are essential to finding out how to reach named entities on the network, making and breaking connections, and other administrative tasks.

An "xmlrpc_carrier" plugin has been added to YARP. This means that all YARP "Ports" can now act as XML/RPC servers and clients.

YARP user data, when sent to or received from a carrier, is expressed in a logical format called the "Bottle" format, which can be thought of to a first approximation as an s-expression in Lisp -- nested lists containing sequences of primitives. This format is easy to map onto the XML model used by the "XmlRpc++" library, which is the XML parser used by ROS and by the xmlrpc_carrier plugin. Here is the mapping:

* XML/RPC integer <-> Bottle integer
* XML/RPC double (floating point number) <-> Bottle double (floating point number)
* XML/RPC string <-> Bottle string
* XML/RPC blobs <-> Bottle blobs
* XML/RPC array <-> Bottle list
* XML/RPC structure <-> Bottle list

XML/RPC structures are sets of key/value pairs. These are mapped to a list with the tag "dict" as the first element, followed by sublists with key->value mappings:

 (dict (key1 val1) (key2 val2))

With some care, the mapping can be made exact, and means that no new types need to be added to YARP in order to conveniently represent data transfer to/from XML/RPC server/clients. So it is now easy to communicate from YARP to the roscore "master" and node "slaves"; it is also possible to have YARP ports pose as ROS "slaves" (or theoretically the "master").

For example, once this carrier is available, here is how YARP can be used from the commandline to look up the address of a ROSCORE entity called "/talker". We assume the roscore "master" server is running on the machine called "zimba", on port number 11311:

 # for convenience, give the roscore master a name ("/roscore") in the YARP network
 yarp name register /roscore tcp zimba 11311
 # send a look-up message, following the master API
 echo "lookupNode yarp_contact_id /talker" | yarp rpc xmlrpc://roscore

This result is printed:

 1 "node api" "http://contact:37291/"

So we know that the entity "/talker" can be reached on the machine "contact" on port number 37291, speaking "http" (this means XML/RPC). We can in turn talk to that entity using XML/RPC to get information about it or to prod it into making connections.

The command-line operation above can be trivially converted to code. Such operations are not intended for end-users, it is given here just to show some detail of this aspect of interoperability.

The TCPROS carrier

User data transmitted between ROS programs is typically carried to the "TCPROS" protocol. This is much more efficient than XML/RPC. A carrier called tcpros_carrier has been added to YARP in order to speak this protocol. We deal here with transmitting user data as an uninterpreted binary blob from YARP to ROSCORE or from ROSCORE to YARP. The issue of how that data can be correctly interpreted on both sides needs to be separately addressed.

There are two very different kinds of data flow that may be happening across a TCPROS connection, from ROSCORE's perspective:

  • "Service" data - essentially an RPC command/reply data flow initiated by a client, directed at a server.
  • "Topic" data - a stream of data from one "publisher" to one "subscriber". Initiation of this stream is a little complicated.

We can use regular YARP ports to act as publishers, subscribers, service-servers and service-clients. The ROS notion of a "Topic" is addressed separately; in summary it just affects the initiation/termination of connections and doesn't materially affect what a carrier needs to do.

There is not much that a tcpros_carrier needs to do. Here's what it does:

  • Produce/consume TCPROS headers (a list of "key=value" strings). The headers may need to include side information, such as the name of the ROS topic; such information is passed to the carrier using "carrier modifiers".
  • We choose to produce/consume a small header on the YARP side of a connection, for compatibility with the Bottle format on that side. This header does not need to be transmitted, it is in effect "virtual". It could be eliminated, but has been convenient for testing.

As an example: suppose we want to use a ROS service that adds two 64-bit integers and gives back a 64-bit result. Here's how to do it from the command line: (we assume that the "/roscore" master has been registered in YARP as in the example earlier)

Maybe we should better explain that in this case we use separate nameservers and manually make ros resources visible to yarp.
 echo "lookupNode dummy_caller_id /add_two_ints_server" | yarp rpc xmlrpc://roscore
 [prints] 1 "node api" "http://contact:37291/"
 yarp name register /add_two_ints_server tcp contact 37291
 echo "requestTopic dummy /add_two_ints ((TCPROS))" | yarp rpc xmlrpc://add_two_ints_server
 [prints] 1 "" (TCPROS contact 38265)
 yarp name register /adder tcp contact 38265
 echo "{ 8 0 0 0   0 0 0 0   2 0 0 0   0 0 0 0}" | yarp rpc tcpros+service./add_two_ints://adder
 # we get back { 10 0 0 0 0 0 0 0 }, which is 8 + 2

The syntax tcpros+service./add_two_ints tells the yarp port to use the protocol tcpros and the that we talk to a service on node /add_two_ints.

As another example: suppose we wanted to receive messages from a ROS node called "/talker" that outputs messages on the "/chatter" topic. Let's start a simple YARP program to consume such messages:

 yarp read /read  # or make a program with an input port

Now to connect it up we would do something like:

 echo "lookupNode dummy_id /talker" | yarp rpc xmlrpc://roscore
 [prints] 1 "node api" "http://contact:37291/"
 yarp name register /talker tcp contact 37291
 echo "requestTopic dummy_id /chatter ((TCPROS))" | yarp rpc xmlrpc://talker
 [prints] 1 "" (TCPROS contact 38265)
 yarp name register /talker/chatter tcp contact 38265
 yarp connect /read /talker/chatter tcpros+topic./chatter

The "yarp read" program should now show a stream of binary blobs rendered in text format, corresponding to the strings generated by "/talker".

How about sending messages to a ROS subscriber? It turns out the subscriber has to be convinced to initiate this connection, and will first need to talk to a "slave" node via XML/RPC. This can easily be achieved in YARP by a temporary port. See the example in the README.TXT bundled with the tcpros_carrier in YARP.

It is clear that connection initiation between YARP and ROS requires some orchestration. For the moment, the necessary logic has been bundled into a simple helper program called "yarpros", which currently has the following functionality:

yarpros roscore <hostname> <port number>
 -- tell yarp how to reach the ros master
 -- example: yarpros roscore 11311
 yarpros import <name>
 -- import a ROS name into YARP
 -- example: yarpros import /talker
 yarpros read <yarpname> <nodename> <topicname>
 -- read to a YARP port from a ROS node's contribution to a topic
 -- example: yarpros read /read /talker /chatter
 yarpros write <yarpname> <nodename> <topicname>
 -- write from a YARP port to a ROS node's subscription to a topic
 -- example: yarpros write /write /listener /chatter
 yarpros rpc <yarpname> <nodename> <servicename>
 -- write/read from a YARP port to a ROS node's named service
 -- example: yarpros rpc /rpc /add_two_ints_server /add_two_ints

Note that the connection initiation used so far is experimental, and just enough to get going. There are plenty of improvements to be made, such as telling the ROS master about what is going on rather than just working around it :-).

Image carrier

Images in YARP are generally transmitted across regular carriers, with no special treatment (other than using multicast when appropriate). It can be useful to have special carriers that transform images in some way, e.g. by compressing them. The "mjpeg_carrier" in YARP does this, for example. Matching a special purpose image carrier in YARP and ROS remains to be investigated, but there are in principle no obstacles to this. Image communication is treated separately in ROS, see:


Image translation to/from network representations by a custom carrier, if done with a little care, does not require copies of the image data to be made. So in principle this type of traffic should be efficient.


The ROSCORE notion of "topic", at first sight, looks like a big difference in abstraction between YARP and ROS. Luckily it is trivial to implement topics with yarp ports. A topic can be seen as a virtual port that connects all its source ports (publishers in ROS-speak) to all its destination ports (subscribers in ROS-speak). A small bit of logic has been added to the yarp name server in implement such virtual ports.

A larger issue is that the ROS "master" tracks a lot more information about the activity of each network entity than YARP's name server does. It remains to be investigated how much a "foreign" program needs to tell the ROS master about its activities in order to interoperate fully.


The YARP network data format is self-describing. Each messages contains sufficient type-tags to interpret that message without any other information. This is less efficient than factoring out type data. But in practice efficiency is mostly a concern when the message is large - and large messages usually contain large lists of homogeneous data, requiring just a few bytes of type data.

The ROSCORE network data format is self-deliminating (it contains its size) but is otherwise a binary blob. A type name is sent at the start of a connection. This means that interpreting messages in practice requires on IDL, with generated code, implying a special build system, implying a framework, implying lower portability of user code. But this approach is more efficient than including type information with each message.

ROSCORE's message types could be sent from or received by a YARP port with ease, if that program could make use of code generated by ROS utilities. With some hacks, it is possible to do this without using ROS's build system; this could potentially be better packaged. An alternative would be to independently implement a parser of ROS message/service definition files.

A subset of YARP message types of a fixed structure can be defined with a ROS definition file, and then read/written easily from ROSCORE-using programs.

In general, the type issue remains to be investigated. The challenges in making systematic solution shouldn't obscure the fact that specific solutions for needed connections can be easily solved *now*, with a little bit of manual effort.


YARP and ROS are used together in different scenarios. We illustrate them here to better clarify how they can be implemented.


Yarp and ROS store names in separate servers (yarpserver and roscore), information on the nameservers need to be visible to both systems.

  1. YARP and ROS use roscore. This solution is good for ROS users but can have certain limitations because in yarp the yarpserver may need to perform certain operations (e.g. mcast) (is this still true?).
  2. YARP and ROS use each its own nameserver. ROS uses only roscore. YARP registers names on both. At the moment this seems to be the better solutions for users, because it does not give users the feeling they are using a different system (or a subset of) (YARP users may not trust ROS and viceversa).

The basic logic is that YARP-using programs will "register everywhere and query anywhere":

  • ROS will ignore yarpserver (since it knows nothing about it). So all non-YARP programs will be registered with roscore only.
  • YARP-using programs will register with *both* yarpserver and roscore.
  • YARP-using programs, when doing queries, with check with each nameserver in whatever order they are listed when you did "yarp namespace /n1 /n2". It will return the first valid response found.


  • YARP subscribes to an existing ROS topic. YARP needs to know type information, via yarpidl_rosmsg produces a Portable object that can be connected to the topic.
  • YARP publish to an existing ROS topic. YARP needs to know type information, again this goes through yarpidl_rosmsg and a dedicated Portable.
  • ROS needs to talk to an existing YARP port. This is a little more tricky, we distinguish:
    • Ports without replies
    • Ports with replies