# 使用.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。 文件名必须使用大驼峰命名法,并且只包含字母数字字符。 ### 字段的命名 字段名称必须使用小写字母数字字符,用下划线分隔单词。它们必须以字母字符开头,不能以下划线结尾,并且不能有两个连续的下划线。 ### 常量的命名 常量名称必须使用大写字母数字字符,用下划线分隔单词。它们必须以字母字符开头,不能以下划线结尾,并且不能有两个连续的下划线。 ## 语法 消息和服务定义是文本文件。 ## 注释 字符#开始一个注释,它在发生注释的行的末尾终止。 ## 消息文件格式 一行可以包含字段定义或常量定义。单个空格是分隔标记的必须的,可以在标记之间插入额外的空格。 ## 字段定义 字段定义具有以下结构: ` ` ## 常量定义 常量定义具有以下结构: ` =` ## 类型 ``由其基础类型和可选的数组说明符定义。 基础类型可以是以下之一: - 上述列表中的一个原始类型:例如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 | | | |