接口
背景
ROS应用通常通过以下三种类型的接口进行通信:主题、服务。ROS 2使用一种简化的描述语言,接口定义语言(IDL),来描述这些接口。这种描述使得ROS工具能够自动生成多种目标语言的接口类型的源代码变得容易。
在本文档中,我们将描述支持的类型:
msg:
.msg
文件是描述 ROS 消息字段的简单文本文件。它们用于在不同语言中生成消息的源代码。srv:
.srv
文件描述一个服务。它由两部分组成:请求和响应。请求和响应都是消息声明。action:
.action
文件描述一个动作。它由三部分组成:目标、结果和反馈。每个部分本身都是消息声明。
消息
消息是ROS 2节点将数据发送到其他ROS节点的一种方式,不需要期望响应。例如,如果一个ROS 2节点从传感器读取温度数据,它可以使用``Temperature``消息将该数据发布到ROS 2网络上。ROS 2网络上的其他节点可以订阅该数据并接收``Temperature``消息。
ROS包的``msg/目录中的
.msg``文件描述和定义了消息。``.msg``文件由两个部分组成:字段和常量。
字段
每个字段由类型和名称组成,用空格分隔,例如:
fieldtype1 fieldname1
fieldtype2 fieldname2
fieldtype3 fieldname3
例如:
int32 my_int
string my_string
字段类型
字段类型可以是:
内置类型
独立定义的消息描述的名称,例如 "geometry_msgs/PoseStamped"
当前支持的内置类型:
类型名称 |
|||
---|---|---|---|
bool |
bool |
builtins.bool |
boolean |
byte |
uint8_t |
内建字节串* |
八位字节 |
字符 |
字符 |
内建字符串* |
字符 |
单精度浮点数 |
浮点数 |
内置浮点型* |
浮点数 |
float64 |
双精度 |
内置浮点型* |
双精度 |
int8 |
int8_t |
内置整型* |
八位字节 |
无符号8位整数 |
uint8_t |
内置整型* |
八位字节 |
有符号16位整数 |
有符号16位整数 |
内置整型* |
短整数 |
无符号16位整数 |
无符号16位整数 |
内置整型* |
无符号短整型 |
32位整型 |
int32_t |
内置整型* |
长整型 |
无符号32位整型 |
uint32_t |
内置整型* |
无符号长整型 |
64位整型 |
int64_t |
内置整型* |
长长整型 |
无符号64位整型 |
uint64_t |
内置整型* |
无符号长长整型 |
字符串 |
std::字符串 |
内建.字符串 |
字符串 |
宽字符串 |
std::u16字符串 |
内建.字符串 |
宽字符串 |
每个内置类型都可以用来定义数组:
类型名称 |
|||
---|---|---|---|
静态数组 |
std::array<T, N> |
内置类型列表* |
T[N] |
无界动态数组 |
std::vector |
builtins.list |
sequence |
bounded dynamic array |
custom_class<T, N> |
内置类型列表* |
sequence<T, N> |
有界字符串 |
std::字符串 |
内建字符串* |
字符串 |
所有比其ROS定义更宽松的类型都会通过软件来强制执行范围和长度上的ROS约束。
使用数组和有界类型的消息定义示例:
int32[] unbounded_integer_array
int32[5] five_integers_array
int32[<=5] up_to_five_integers_array
string string_of_unbounded_size
string<=10 up_to_ten_characters_string
string[<=5] up_to_five_unbounded_strings
string<=10[] unbounded_array_of_strings_up_to_ten_characters_each
string<=10[<=5] up_to_five_strings_up_to_ten_characters_each
服务
服务是一种请求/响应通信,客户端(请求方)等待服务器(响应方)进行简短计算并返回结果。
服务在 ROS 包的 'srv/' 目录下的 '.srv' 文件中进行描述和定义。
一个服务描述文件由请求和响应的消息类型组成,用 '---' 分隔。任何两个 '.msg' 文件通过 '---' 连接在一起都构成一个合法的服务描述。
以下是一个非常简单的服务示例,它接收一个字符串并返回一个字符串:
string str
---
string str
当然,我们可以变得更加复杂(如果你想引用同一包中的消息,不需要提及包名):
# request constants
int8 FOO=1
int8 BAR=2
# request fields
int8 foobar
another_pkg/AnotherMessage msg
---
# response constants
uint32 SECRET=123456
# response fields
another_pkg/YetAnotherMessage val
CustomMessageDefinedInThisPackage value
uint32 an_integer
你不能在一个服务中嵌入另一个服务。
动作
动作是一种长时间运行的请求/响应通信,动作客户端(请求方)等待动作服务器(响应方)执行某些操作并返回结果。与服务不同,动作可以是长时间运行的(数秒或数分钟),在执行过程中提供反馈,并可以中断。
动作定义的形式如下:
<request_type> <request_fieldname>
---
<response_type> <response_fieldname>
---
<feedback_type> <feedback_fieldname>
与服务类似,请求字段位于第一个三短线(---
)之前,响应字段位于其后。还有第二组字段位于第二个三短线之后,用于在发送反馈时发送的字段。
可以有任意数量的请求字段(包括零个)、任意数量的响应字段(包括零个)以及任意数量的反馈字段(包括零个)。
<request_type>
, <response_type>``和``<feedback_type>``都遵循与消息的``<type>``相同的规则。``<request_fieldname>
, ``<response_fieldname>``和``<feedback_fieldname>``都遵循与消息的``<fieldname>``相同的规则。
例如,``Fibonacci``动作定义包含以下内容:
int32 order
---
int32[] sequence
---
int32[] sequence
这是一个动作定义,其中动作客户端发送一个表示要执行的Fibonacci步数的``int32``字段,并期望动作服务器生成包含所有步骤的``int32``数组。在执行过程中,动作服务器还可以提供包含截至某一点的已完成步骤的中间``int32``数组。