forked from robotology/yarp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnote-ports.dox
470 lines (400 loc) · 14.3 KB
/
note-ports.dox
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
/**
* \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="tcp" ];
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="tcp" ];
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.
*/