Skip to content

关于接口(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 文件由字段和常量两部分组成。

每个字段由一个类型和一个名称组成,用空格分隔,即:

Terminal window
fieldtype1 fieldname1
fieldtype2 fieldname2
fieldtype3 fieldname3

例如:

Terminal window
int32 my_int
string my_string

字段类型可以是:

  • 内置类型
  • 单独定义的消息描述名称,例如 “geometry_msgs/PoseStamped”

当前支持的内置类型:

类型名称C++PythonDDS 类型
boolboolbuiltins.boolboolean
byteuint8_tbuiltins.bytes*octet
charcharbuiltins.int*char
float32floatbuiltins.float*float
float64doublebuiltins.float*double
int8int8_tbuiltins.int*octet
uint8uint8_tbuiltins.int*octet
int16int16_tbuiltins.int*short
uint16uint16_tbuiltins.int*unsigned short
int32int32_tbuiltins.int*long
uint32uint32_tbuiltins.int*unsigned long
int64int64_tbuiltins.int*long long
uint64uint64_tbuiltins.int*unsigned long long
stringstd::stringbuiltins.strstring
wstringstd::u16stringbuiltins.strwstring

每种内置类型都可以用来定义数组:

类型名称C++PythonDDS 类型
静态数组 (static array)std::array<T, N>builtins.list*T[N]
无界动态数组 (unbounded dynamic array)std::vectorbuiltins.listsequence
有界动态数组 (bounded dynamic array)custom_class<T, N>builtins.list*sequence<T, N>
有界字符串 (bounded string)std::stringbuiltins.str*string

(*) 对于所有比 ROS 定义更宽松的类型,软件会强制施加 ROS 的范围和长度约束。

使用数组和有界类型的消息定义示例:

Terminal window
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

字段名称必须使用小写字母数字字符,并用下划线分隔单词。 它们必须以字母字符开头,并且不得以下划线结尾或包含两个连续的下划线。

可以为消息类型中的任何字段设置默认值。 目前不支持为字符串数组和复杂类型(即上述内置类型表中不存在的类型;这适用于所有嵌套消息)设置默认值。

定义默认值的方法是在字段定义行中添加第三个元素,即:

Terminal window
fieldtype fieldname fielddefaultvalue

例如:

Terminal window
uint8 x 42
int16 y -2000
string full_name "John Doe"
int32[] samples [-200, -100, 0, 100, 200]

注意:

  • 字符串值必须用单引号 ' 或双引号 " 括起来
  • 目前字符串值不做转义处理

常量定义与带默认值的字段描述类似,但常量值无法通过编程方式修改。 赋值通过等号 ’=’ 表示,例如:

Terminal window
constanttype CONSTANTNAME=constantvalue

例如:

Terminal window
int32 X=123
int32 Y=-123
string FOO="foo"
string EXAMPLE='bar'

注意:常量名称必须为大写

服务是一种请求/响应通信模式,客户端(请求者)向服务端(响应者)发起请求,等待对方执行简短计算并返回结果。

服务在 ROS 包 srv/ 目录中的 .srv 文件中描述和定义。

服务描述文件由请求和响应消息类型组成,用 --- 分隔。 任意两个 .msg 文件用 --- 连接即为合法的服务描述。

以下是一个非常简单的服务示例,它接收一个字符串并返回一个字符串:

Terminal window
string str
---
string str

当然也可以更加复杂(如果想引用同一个包中的消息,则不必提及包名):

Terminal window
# 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

你不能在一个服务中嵌套另一个服务。

动作是一种适用于长时间运行场景的请求/响应通信模式,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 中间数组,表示截至某一步已完成的序列。