前言
原文链接:Managed nodes
本文描述了具有受管理生命周期的节点概念。它旨在记录在ROS 2中支持受管理生命周期节点的一些选项。在撰写本文时,考虑了ROS 2 C++客户端库的现有设计,特别是执行器的当前设计。
翻译:deepL & chatgpt
撰写日期:2015 年 6 月
最后修改时间:2021 年 2 月
背景
节点的受管理生命周期允许更好地控制ROS系统的状态。它将允许roslaunch确保在允许任何组件开始执行其行为之前,所有组件都已正确实例化。它还将允许节点在线重新启动或替换。
本文的最重要概念是,受管理节点呈现了已知的接口,按照已知的生命周期状态机执行,并且否则可以被视为黑匣子。这允许节点开发人员自由选择如何提供受管理生命周期功能,同时确保任何用于管理节点的工具都可以与任何符合规范的节点一起使用。
生命周期
有 4 个主要状态:
-
Unconfigured
// 未配置 -
Inactive
// 非活动 -
Active
//激活 -
Finalized
//已完成
要跳出一级状态,需要外部监控程序采取行动,但在 "active"状态下触发的错误除外。
还有 6 个转换状态,它们是请求转换期间的中间状态。
-
Configuring
// 配置中 -
CleaningUp
// 清理中 -
ShuttingDown
// 关闭中 -
Activating
// 激活中 -
Deactivating
// 删除中 -
ErrorProcessing
// 错误处理中
在转换状态中,将执行逻辑以确定转换是否成功。成功或失败应通过生命周期管理界面传达给生命周期管理软件。
监督流程涉及 7 个转换,它们是:
-
create
// 创建 -
configure
// 配置 -
cleanup
// 清理 -
activate
// 激活 -
deactivate
// 停用 -
shutdown
// 关闭 -
destroy
//销毁
每个状态的行为定义如下。
一、主要状态
1.主要状态:未状态配置
这是节点在实例化后立即所处的生命周期状态。这也是节点在发生错误后可以返回的状态。在这种状态下,预计不会存储状态。
这意味着节点没有任何存储的数据或配置设置。它是一个等待配置的干净状态。如果节点在操作过程中遇到错误,它可能会返回到“未配置”状态。这意味着在遇到错误后,节点可能需要重置到初始状态,然后再尝试恢复正常操作。
有效转出
-
节点可通过configure转换过渡到inactive状态。
-
节点可通过shutdown转换过渡到finalized状态。
2.主要状态:非活动
这种状态表示节点当前不执行任何处理。
这种状态的主要目的是允许对节点进行(重新)配置(更改配置参数、添加和删除主题发布/订阅等),而不改变其运行时的行为。
在此状态下,节点将不会获得任何执行时间来读取主题、执行数据处理、响应功能服务请求等。
在非活动状态下,任何到达托管主题的数据都不会被读取或处理。数据保留将取决于为主题配置的 QoS 策略。
任何向处于非活动状态的节点发出的托管服务请求都不会得到响应(对呼叫者来说,这些请求会立即失败)。
从 "非活动 "状态的有效过渡
-
节点可通过shutdown转换过渡到Finalized状态。
-
节点可通过cleanup转换过渡到Unconfigured状态。
-
节点可通过activate转换过渡到Active状态。
3.主要状态:活动
这是节点生命周期的主要状态。在这种状态下,节点会执行任何处理、响应服务请求、读取和处理数据、产生输出等。
如果在此状态下发生节点/系统无法处理的错误,节点将过渡到 ErrorProcessing(错误处理)状态。
从活动状态有效转换
-
节点可通过deactivate转换过渡到Inactive状态。
-
节点可通过shutdown转换过渡到Finalized状态。
4.主要状态:最终确定
最终完成状态是节点在销毁前立即结束的状态。这种状态总是终结的,从这里开始的唯一转换就是销毁。
这种状态的存在是为了支持调试和反省。失效的节点对系统自省仍是可见的,调试工具可能会对其进行自省,而不是直接销毁。如果一个节点是在重生循环中启动的,或有已知的循环原因,则预计监管进程将制定自动销毁和重新创建节点的策略。
最终确定的有效转换
-
节点可以通过
destroy
转换被释放。
二、过渡状态
1.过渡状态:正在配置
在这种转换状态下,节点的 onConfigure 回调将被调用,以允许节点加载其配置并进行任何必要的设置。
节点的配置通常涉及在节点生命周期内必须执行一次的任务,如获取永久内存缓冲区和设置不会更改的主题发布/订阅。
节点以此来设置其在整个生命周期内必须持有的任何资源(无论其处于活动还是非活动状态)。例如,此类资源可包括主题出版物和订阅、持续保留的内存以及初始化配置参数。
退出配置的有效过渡
-
如果 onConfigure 回调成功,节点将过渡到inactive状态
-
如果 onConfigure 回调导致失败代码(TODO 特定代码),节点将转回Unconfigured状态。
-
如果 onConfigure 回调引发或导致任何其他结果代码,节点将过渡到 ErrorProcessing 状态
2.过渡状态:清理
在这种过渡状态下,节点的回调 onCleanup 将被调用。该方法将清除所有状态,并将节点恢复到与首次创建时功能相当的状态。如果无法成功完成清理,则将过渡到 ErrorProcessing(错误处理)状态。
清理时的有效过渡
-
如果 onCleanup 回调成功,节点将过渡到Unconfigured状态。
-
如果 onCleanup 回调引发或产生任何其他返回代码,节点将过渡到
ErrorProcessing
。
3.过渡状态:激活Unconfigured
在此过渡状态下,将执行回调 onActivate。该方法将为开始执行做最后的准备工作。这可能包括获取只有在节点实际激活时才会保留的资源,如访问硬件。理想情况下,此回调不应执行需要大量时间的准备工作(如冗长的硬件初始化)。
激活时的有效转出
-
如果 onActivate 回调成功,节点将过渡到激活状态。
-
如果 onActivate 回调引发或产生任何其他返回代码,节点将过渡到 ErrorProcessing。
4.过渡状态:停用
在此过渡状态下,将执行回调 onDeactivate。预计该方法将在开始执行前进行任何清理,并应与 onActivate 的变化相反。
退出停用的有效过渡
-
如果 onDeactivate 回调成功,节点将过渡到Inactive状态。
-
如果 onDeactivate 回调引发或产生任何其他返回代码,节点将过渡到 ErrorProcessing。
5.过渡状态:关闭
在此过渡状态下,将执行回调 onShutdown。该方法将在销毁前进行必要的清理。该方法可从任何主状态(最终完成除外)进入,初始状态将传递给该方法。
退出 ShuttingDown 的有效过渡
-
如果 onShutdown 回调成功,节点将过渡到最终完成。
-
如果 onShutdown 回调引发或产生任何其他返回代码,节点将过渡到 ErrorProcessing。
6.过渡状态:错误处理
在此过渡状态下,可以清除任何错误。可以从执行用户代码的任何状态进入此状态。如果错误处理成功完成,节点可以返回到未配置状态;如果无法进行全面清理,则必须失败,节点将过渡到最终状态,准备销毁。
回调中的错误返回代码、回调中的方法或未捕获的异常都可能导致向 ErrorProcessing 过渡。
退出 ErrorProcessing 的有效过渡
-
如果 onError 回调成功,节点将过渡到未配置状态。预计 onError 会清除之前状态的所有状态。
因此,如果从active状态进入,则必须提供 onDeactivate 和 onCleanup 的清理才能返回成功,即先回到inactive再回到unconfigured。
-
如果 onShutdown 回调引发或产生任何其他结果代码,节点将过渡到 Finalized。
三、创建和销毁节点的过渡状态
销毁过渡(Demise Transition)
这是节点从执行到被销毁的过渡。在销毁过渡期间,节点停止接收新的消息或服务请求,并且正在处理的消息或服务请求被完成或取消。随后,节点的资源被释放,通信机制被关闭,节点对象被销毁。
这种转变只会导致节点的释放。在面向对象的环境中,它可能只涉及调用析构函数。否则它将调用标准的释放方法。这种转变应该总是成功的。
创建过渡( Birth Transition)
这是节点从被创建到开始执行的过渡。在创建过渡期间,节点的资源被分配,通信机制被初始化,并且节点可以开始处理消息、发布消息或者提供服务。
此转换将实例化节点,但不会运行构造函数之外的任何代码。
理解这两个过渡对于确保节点的正确运行至关重要。在创建过渡期间,节点必须正确地初始化其资源,并准备好接收和处理消息。而在销毁过渡期间,节点必须正确地处理未完成的任务,并释放其资源,以确保不会出现资源泄漏或者未完成的操作。
四、其他
1.接口管理
受到管理的节点将通过以下接口暴露给执行管理任务的工具,这个接口不应受到生命周期状态所施加的通信限制的影响。
通常情况下,一个常见的模式是拥有一个容器类,该容器类从库中加载一个管理的节点实现,并通过插件架构自动通过方法公开所需的管理接口,而容器不受生命周期管理的约束。然而,完全可以考虑任何提供此接口并遵循生命周期策略的实现为管理节点。相反,任何提供这些服务但不按照生命周期状态机中定义的方式行事的对象都是不合规的。
这些服务也可以通过属性和方法调用(用于本地管理)来提供,除此之外还可以通过ROS消息和话题/服务(用于远程管理)来暴露。在提供ROS中间件接口的情况下,必须使用特定的话题,并且它们应该放置在合适的命名空间中。
每个可能的监管过渡都将作为一个服务提供,服务的名称为过渡的名称,除了创建(create)之外。创建服务将需要额外的参数来找到要实例化的节点。该服务将报告过渡是否成功完成。
2.生命周期事件
当生命周期状态发生变化时,应提供一个话题来广播新的生命周期状态。该话题必须是latched(锁定的)【锁定:保留最新的消息,客户端将第一时间获取到最新的消息(最新的消息不代表当前时刻的消息)】。话题的名称必须为lifecycle_state,它将携带结束状态和转换,以及结果代码。每次触发转换时,无论成功与否,它都会发布。
3.节点管理
受管理的节点可能以几种不同的方式在状态之间转换。大多数状态转换预期由外部管理工具协调,该工具将为节点提供其配置并启动它。外部管理工具还应该监控节点并在发生故障时执行恢复行为。本地管理工具也是一种可能性,利用方法级接口。节点也可以配置为自我管理,但这是不建议的,因为这会干扰尝试通过接口管理节点的外部逻辑。
预期有一种转换是在本地发起的,即错误(ERROR)转换。
受管理的节点还可能希望公开参数,在未受管理的系统中运行时自动配置和激活。
4.扩展
这个生命周期将被要求在整个工具链中得到支持,因此这个设计并不打算通过添加额外的状态来进行扩展。预期会有更复杂的特定于应用程序的状态机。它们可能存在于任何生命周期状态内部,或者在宏观级别,这些生命周期状态预期将作为监管系统的有用原语的一部分。