前文链接
【轻量级开源ROS 的机器人设备(4)】--(2)通信实现_无水先生的博客-CSDN博客
六、数据流
数据流 虽然 XML-RPC 为远程方法调用提供了一种简单而干净的协议,但其冗长和以文本为中心的编码使其不适合高带宽和低延迟任务。数据流就是这种情况,例如由传感器或执行器发送的数据流。 ROS 为此类流定义了自定义二进制协议;这允许在节点之间传输原始数据,所需的消息长度最小(带宽最大化)并且几乎没有处理时间(延迟最小化)。有关主题和服务消息语法的详细信息 。
6.1 类型描述符
数据流基于特定类型的消息交换,在注册时由主题/服务指定(参见上一节)。消息是一系列值,按照类型描述符定义的顺序排列。 ROS中有两种,主题描述符和服务描述符。我们将首先考虑主题描述符,因为服务类型只是一个简单的扩展。 主题类型 ROS 主题消息描述符被编写为纯文本文件,其中文件名与类型名称一致,加上 .msg 扩展名。
每行都可以定义一个强类型变量,其中类型可以是原始类型,也可以是另一个消息类型描述符的名称,甚至可以是任何此类类型的数组(固定或变量)。因此,消息可以嵌套,并且由于是强类型,它们的流式传输得到简化(无需处理动态类型)。描述符还可以声明原始类型的常量名称。
清单 4.3 显示了 rosgraph_msgs/msg/Log.msg 的内容,而清单 4.4 是其干净的扩展版本,由 rosmsg show 生成。
服务类型 虽然主题是单向的,因此只需要定义一种消息类型,但服务以请求/响应方式工作
-
1
##
-
2
## Severity level constants
-
3
##
-
4
byte DEBUG=
1
#debug level
-
5
byte INFO=
2
#general level
-
6
byte WARN=
4
#warning level
-
7
byte ERROR=
8
#error level
-
8
byte FATAL=
16
#fatal/critical level
-
9
##
-
10
## Fields
-
11
##
-
12 Header header
-
13
byte level
-
14
string name
# name of the node
-
15
string msg
# message
-
16
string file
# file the message came from
-
17
string function
# function the message came from
-
18 uint32 line
# line the message came from
-
19
string[] topics
# topic names that the node publishes
Listing 4.3: Contents of rosgraph_msgs/msg/Log.msg
-
byte DEBUG=
1
-
2
byte INFO=
2
-
3
byte WARN=
4
-
4
byte
ERROR=
8
-
5
byte FATAL=
16
-
6 std_msgs/Header header
-
7 uint32 seq
-
8 time stamp
-
9
string frame_id
-
10
byte level
-
11
string name
-
12
string msg
-
13
string file
-
14
string
function
-
15 uint32 line
-
16
string[] topics
Listing 4.4: Clean, expanded contents of rosgraph_msgs/msg/Log.ms
因此,服务涉及两种类型,一种用于请求,一种用于响应。服务类型描述符的存储方式与主题类型类似,但扩展名为 .srv。描述符被 -- 分隔线分成两部分,其中第一部分是请求消息描述符,第二部分是响应消息描述符。清单 4.5 是 dynamic_reconfigure/srv/Reconfigure.srv 内容的示例,而清单 4.6 是其干净的扩展版本,由 rossrv show 生成。
散列 因为节点之间的描述符文本可能不同,而它们的名称可以相同,所以必须有一种方法来确定两个节点是否实际上共享相同的类型。对于此类任务,选择 MD5 和来比较两种不同的类型描述。比较函数对每个类型描述符执行以下操作:
1.评论被删除;
2. 去除空格;
3.去除依赖包名;
4. 常量移到变量声明之前,保持它们的排列;
5. 对于嵌套类型,计算它们的散列文本并按照它们出现的顺序附加到当前散列文本;
6.计算整个哈希文本的MD5和。如果 MD5 和相同,则两个描述符相等。
-
1 Config
config
-
2
---
-
3 Config
config
-
Listing
4.5: Contents of dynamic_reconfigure/srv/Reconfigure.srv
-
1 dynamic_reconfigure/Config config
-
2 dynamic_reconfigure/BoolParameter[] bools
-
3
string name
-
4
bool value
-
5 dynamic_reconfigure/IntParameter[] ints
-
6
string name
-
7
int32 value
-
8 dynamic_reconfigure/StrParameter[] strs
-
9
string name
-
10
string value
-
11 dynamic_reconfigure/DoubleParameter[] doubles
-
12
string name
-
13
float64 value
-
14 dynamic_reconfigure/GroupState[] groups
-
15
string name
-
16
bool state
-
17
int32 id
-
18
int32 parent
-
19 ---
-
20 dynamic_reconfigure/Config config
-
21 dynamic_reconfigure/BoolParameter[] bools
-
22
string name
-
23
bool value
-
24 dynamic_reconfigure/IntParameter[] ints
-
25
string name
-
26
int32 value
-
27 dynamic_reconfigure/StrParameter[] strs
-
28
string name
-
29
string value
-
30 dynamic_reconfigure/DoubleParameter[] doubles
-
31
string name
-
32
float64 value
-
33 dynamic_reconfigure/GroupState[] groups
-
34
string name
-
35
bool state
-
36
int32 id
-
37
int32 parent
-
Listing
4.6: Clean, expanded contents of dynamic_reconfigure/srv/Reconfigure.srv
-
ROS type C99 type
-
uint8
uint8_t
-
uint16
uint16_t
-
uint32
uint32_t
-
uint64
uint64_t
-
int8
int8_t
-
int16
int16_t
-
int32
int32_t
-
int64
int64_t
-
time
uros_time_t
-
duration
uros_time_t
-
string
struct
UrosString {
size_t length;
char *datap; };
-
type[]
struct
UrosTcpRosArray {
uint32_t length;
void *entriesp; };
-
byte
uint8_t
-
char
char
-
uint
uint32_t
-
int
int32_t
-
Table
4.1: ROS to C type mapping
6.2 消息数据结构:( Message structure )
消息以小端二进制形式序列化。这使得市场上大多数小端 CPU 架构(例如基于 x86 或 ARM 设计的架构)的处理变得简单。因此,数据流消息很像 C 结构变量的序列化;例如,在 x86 架构上,消息是变量本身的一对一转储,因为内存中的 8 位字段对齐(相比之下,ARM 内核为 32 位)。
基本类型可以直接映射到 C 类型,如表 4.1 所示。可变长度数组和字符串(字符数组)是一种特殊情况,因为它们提供 uint32 长度的条目数,后跟序列化条目本身。相比之下,固定长度数组被视为指定类型的条目序列。任何嵌套类型都被扩展为它们各自的基本类型或数组。
在刚刚描述的消息内容之前,uint32 值预计内容本身的总长度。
6.3 话题消息:Topic messages
主题消息简单地遵循上面描述的长度+内容方案,因为主题涉及相同类型的单向消息。 “你好,世界!”的一个例子std_msgs/String 类型的消息如图 4.4 所示。流偏移量以粗体字写为十六进制索引;如果可打印,值将写为 ASCII 字符,否则将写为十六进制数字。右侧的注释表示正在流式传输的特定字段及其人类可读的值。
-
00
01
02
03 uint32 message_length
-
11
00
00
00
17
-
04
05
06
07
08
09 0A 0B 0C 0D 0E 0F
10
11
12
13
14 string
data
-
0D
00
00
00
H e l l o ,
W o r l d !
13
"Hello, World!"
-
Figure
4.4:
Dump
of a
"Hello, World!" message
of
type std_msgs/String
-
00
01
02
03
uint32
message_length
-
10
00
00
00
16
-
04
05
06
07
08
09
0
A
0
B
int64
a
-
D2
04
00
00
00
00
00
00
1234
-
0
C
0
D
0
E
0
F
10
11
12
13
int64
b
-
2
E
16
00
00
00
00
00
00
5678
-
Figure
4.5:
Dump
of
a
call
to
service
of
type
rospy_tutorials/
AddTwoInts
服务消息 服务请求的序列化方式与主题消息相同。相反,响应的序列化需要考虑响应的状态,它可以是实际的响应值,也可以是错误消息。
在响应之前发送一个所谓的 ok 字节。如果为 1,则表示后面的流数据是预期的服务响应类型。如果为 0 则表示在处理请求时发生错误,后面的流值是字符串类型,代表人类可读的错误文本。
rospy_tutorials/AddTwoInts服务请求和响应示例如图4.5和图4.6所示。相反,可以在图 4.7 中看到报告未知错误的服务响应。
6.4 连接头 Connection header
一旦主题/服务客户端和相关服务器连接,它们就必须就流参数达成一致。它们包括主题/服务名称和类型、多个服务请求的可能性、带宽优化的使用等。所有这些参数都由连接标头设置,连接标头是两个端点在整个流的最开始发送的特殊消息。首先,客户端发送一个标头,作为一个请求。然后服务器将使用另一个标头进行回复,该标头充当响应。
连接标头由字段组成。它们像字符串一样被编码,因此告诉字符串长度的 uint32 在字符串字符之前发送。该值遵循 field=value 格式,其中可用字段及其语义取决于主题/服务请求/响应标头。连接标头由一个包含整个标头长度的 uint32 引入,就像普通消息一样。
-
00
uint8 ok
-
01 acknowledge
-
01
02
03
04
uint32 message_length
-
08
00
00
00
8
-
05
06
07
08
09
0A
0B
0C
int64 sum
-
00
1B
00
00
00
00
00
00
6912
Figure 4.6: Dump of the response to the service call of Figure 4.5
-
Figure
4.6: Dump
of the response
to the service
call
of Figure
4.5
-
00 uint8 ok
-
00
error
-
01
02
03
04
05
06
07
08
09
0A
0B
0C
0D
0E
0F
10
11
string error_text
-
0D
00
00
00 U n k n o w n e r r o r
13
"Unknown error"
Figure 4.7: Dump of a service error response
表 4.2 总结了连接标头的字段及其存在,在主题、服务或错误标头 (X) 中,其中一些是可选的 ((X))或者可以通过请求标头探测(字段值等于 *)。
图 4.8 和图 4.9 分别显示了 /turtlesim 节点的 /turtle1/command_velocity 的请求和响应连接头,通过 turtlesim_teleop 节点。
-
00
01
02
03 uint32 header_length
-
91
00
00
00
145
-
04
05
06
07
08
09
0A
0B
0C
0D
0E
0F
10
11
12
13
14
15
16
17
18
19
1A (
string field)
-
13
00
00
00 c a l l e r i d = /
t u r
t l e s i m
-
1B
1C
1D
1E
1F
20
21
22
23
24
25 (
string field)
-
27
00
00
00 m d
5 s u m =
-
26
27
28
29
2A
2B
2C
2D
2E
2F
30
31
32
33
34
35
-
9 d
5 c
2 d c d
3
4
8 a c
8 f
7
-
36
37
38
39
3A
3B
3C
3D
3E
3F
40
41
42
43
44
45
-
6 c e
2 a
4
3
0
7 b d
6
3 a
1
3
-
46
47
48
49
4A
4B
4C
4D
4E
4F
50
51
52
53
54
55
56 (
string field)
-
0D
00
00
00
t c p _ n o d e l a y =
0
-
57
58
59
5A
5B
5C
5D
5E
5F
60 (
string field)
-
1F
00
00
00
t o p i c =
-
61
62
63
64
65
66
67
68
69
6A
6B
6C
6D
6E
6F
70
71
72
73
74
75
76
77
78
79
-
/
t u r
t l e
1 / c o m m a n d _ v e l o c i
t y
-
7A
7B
7C
7D
7E
7F
80
81
82 (
string field)
-
17
00
00
00
t y p e =
-
83
84
85
86
87
88
89
8A
8B
8C
8D
8E
8F
90
91
92
93
94
-
t u r
t l e s i m / V e l o c i
t y
Figure 4.8: Dump of a connection header request
-
00
01
02
03 uint32 header_length
-
A5
00
00
00
165
-
04
05
06
07
08
09
0A
0B
0C
0D
0E
0
F
10
11
12
13
14
15
16
17
18
19
1A
1B
1C
1D
1E
-
13
00
00
00
c a l l e r i d
=
/ t e l e o p _ t u r t l e
-
1
F
20
21
22
23
24
25
26
27
28
29
2A
2B
2C
-
0A
00
00
00 l a t
c h i n g
=
0
-
2D
2E
2
F
30
31
32
33
34
35
36
37
-
27
00
00
00 m d
5 s u m
=
-
38
39
3A
3B
3C
3D
3E
3
F
40
41
42
43
44
45
46
47
-
9 d
5
c
2 d
c d
3
4
8 a
c
8 f
7
-
48
49
4A
4B
4C
4D
4E
4
F
50
51
52
53
54
55
56
57
-
6
c e
2 a
4
3
0
7 b d
6
3 a
1
3
-
58
59
5A
5B
5C
5D
5E
5
F
60
61
62
63
64
65
66
67
68
69
6A
6B
6C
6D
6E
-
32
00
00
00 m e s s a g e _ d e f i n i t i o n
=
-
6
F
70
71
72
73
74
75
76
77
78
79
7A
7B
7C
7D
-
f l o a t
3
2 l i n e a r
\n
-
7E
7
F
80
81
82
83
84
85
86
87
88
89
8A
8B
8C
8D
-
f l o a t
3
2 a n g u l a r
\n
-
8E
8
F
90
91
92
93
94
95
96
97
98
99
9A
9B
9C
9D
9E
9
F A0 A1 A2 A3 A4 A5 A6 A7 A8
-
17
00
00
00 t y p e
= t u r t l e s i m
/ V e l o
c i t y
Figure 4.9: Dump of a response to the connection header in Figure 4.8
转载:https://blog.csdn.net/gongdiwudu/article/details/128323480