使用.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