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:
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:
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:
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:
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):
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:
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:
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).
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.