YARP
Yet Another Robot Platform
Getting Started with YARP Ports

A network of ports

Communication in YARP generally follows the Observer design pattern. Special port objects deliver messages to any number of observers (other ports), in any number of processes, distributed across any number of machines, using any of several underlying communication protocols. Here is a very simple network of ports for a visual tracking application:

dot_inline_dotgraph_2.png

Images are transmitted from a camera ("/camera") port to a viewer ("/viewer1") port and the input of a visual tracker ("/tracker/image"). The tracker annotates the image, for example by placing a marker on a tracked point, and transmits that to another viewer ("/viewer2"). The tracker also sends just the tracked position from a position output port ("/tracker/position") to a input controlling head position ("/motor/position"). Every port belongs to a process. They do not need to belong to the same process. Every connection can take place using a different protocol and/or physical network. The use of several different protocol allows us to exploit their best characteristics:

  • TCP: reliable, it can be used to guarantee the reception of a message;
  • UDP: faster than TCP, but without guarantees;
  • multicast: efficient for distributing the same information to large numbers of targets;
  • shared memory: employed for local connections (selected automatically whenever possible, without the need for programmer intervention); If messages follow follow YARP guidelines, then they can be automatically converted to and from a "text mode" connection, for easy human monitoring and intervention in the system.
dot_inline_dotgraph_3.png

Processes can be on different physical machines without a problem. They can also run under different operating systems and be implemented using different languages. If the message format follows YARP guidelines, then communication will not be a problem:

dot_inline_dotgraph_4.png

A worked example

Make sure you've followed the instructions for installing and testing your YARP configuration on the website (http://www.yarp.it). Now start some three terminals and do the following:

[on terminal 1] yarp server
[on terminal 2] yarp read /read
[on terminal 3] yarp write /write /read

We'll say a bit more about "yarp server" in the next section; for now it is enough to know that it acts as a database for port contact information. We can ignore it for now.

If you type a list of numbers on terminal 3 ("yarp write"), they will show up on terminal 2 ("yarp read"), e.g. if you type on terminal 3:

10 -5 17.15 6

you will see the same on terminal 2:

10 -5 17.15 6

Our network so far is very simple:

dot_inline_dotgraph_5.png

Now let's make a program that transforms the output of /write in some way, for example by adding up all the numbers in it. Here is a program for this ("example/os/summer/summer.cpp" in the YARP source):

/*
* Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
* Copyright (C) 2006-2010 RobotCub Consortium
* All rights reserved.
*
* This software may be modified and distributed under the terms of the
* BSD-3-Clause license. See the accompanying LICENSE file for details.
*/
#include <yarp/os/Bottle.h>
#include <iostream>
int main(int argc, char* argv[])
{
YARP_UNUSED(argc);
YARP_UNUSED(argv);
Network yarp;
BufferedPort<Bottle> port;
port.open("/summer");
while (true) {
yInfo() << "waiting for input";
Bottle* input = port.read();
if (input != nullptr) {
yInfo() << "got " << input->toString().c_str();
double total = 0;
for (size_t i = 0; i < input->size(); i++) {
total += input->get(i).asFloat64();
}
Bottle& output = port.prepare();
output.clear();
output.addString("total");
output.addFloat64(total);
yInfo() << "writing " << output.toString().c_str();
port.write();
}
}
return 0;
}

For now, there's no need to worry too much the details of this code. Start another two terminals and do the following (make sure the "yarp read" and "yarp write" programs started earlier are still running):

[on terminal 4] ./summer
[on terminal 5] yarp connect /write /summer
[on terminal 5] yarp connect /summer /read

(You may need to replace "./summer" with "summer.exe" or whatever the executable name of the compiled program is). The network is now as follows:

dot_inline_dotgraph_6.png

If you type a list of numbers the "yarp write" terminal, they will show up on the "yarp read" terminal as before. But they will also be sent to the "summer" process, which will send an extra message to the "yarp read" terminal. For example, if on terminal 3 ("yarp write") you type:

10 -5 17.15 6

on terminal 2 ("yarp read"), you will see:

10 -5 17.15 6
total 28.15

(the order of these messages is random).

We can get rid of the original connection from "/write" to "/read" with:

[on terminal 5] yarp disconnect /write /read

Now if on terminal 3 ("yarp write") you type:

10 -5 17.15 6

on terminal 2 ("yarp read"), you will see just:

total 28.15

Suppose we wanted to send the output of "summer" to many, many readers "/read1" "/read2" .... "/readN". To do that efficiently, we may want to use the multicast network protocol instead of tcp. We can do that easily. As an example, we just switch the output from "/summer" to "/read" to use multicast:

yarp disconnect /summer /read
yarp connect /summer /read mcast

The network is now as follows:

dot_inline_dotgraph_7.png

For this small example, you should see no change in performance from using multicast (unless your network interface just doesn't support it at all).

Taking a closer look

The first program we ran in the previous section was "yarp server". This is a simple database of information about a yarp network. We can, for example, find out some information about how to reach a port:

[you type] yarp name query /summer
[response] registration name /summer ip 5.255.222.252 port 10012 type tcp
           *** end of message

This tells us that the port called "/summer" is on a machine with IP address 5.255.222.252, is listening on socket port 10012, and expects any connection with it to be made initially using tcp. After this initial connection, we can request a YARP port to switch to a different protocol for that connection. To see what protocols the port will accept, we do:

[you type] yarp name get /summer accepts
[response] port /summer property accepts = tcp text text_ack udp mcast shmem
           *** end of message

We see for example that "tcp" and "mcast" are on this list. There's also a "text" protocol. This is to make it easier for a human to make connections manually. For example, we could easily connect to "/summer" with telnet using the socket number we discovered above:

telnet localhost 10012

This gives us a TCP connection to the port. Now let's request we switch to "text" mode by typing:

CONNECT anonymous

It is important to get the first 8 characters exactly right – they are the code that chooses the protocol. "CONNECT " is the code for the text protocol. Some versions of telnet won't show what you're typing, or let you delete, so be careful. If all goes well, the port will respond with:

Welcome anonymous

We won't cover all the things you can do with the port at this point; one thing you can do is send it some data. We can send the list of numbers (10,20,30) by typing:

d
10 20 30

On the terminal where "summer" is running, you should see those numbers appear, and their total should appear on "yarp read". Type "q" to disconnect.

In these examples, we've made use of the fact that "yarp read" and "yarp write" can work with a data type called a Bottle, which is particularly flexible – it is a (potentially nested) list of some primitive types like integers, doubles, and strings, with a well defined representation in binary and text form. But any kind of data can be send across a YARP network.

LogStream.h
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
Network.h
main
int main(int argc, char *argv[])
Definition: yarpros.cpp:261
YARP_UNUSED
#define YARP_UNUSED(var)
Definition: api.h:159
yarp::os::BufferedPort
A mini-server for performing network communication in the background.
Definition: BufferedPort.h:64
BufferedPort.h
yarp::os::Network
Utilities for manipulating the YARP network, including initialization and shutdown.
Definition: Network.h:786
yarp
The main, catch-all namespace for YARP.
Definition: environment.h:18
yInfo
#define yInfo(...)
Definition: Log.h:260
Bottle.h