使用.msg / .srv / .action文件定义接口¶
本文规定了来自ROS 1的文件格式,描述了ROS组件之间交换的数据结构,以便它们相互交互。
作者:Dirk Thomas¶
撰写日期:2019-03¶
最后修改:2021-02¶
范围¶
本文规定了来自ROS 1的文件格式,描述了用于组件间交换信息的数据结构。数据结构以不受编程语言限制的方式定义。该格式基于ROS 1中的.msg格式定义。
下面仅描述了映射到IDL类型的部分。请参见“接口定义和语言映射”文章,了解如何映射到特定于编程语言的类型和API。
概述¶
数据结构由一组字段定义。字段的顺序无关紧要。每个字段由类型和名称描述。
消息¶
单个数据结构称为消息。每个消息都有一个名称。结合包的名称,可以唯一地识别消息。
服务¶
对于请求/回复风格的通信,两个交换的数据结构是相关的。这些数据结构对称为服务。服务通过其名称和所在的包来识别。每个服务描述两个消息,一个用于请求数据结构,一个用于回复数据结构。
动作¶
对于带有进度反馈的长时间运行的请求/回复风格通信,交换的数据结构是相关的。这些数据结构的三元组称为动作。动作通过其名称和所在的包来识别。每个动作描述三个消息,一个用于目标数据结构,一个用于结果数据结构,一个用于反馈数据结构。
字段类型¶
字段的类型可以是原始类型或其他数据结构。这些可以是动态或静态大小的数组。
原始字段类型¶
定义了以下原始类型:
bool
byte
char
float32, float64
int8, uint8
int16, uint16
int32, uint32
int64, uint64
string
虽然在ROS 1中byte和char已弃用,但它们仍然是此定义的一部分,以便于迁移。
在ROS 1中,字符串未指定任何编码,传输对其不敏感。这意味着通常它只能包含ASCII。对于明确支持宽字符字符串,请考虑迁移到.idl文件,它定义了明确的类型。
非原始字段类型¶
除了原始类型,还可以引用其他消息来描述“复杂”字段的类型。复杂字段类型由包和消息名称识别。
静态大小数组¶
静态数组恰好有N个指定类型的元素。N必须大于0。
动态大小数组¶
动态数组可以有0到N个指定类型的元素。N可能没有上限,可能仅受内存或其他系统特定限制的限制。
上限¶
此功能在ROS 1中不可用。
字符串以及动态数组的大小可以通过上限限制。这使得可以为使用动态大小数据的数据结构预分配内存。
默认值¶
此功能在ROS 1中不可用。
字段可以可选地指定默认值。如果没有指定默认值,则使用通用默认值:
对于bool,它是false
对于数值类型,它是0值
对于字符串,它是一个空字符串
对于静态大小数组,它是一个N个元素的数组,其字段被零初始化
对于有界大小数组和动态大小数组,它是一个空数组 []
数组默认值¶
类型为数组的字段可以可选地指定默认值。
数组的默认值必须以开方括号(
[)开始并以闭方括号(])结束数组中的每个值必须用逗号(
,)分隔数组中的所有值必须与字段的类型相同
数组的第一个值之前不能有逗号,
数组最后一个元素后的尾随逗号被忽略
字符串数组的额外规则:
字符串数组必须只包含遵循以下规则的字符串:
可以可选地用单引号(’)或双引号(”)引用的字符串值
双引号(”)的字符串(分别用单引号(’))应该将任何内部双引号(分别用单引号)转义
常量¶
常量由原始类型、名称和固定值定义。如果原始类型是整数类型,固定值可以以以下方式之一指定:
十进制整数,例如1
二进制整数,例如0b01或0B01
八进制整数,例如0o01或0O01
十六进制整数,例如0x01或0X01
约定¶
消息和服务的命名¶
每个文件包含一个消息或服务。消息文件使用扩展名.msg,服务文件使用扩展名.srv。
文件名必须使用大驼峰命名法,并且只包含字母数字字符。
字段的命名¶
字段名称必须使用小写字母数字字符,用下划线分隔单词。它们必须以字母字符开头,不能以下划线结尾,并且不能有两个连续的下划线。
常量的命名¶
常量名称必须使用大写字母数字字符,用下划线分隔单词。它们必须以字母字符开头,不能以下划线结尾,并且不能有两个连续的下划线。
语法¶
消息和服务定义是文本文件。
注释¶
字符#开始一个注释,它在发生注释的行的末尾终止。
消息文件格式¶
一行可以包含字段定义或常量定义。单个空格是分隔标记的必须的,可以在标记之间插入额外的空格。
字段定义¶
字段定义具有以下结构:
<type> <name> <optional_default_value>
常量定义¶
常量定义具有以下结构:
<type> <name>=<value>
类型¶
<type>由其基础类型和可选的数组说明符定义。
基础类型可以是以下之一:
上述列表中的一个原始类型:例如int32
具有上限的字符串:string<=N以将字符串长度限制为N个字符
引用另一个消息的复杂类型:
消息的绝对引用:例如some_package/SomeMessage
同一包内消息的相对引用:例如OtherMessage
数组说明符可以是以下之一:
静态数组由后缀[N]描述,其中N是数组的固定大小
无界动态数组由后缀[]描述
有界动态数组由后缀[<=N]描述,其中N是数组的最大大小
值¶
根据类型,以下值是有效的:
bool:
true, 1
false, 0
byte:
在[0, 255]区间内的不透明8位数
char:
在[0, 255]区间内的无符号整数值
float32和float64:
使用点(.)作为整数部分和小数部分之间的分隔符的十进制数。
int8, int16, int32和int64:
在[- 2 ^ (N - 1), 2 ^ (N - 1) - 1]区间内的整数值,其中N是int后面的位数
uint8, uint16, uint32和uint64:
在[0, 2 ^ N - 1]区间内的无符号整数值,其中N是uint后面的位数
string:
可以可选地用单引号(’)或双引号(”)引用的字符串值
双引号(”)的字符串(分别用单引号(’))应该将任何内部双引号(分别用单引号)转义:
string my_string “I heard “Hello”” 是有效的
string my_string “I heard “Hello”” 是无效的
string my_string “I heard ‘Hello’” 是有效的
string my_string ‘I heard ‘Hello’’ 是有效的
string my_string ‘I heard ‘Hello’’ 是无效的
string my_string ‘I heard “Hello”’ 是有效的
服务文件格式¶
服务文件包含两个消息定义,它们由只包含三个破折号的一行分隔:
转换为IDL¶
为定义的接口生成代码,以便不同的客户端库可以使用。使用上述格式描述的接口首先转换为IDL。代码生成使用生成的文件。
在上述格式中定义的结构可能是空的/不包含成员。在这种情况下,生成的.idl结构将有一个虚拟成员(uint8 structure_needs_at_least_one_member),以满足IDL的非空要求。
映射到IDL类型¶
| ROS类型 | IDL类型 | | — | — | | bool | boolean | | byte | octet | | char | uint8 | | float32 | float | | float64 | double | | int8 | int8 | | uint8 | uint8 | | int16 | short | | uint16 | unsigned short | | int32 | long | | uint32 | unsigned long | | int64 | long long | | uint64 | unsigned long long | | string | string |
字节的映射使用了与ROS 1不同的类型,同时仍然是一个不透明的8位数。ROS 1中的定义:已弃用的int8的别名。IDL (7.4.1.4.4.2.6)中的定义:一个不透明的8位数。
虽然字符的映射不太直观,但它保持了与ROS 1定义的兼容性:“已弃用的uint8的别名”。
| ROS类型 | IDL类型 |
|---|---|
| 静态数组 | array |
| 无界动态数组 | sequence |
| 有界动态数组 | bounded sequence |
| 有界字符串 | bounded string |