14. ROS中的参数API设计

【编者注】:由于ROS 2设计文章系列中的“基于ZeroMQ和Friends之上的ROS(ROS on ZeroMQ and Friends)”和“ROS中的RPC API设计(RPC API design in ROS)”两篇文章已经过时,且由于ROS 2最终决定构建于DDS和RTPS之上,而不是ZeroMQ和RPC之上,因此不再翻译学习那两篇文章,若对这两篇文章感兴趣的话可以直接参阅其英语原文。

本文提出了ROS 2中用于与参数交互的接口设计。本文重点关注对系统设计的说明,而未对其具体实现进行介绍。

作者:塔利·富特(Tully Foote)

撰写日期:2015-09

最后修改时间:2019-05

14.1 背景

在ROS 1中,参数是在“黑板模型”中实现的,所有节点都可以不受限制地对其进行读写访问。该数据模型在许多示例中都被证明是有用的,但在许多情况下,缺乏控制或所有权被证明是一个问题。常见的缺陷之一就是在驱动程序上设置参数。为解决这个用例,开发了一个名为dynamic_reconfigure的工具。该工具提供了基于服务的接口来与其他节点的参数进行交互。

14.1.1 其他资源

与ROS 2参数设计过程相关的其他资源包括:

● Gonzalo在参数方面的研究。

○ 讨论:https://groups.google.com/forum/#!topic/ros-sig-ng-ros/YzCmoIsN0o8  https://groups.google.com/forum/#!searchin/ros-sig-ng- ros/parameter/ros-sig-ng-ros/fwDBcei5Ths/L6ORPfjUDXYJ

○ 原型:github.com/abellagonzal

○ 最终说明:wiki.ros.org/sig/NextGe

● Thibault的nodeparam草案REP:

github.com/tkruse/rep/b

14.2 理想系统

考虑一个理想系统以了解它如何工作以及它与当前系统的关系是很有用的。一个理想系统应可以支持ROS 1.0的内置参数以及ROS 1.0的动态参数系统的组合用例。基于该准则,理想系统应该能够:

● 设置参数值

包括以原子方式设置参数值组。

● 获取参数值

包括以原子方式获取参数值组。

● 取消设置参数值

包括以原子方式取消设置参数值组,但可能是以原子方式设置参数组的一种特殊情况。

● 列出当前设置的参数

由于参数的数量可能很大,因此需要能够提供参数的子集。例如,可以为树状GUI增量查询参数。

● 在添加和删除参数或更改参数值时提供通知

● 拒绝参数值更改

这意味着某些实体有权基于任意准则拒绝或接受某个更改。这还包括向外部参与者传达接受某个变更的至少部分准则的能力。例如,传达某个整型参数的范围或某个字符串参数的几个选项。此类信息应该用于生成用户通用接口,但可能无法捕获所有准则。由于验证标准可以是任意复杂的且可能无法传达给客户端,因此参数服务器应该可以提供验证一组原子参数的功能,并在这些参数值被接受(基于当前标准)时以布尔标志进行响应。显然,当这些参数值在不久之后设置时,结果可能会有所不同,但允许在例如一个GUI中通用性地实现各个验证器。

● 提供对什么样的参数预期会通过验证与什么样的参数会被拒绝的洞见能力

在更新一个值时,在不实际请求做出该更改的情况下知道该参数更新是否会被接受,这一点是很有价值的。

● 为参数的生命周期提供明确的规则

这些规则应定义该参数的生命周期是什么以及什么条件下会清除其值。

● 无歧义地解释所有参数的名称

当前系统的挑战之一就是节点与参数之间存在命名歧义,例如,/foo/bar/baz可能是节点/foo/bar/baz,或者也可能是节点/foo/bar上的私有参数baz。

● 为回放和分析进行日志记录

14.3 提议的方法

为覆盖上述理想系统的功能集,提出了如下ROS 2参数系统。

14.3.1 托管在节点中的参数

为了验证参数的生命周期,所有参数都将会被托管在一个节点上。这些参数的生命周期将会隐含地捆绑到节点的生命周期上。节点将会负责验证当前值。节点还应该实现参数的持久化,以在重启后重新加载之前的参数值。

14.3.2 参数寻址

所有参数将会通过两个元素来寻址:完整的节点名称和参数名称。

14.3.3 支持的数据类型

每个参数由一个键和一个值组成。键是一个字符串值。值可以是以下数据类型之一:

● 布尔型(bool)

● 64位整型(int64)

● 64位浮点型(float64)

● 字符串(string)

● 字节型数组(byte[])

● 布尔型数组(bool[])

● 64位整型数组(int64[])

● 64位浮点型数组(float64[])

● 字符串数组(string[])

所选的数据类型都不是如“接口定义文章(interface definitions article)”中所定义的那些复杂数据类型。这里不对不同位深度和无符号类型的数据类型进行补全,以允许对基于文本的配置文件进行解释。

