关于接口(msg/srv/action)
ROS 应用通常通过三种类型的接口之一进行通信:topics、services 或 actions。 ROS 2 使用一种简化的描述语言,即接口定义语言(IDL),来描述这些接口。 这样 ROS 工具就能轻松地为多种目标语言自动生成接口类型的源代码。
本文档将介绍支持的类型:
- msg:
.msg文件是简单的文本文件,描述 ROS 消息的字段,用于为不同语言生成消息的源代码。 - srv:
.srv文件用于描述服务(service)。它们由两部分组成:请求和响应。请求和响应都是消息声明。 - action:
.action文件用于描述动作(action)。它们由三部分组成:目标(goal)、结果(result)和反馈(feedback)。每个部分本身都是一条消息声明。
消息是 ROS 2 节点向网络上的其他 ROS 节点发送数据的一种方式,不期望获得任何响应。
例如,如果一个 ROS 2 节点从传感器读取温度数据,就可以使用 Temperature 消息将该数据发布到 ROS 2 网络上。
ROS 2 网络上的其他节点可以订阅该数据并接收 Temperature 消息。
消息在 ROS 包 msg/ 目录中的 .msg 文件中描述和定义。
.msg 文件由字段和常量两部分组成。
每个字段由一个类型和一个名称组成,用空格分隔,即:
fieldtype1 fieldname1fieldtype2 fieldname2fieldtype3 fieldname3例如:
int32 my_intstring my_string字段类型可以是:
- 内置类型
- 单独定义的消息描述名称,例如 “geometry_msgs/PoseStamped”
当前支持的内置类型:
| 类型名称 | C++ | Python | DDS 类型 |
|---|---|---|---|
| bool | bool | builtins.bool | boolean |
| byte | uint8_t | builtins.bytes* | octet |
| char | char | builtins.int* | char |
| float32 | float | builtins.float* | float |
| float64 | double | builtins.float* | double |
| int8 | int8_t | builtins.int* | octet |
| uint8 | uint8_t | builtins.int* | octet |
| int16 | int16_t | builtins.int* | short |
| uint16 | uint16_t | builtins.int* | unsigned short |
| int32 | int32_t | builtins.int* | long |
| uint32 | uint32_t | builtins.int* | unsigned long |
| int64 | int64_t | builtins.int* | long long |
| uint64 | uint64_t | builtins.int* | unsigned long long |
| string | std::string | builtins.str | string |
| wstring | std::u16string | builtins.str | wstring |
每种内置类型都可以用来定义数组:
| 类型名称 | C++ | Python | DDS 类型 |
|---|---|---|---|
| 静态数组 (static array) | std::array<T, N> | builtins.list* | T[N] |
| 无界动态数组 (unbounded dynamic array) | std::vector | builtins.list | sequence |
| 有界动态数组 (bounded dynamic array) | custom_class<T, N> | builtins.list* | sequence<T, N> |
| 有界字符串 (bounded string) | std::string | builtins.str* | string |
(*) 对于所有比 ROS 定义更宽松的类型,软件会强制施加 ROS 的范围和长度约束。
使用数组和有界类型的消息定义示例:
int32[] unbounded_integer_arrayint32[5] five_integers_arrayint32[<=5] up_to_five_integers_array
string string_of_unbounded_sizestring<=10 up_to_ten_characters_string
string[<=5] up_to_five_unbounded_stringsstring<=10[] unbounded_array_of_strings_up_to_ten_characters_eachstring<=10[<=5] up_to_five_strings_up_to_ten_characters_each字段名称必须使用小写字母数字字符,并用下划线分隔单词。 它们必须以字母字符开头,并且不得以下划线结尾或包含两个连续的下划线。
可以为消息类型中的任何字段设置默认值。 目前不支持为字符串数组和复杂类型(即上述内置类型表中不存在的类型;这适用于所有嵌套消息)设置默认值。
定义默认值的方法是在字段定义行中添加第三个元素,即:
fieldtype fieldname fielddefaultvalue例如:
uint8 x 42int16 y -2000string full_name "John Doe"int32[] samples [-200, -100, 0, 100, 200]注意:
- 字符串值必须用单引号
'或双引号"括起来- 目前字符串值不做转义处理
常量定义与带默认值的字段描述类似,但常量值无法通过编程方式修改。 赋值通过等号 ’=’ 表示,例如:
constanttype CONSTANTNAME=constantvalue例如:
int32 X=123int32 Y=-123string FOO="foo"string EXAMPLE='bar'注意:常量名称必须为大写
服务是一种请求/响应通信模式,客户端(请求者)向服务端(响应者)发起请求,等待对方执行简短计算并返回结果。
服务在 ROS 包 srv/ 目录中的 .srv 文件中描述和定义。
服务描述文件由请求和响应消息类型组成,用 --- 分隔。
任意两个 .msg 文件用 --- 连接即为合法的服务描述。
以下是一个非常简单的服务示例,它接收一个字符串并返回一个字符串:
string str---string str当然也可以更加复杂(如果想引用同一个包中的消息,则不必提及包名):
# request constantsint8 FOO=1int8 BAR=2# request fieldsint8 foobaranother_pkg/AnotherMessage msg---# response constantsuint32 SECRET=123456# response fieldsanother_pkg/YetAnotherMessage valCustomMessageDefinedInThisPackage valueuint32 an_integer你不能在一个服务中嵌套另一个服务。
动作是一种适用于长时间运行场景的请求/响应通信模式,Action 客户端(请求者)向 Action 服务端(响应者)发起请求,等待对方执行操作并返回结果。 与服务不同,动作可以长时间运行(数秒或数分钟),在执行过程中提供反馈,并且可以被中断。
动作定义具有以下形式:
<request_type> <request_fieldname>---<response_type> <response_fieldname>---<feedback_type> <feedback_fieldname>与服务一样,请求字段在前,响应字段在第一个三横线(---)之后。
在第二个三横线之后还有第三组字段,即反馈(feedback)字段。
可以有任意数量的请求字段(包括零个)、任意数量的响应字段(包括零个)和任意数量的反馈字段(包括零个)。
<request_type>、<response_type> 和 <feedback_type> 遵循与消息的 <type> 相同的所有规则。
<request_fieldname>、<response_fieldname> 和 <feedback_fieldname> 遵循与消息的 <fieldname> 相同的所有规则。
例如,Fibonacci 动作定义包含以下内容:
int32 order---int32[] sequence---int32[] sequence这是一个动作定义,Action 客户端发送一个 int32 字段,表示要计算的 Fibonacci 步数;Action 服务端则返回一个包含完整步骤序列的 int32 数组。
在计算过程中,Action 服务端还可以通过反馈发送一个 int32 中间数组,表示截至某一步已完成的序列。