YARP built-in types can be sent through Ports.
Sometimes you need to send custom datatypes, in YARP objects that can be sent through ports are called portable objects. Port Power, Going Further with Ports shows how you can manually implement a portable object.
For ROS interoperability YARP supports ROS msg types. In this tutorial we see how you can automatically generate YARP portable objects using ROS syntax. The advantage in this case is that your type is compatible with ROS and can be directly read from a topic.
Suppose we have two modules that wish to share a SharedData \m struct that contains a string and a vector. Normally you would define the data in a C++ header file and write serialization/deserialization methods to allow it to be sent and received to/from a port (this process is called marshalling/demarshalling). This process requires some YARP specific expertise, is error-prone and tedious. The idea here is that instead of manually writing the class you define the structure using the ROS syntax, then you ask a compiler (called yarpidl_rosmsg) to generate the class for you, including all the required code. Because you use the ROS syntax this type is also compatible with ROS and can be read from a topic.
Let's see how to do it.
We start by defining our ShareData structure. Open a text editor and type the following:
name this file SharedData.msg save and close it.
In ROS this specifies that SharedData is a struct that contains a text field of type string and a content field which type is a vector of double precision floating point numbers. ROS in fact supports much more options, see http://wiki.ros.org/msg.
Now you can convert the ROS type in a YARP compatible type.
Type:
This is the output you shuld get:
This will generate one file: yarp/rosidl/SharedData.h
In case you are interested you can inspect it to see that it defines a C++ class with some extra code. The good thing is that you don't actually need to bother about the details, but you can readily use the class in your code.
Now we can use these files in your YARP programs. We now write a sender and a receiver.
This code is straightforward. We define a sender executable that opens a port and periodically writes a yarp::rosidl::SharedData object and a receiver that opens a port and receives the same message type.
As usual we start with the CMake code, write your CMakeLists.txt:
Now we write the code for the sender in sender.cpp:
Now compile the code
Now you can run yarp read on a separate console to inspect the content that is being transmitted on the port, the output should be something like this (you'll need a very recent version of YARP for this to work - if it doesn't just skip it):
It is simple to write a receiver:
Append the following to the CMakeLists.txt
Now we write the code for the receiver in receiver.cpp:
Compile, and start the receiver, with the sender running:
YARP provides CMake supports to automate the invocation of yarpidl_rosmsg. This is convenient in large projects when we generate several files and we do not want to keep track of all of them individually.
Edit the file CMakeLists.txt:
We now tell CMake to parse SharedData.msg with the rosmsg compiler. All generated files will be placed in separate include and src directories.
The first time you run CMake it will produce a file SharedData_msg.cmake that contains all generated files. This file can be used to compile our executables, i.e.:
Now you just have to execute CMake. The variable ALLOW_IDL_GENERATION controls if the rosmsg compiler is executed to generate SharedData.h or not. Notice that the first time you run cmake you have to enable this flag otherwise compilation will fail because SharedData.h will be missing.
The code generation step is required only when SharedData.msg is modified.
This tutorial continues with:
More information on interoperatiblity with ROS can be found here: Using YARP with ROS
The Thrift IDL allows defining portable objects and modules interfaces with YARP native types:
Code for this tutorial can be found here: example/idl/rosportable