数组数据类型支持多种用例,例如:

● 字节型数组(byte[])包括在其中以允许存储二进制blob。不推荐使用二进制blob,但它的使用非常方便,而且明确支持它比让人们尝试滥用其他数据类型(如字符串)要好。

● 布尔型数组(bool[])作为其他数组参数的掩码非常有用。

● 64位整型数组(int64[])和浮点型数组(float64[])可用于表示数值向量和矩阵参数。

● 字符串数组(string[])可用于表示名称组,例如多机器人环境中的一组机器人。

虽然数组参数的使用增加了API的复杂性,但删去它们会需要像矩阵等这类在机器人技术中很常见的参数的复杂命名方案。

只支持数据类型同构的数组。这是为了避免处理数组内的多维性和异质性所需的不必要的内省复杂性。

然而,不应该滥用数组;用户应尽可能依赖命名空间和显式变量名。

14.3.5 要求的功能

每个节点负责提供以下功能:

● 获取参数

给定一个参数名称列表,该功能会返回各个参数的值。

● 设置参数

给定一个参数名称列表,该功能会视参数值验证情况请求参数的更新值。更新的值可以包括取消设置值。该功能会提供一个API,可以以原子方式更新一组值,这样如果任何参数值验证失败,则不会设置任何参数值。这个功能调用的成功或失败将会提供给每个更新单元的客户端。参数值的验证结果应尽快返回,并且该验证结果仅与接受或拒绝设置请求有关。该功能不应考虑更改的参数值可能会或可能不会如何影响节点或更大系统正在进行中的系统性能。

● 列出参数

提供当前设置的参数名称列表。

● 描述参数

给定一个参数名称列表,该功能会返回这些参数的数据类型。

这些功能将会通过用户API进行公开,该API还会支持本地API调用以及通过ROS服务API对远程节点的调用。

14.3.6 参数更新验证

节点可以验证传入参数的更改并接受或拒绝这些参数的更新。

14.3.7 类似于向后兼容性参数服务器的行为

在某些用例中,使用参数服务器的旧行为很有用。超过某个具体节点持续时间的持久性以及具有与某个潜在拥有参数值或验证参数值的节点没有特定关联的参数都是很有价值的。为此,我们建议编写一个模拟ROS 1.0参数服务器策略的简单节点:该节点会在命名空间“/”中运行,并简单地接受所有请求的更改。这个参数服务器节点持有的参数应在参数服务器节点的生命周期内持续存在。可以在不同的命名空间中启动具体实例以支持不同的参数持久性模型。

14.3.8 搜索参数行为

ROS 1.0中开发的一种模式是searchParam模式,在该模式中,可以在命名空间中设置参数,并且参数查询会在该命名空间中搜索该参数。通过允许该搜索参数实现以分层顺序遍历不同节点,可以实现类似行为。

14.3.9 参数 API

ROS客户端库会提供以下API,用于与本地节点及包含返回代码的远程节点的核心参数API进行交互。

14.3.10 参数事件

每个节点会提供一个话题,参数事件将会在该话题上发布。这个话题是为了支持监控参数的更改。期望客户端库会实现为使用这个话题的具体参数更改注册回调函数的功能。

14.3.11 日志记录和回放

在对整个系统进行日志记录时,可以通过事件信道的标准话题记录功能来记录参数更改。回放机制的实现可以侦听参数事件流并通过远程API调用设置参数功能。

14.4 当前的实现

上述规范已经进行了原型化;其实现可以在rclcpp中找到。用于远程交互的服务定义包含在rcl_interfaces软件包中。

14.4.1 未实现的功能

目前,ROS参数API设计规范的部分功能尚未实现,包括:

● 无参数订阅注册功能。事件可以发布,但无法为某个具体参数的更改注册回调函数。当前可以为某个节点参数的所有更改注册一个回调函数。

● 无法注册回调函数以在参数更新之前验证参数更新的有效性。

● 尚未开展对被记录日志的参数更改进行记录和回放方面的工作。

● 列出和获取期望的验证策略的功能尚未实现。预计会在比参数稍高的层次上进行操作,并且可能会与组件的生命周期有关。

14.5 目前尚未涉及的话题

展望未来,无论是在本文档还是其他文档中,仍有一些话题需要进行讨论和充实。需要突出强调的话题有以下几个:

14.5.1 参数初始化

在启动时加载参数的方法有几种,包括命令行参数、roslaunch 参数和潜在的参数文件。参数初始化问题应与新的启动系统一并解决。

14.5.2 支持静态检查/验证的预声明接口

API声明功能可以帮助进行静态检查并防止因错别字设置错误参数而产生的逻辑错误。节点可以通过拒绝意外名称来强制执行静态检查/验证操作,但在某些情况下,知道期望的参数名称对开发者工具很有用。

*英语原文网址:design.ros2.org/article