📄 note-ports.dox
字号:
/**
* \page note_ports Getting Started with YARP Ports
\section note_ports_network A network of ports
Communication in YARP generally follows the <i>Observer</i> design
pattern. Special <i>port</i> 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
digraph tracker_example1 {
graph [ rankdir = "LR" ];
node [shape=box, fontname=Helvetica, fontsize=10];
edge [fontname=Helvetica, fontsize=10, arrowhead="open", style="solid"];
subgraph cluster_machine1 {
style = "invis";
subgraph cluster_camera {
style = "invis";
camera [ label="/camera", shape=ellipse];
}
subgraph cluster_tracker {
style = "invis";
tracker_position [ label="/tracker/position",
shape=ellipse];
tracker_image [ label="/tracker/image", shape=ellipse];
}
}
subgraph cluster_machine2 {
style = "invis";
subgraph cluster_motor {
style = "invis";
motor_position [ label="/motor/position", shape=ellipse];
}
}
subgraph cluster_machine3 {
style = "invis";
subgraph cluster_viewer1 {
style = "invis";
viewer1 [ label="/viewer1", shape=ellipse];
}
subgraph cluster_viewer2 {
style = "invis";
viewer2 [ label="/viewer2", shape=ellipse];
}
}
//connections
camera -> viewer1;
camera -> tracker_image;
tracker_image -> viewer2;
tracker_position -> motor_position;
fontname=Helvetica;
fontsize=10;
label = "An example of a network of ports";
}
\enddot
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:
\li TCP: reliable, it can be used to guarantee the reception
of a message;
\li UDP: faster than TCP, but without guarantees;
\li multicast: efficient for distributing
the same information to large numbers of targets;
\li 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
digraph tracker_example2 {
graph [ rankdir = "LR" ];
node [shape=box, fontname=Helvetica, fontsize=10];
edge [fontname=Helvetica, fontsize=10, arrowhead="open", style="solid"];
subgraph cluster_machine1 {
style = "invis";
subgraph cluster_camera {
label = "yarpdev";
color = "black"; style = "solid";
camera [ label="/camera", shape=ellipse];
}
subgraph cluster_tracker {
label="tracker";
color = "black"; style = "solid";
tracker_position [ label="/tracker/position",
shape=ellipse];
tracker_image [ label="/tracker/image", shape=ellipse];
}
}
subgraph cluster_machine2 {
style = "invis";
subgraph cluster_motor {
color = "black"; style = "solid";
label = "motor_control";
motor_position [ label="/motor/position", shape=ellipse];
}
}
subgraph cluster_machine3 {
style = "invis";
subgraph cluster_viewer1 {
color = "black"; style = "solid";
label="yarpview";
viewer1 [ label="/viewer1", shape=ellipse];
}
subgraph cluster_viewer2 {
color = "black"; style = "solid";
label="yarpview";
viewer2 [ label="/viewer2", shape=ellipse];
}
}
//connections
camera -> viewer1 [ label="mcast" ];
camera -> tracker_image [ label="mcast" ];
tracker_image -> viewer2 [ label="udp" ];
tracker_position -> motor_position [ label="shmem" ];
fontname=Helvetica;
fontsize=10;
label = "Ports belong to processes, and connections can use different protocols";
}
\enddot
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
digraph tracker_example3 {
graph [ rankdir = "LR" ];
node [shape=box, fontname=Helvetica, fontsize=10];
edge [fontname=Helvetica, fontsize=10, arrowhead="open", style="solid"];
subgraph cluster_machine1 {
label = "machine 1 (Linux)";
color = "blue"; style = "dashed";
subgraph cluster_camera {
label = "yarpdev";
color = "black"; style = "solid";
camera [ label="/camera", shape=ellipse];
}
subgraph cluster_tracker {
label="tracker";
color = "black"; style = "solid";
tracker_position [ label="/tracker/position",
shape=ellipse];
tracker_image [ label="/tracker/image", shape=ellipse];
}
}
subgraph cluster_machine2 {
label = "machine 2 (Linux)";
color = "blue"; style = "dashed";
subgraph cluster_motor {
color = "black"; style = "solid";
label = "motor_control";
motor_position [ label="/motor/position", shape=ellipse];
}
}
subgraph cluster_machine3 {
label = "machine 3 (Windows)";
color = "blue"; style = "dashed";
subgraph cluster_viewer1 {
color = "black"; style = "solid";
label="yarpview";
viewer1 [ label="/viewer1", shape=ellipse];
}
subgraph cluster_viewer2 {
color = "black"; style = "solid";
label="yarpview";
viewer2 [ label="/viewer2", shape=ellipse];
}
}
//connections
camera -> viewer1 [ label="mcast" ];
camera -> tracker_image [ label="mcast" ];
tracker_image -> viewer2 [ label="udp" ];
tracker_position -> motor_position [ label="shmem" ];
fontname=Helvetica;
fontsize=10;
label = "Ports can be on different machines and OSes";
}
\enddot
\section note_ports_example A worked example
Make sure you've followed the instructions for installing and testing
your YARP configuration on the website (http://yarp0.sourceforge.net).
Now start some three terminals and do the following:
\verbatim
[on terminal 1] yarp server
[on terminal 2] yarp read /read
[on terminal 3] yarp write /write /read
\endverbatim
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:
\verbatim
10 -5 17.15 6
\endverbatim
you will see the same on terminal 2:
\verbatim
10 -5 17.15 6
\endverbatim
Our network so far is very simple:
\dot
digraph read_write_example {
graph [ rankdir = "LR" ];
node [shape=box, fontname=Helvetica, fontsize=10];
edge [fontname=Helvetica, fontsize=10, arrowhead="open", style="solid"];
subgraph cluster_read {
label = "yarp read";
color = "black"; style = "solid";
read [ label="/read", shape=ellipse];
}
subgraph cluster_write {
label="yarp write";
color = "black"; style = "solid";
write [ label="/write", shape=ellipse];
}
//connections
write -> read [ label="tcp" ];
fontname=Helvetica;
fontsize=10;
label = "Simple read-write example";
}
\enddot
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.cpp" in the YARP source):
\include example/os/summer.cpp
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):
\verbatim
[on terminal 4] ./summer
[on terminal 5] yarp connect /write /summer
[on terminal 5] yarp connect /summer /read
\endverbatim
(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
digraph read_write_example {
graph [ rankdir = "LR" ];
node [shape=box, fontname=Helvetica, fontsize=10];
edge [fontname=Helvetica, fontsize=10, arrowhead="open", style="solid"];
subgraph cluster_read {
label = "yarp read";
color = "black"; style = "solid";
read [ label="/read", shape=ellipse];
}
subgraph cluster_summer {
label="summer";
color = "black"; style = "solid";
summer [ label="/summer", shape=ellipse];
}
subgraph cluster_write {
label="yarp write";
color = "black"; style = "solid";
write [ label="/write", shape=ellipse];
}
//connections
write -> read [ label="tcp" ];
write -> summer [ label="tcp" ];
summer -> read [ label="tcp" ];
fontname=Helvetica;
fontsize=10;
label = "Adding the \"summer\" program";
}
\enddot
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:
\verbatim
10 -5 17.15 6
\endverbatim
on terminal 2 ("yarp read"), you will see:
\verbatim
10 -5 17.15 6
total 28.15
\endverbatim
(the order of these messages is random).
We can get rid of the original connection from "/write" to "/read" with:
\verbatim
[on terminal 5] yarp disconnect /write /read
\endverbatim
Now if on terminal 3 ("yarp write") you type:
\verbatim
10 -5 17.15 6
\endverbatim
on terminal 2 ("yarp read"), you will see just:
\verbatim
total 28.15
\endverbatim
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 <i>multicast</i> 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:
\verbatim
yarp disconnect /summer /read
yarp connect /summer /read mcast
\endverbatim
The network is now as follows:
\dot
digraph read_write_example {
graph [ rankdir = "LR" ];
node [shape=box, fontname=Helvetica, fontsize=10];
edge [fontname=Helvetica, fontsize=10, arrowhead="open", style="solid"];
subgraph cluster_read {
label = "yarp read";
color = "black"; style = "solid";
read [ label="/read", shape=ellipse];
}
subgraph cluster_summer {
label="summer";
color = "black"; style = "solid";
summer [ label="/summer", shape=ellipse];
}
subgraph cluster_write {
label="yarp write";
color = "black"; style = "solid";
write [ label="/write", shape=ellipse];
}
//connections
write -> summer [ label="tcp" ];
summer -> read [ label="mcast" ];
fontname=Helvetica;
fontsize=10;
label = "Manipulating connections";
}
\enddot
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).
\section note_ports_closer 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:
\verbatim
[you type] yarp name query /summer
[response] registration name /summer ip 5.255.222.252 port 10012 type tcp
*** end of message
\endverbatim
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:
\verbatim
[you type] yarp name get /summer accepts
[response] port /summer property accepts = tcp text text_ack udp mcast shmem
*** end of message
\endverbatim
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:
\verbatim
telnet localhost 10012
\endverbatim
This gives us a TCP connection to the port. Now let's request we
switch to "text" mode by typing:
\verbatim
CONNECT anonymous
\endverbatim
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:
\verbatim
Welcome anonymous
\endverbatim
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:
\verbatim
d
10 20 30
\endverbatim
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.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -