ROS2中的LifecycleNode节点
本文参考:ros2 node_lifecycle
ros2中加入了一种区别于普通的node节点的管理节点LifecycleNode,这种节点有点像是状态机,会在几种不同的状态中切换。
LifecycleNode 节点的状态主要分为基本状态(Primary States)和切换状态(Transition States)。主要状态是任何节点都可以做相应的任务的稳态,切换状态切换过程中短暂的临时状态。这些中间状态的结果用于指示两个主要状态之间的转换是否成功。
主要状态分为4种:
unconfigured
inactive
active
shutdown
切换状态分为6种:
configuring
activating
deactivating
cleaningup
shuttingdown
ErrorProcessing
关于状态的切换可以看这张图:
Unconfigured
节点实例化之后就会立马进入这个状态,节点出错之后也会返回到这个状态。
有效的状态转换:
- 可以通过
configure
切换到Inactive
状态 - 可以通过
shutdown
切换到Finalized
状态
Inactive
这个状态代表节点目前没有进行任何处理。这个状态的主要目的是让节点进行(重新)配置(比如改变配置参数、增加或删除topic的发布和订阅等)而不在运行时改变它的行为。
在这个状态时,节点不会接受任何运行时间来读取topic、进行数据处理或是回应service的请求等。Inactive
状态下不会对收到的任何来自管理话题的数据进行读取或者是处理。数据保留将会取决于为主题配置的QoS策略。同时service请求也不会被回应(对请求者来说,会立马fail)。
有效的状态转换:
- 通过
shutdown
切换到Finalized
- 通过
cleanup
切换到Unconfigured
- 通过
acticate
切换到Active
Active
这个lifecycle节点的主要状态。在这个状态时,节点会进行一些处理、回应service请求、读取和处理数据、产生输出等。
如果这个状态下节点或是系统发生了不能处理的错误,那么节点会切换到ErrorProcessing
状态。
有效的状态切换:
- 通过
deactivate
切换到Inactive
- 通过
shutdown
切换到Finalized
Finalized
该状态是节点被销毁前会立马就结束的状态。这个状态只会通往销毁。
有效的状态切换:
- 通过
destroy
被消除分配(deallocated)
Configuring
节点的conConfigure
回调函数会被调用,来允许节点加载配置以及进行必要的设置。
节点的配置通常都会涉及到一些在节点的生命周期中必须被执行一次的任务,比如说申请内存、配置不会改变的topic的发布/订阅等等。
节点也会用此来设置一些它的整个生命周期中必须保留的资源(不论是active状态还是inactive状态),比如说topic的发布/订阅器,持续需要的内存空间以及初始的配置参数。
有效的状态切换:
- 如果
conConfigure
回调函数成功被调用,那么节点会切换到Inactive
状态。 - 如果回调函数出现失败代码(需要具体的代码),那么节点就会返回到
Unconfigured
状态。 - 如果回调函数引发或return了别的值,则节点将转换为
ErrorProcessing
状态。
CleaningUp
节点的onCleanup
回调函数会被调用。函数中应当清除所有状态并返回到与初次创建时一样的状态。
有效的状态切换;
- 如果
onCleanup
回调函数成功执行,就会被切换到Unconfigured
状态。 - 如果执行出错就会切换到
ErrorProcessing
Activating
节点的onActivate
回调函数会被调用。函数中应当做好开始执行前的最后准备,包括获得只在节点active期间会用到的资源,比如对硬件的访问。理想情况下,不应该在这里执行需要大量时间的准备工作(比如冗长的硬件初始化,我猜测可能是单目SLAM的初始化这种)。
有效的状态切换;
- 如果
onActivate
回调函数成功执行,就会被切换到Active
状态。 - 如果执行出错就会切换到
ErrorProcessing
Deactivating
节点的onDeactivate
回调函数会被调用。函数中应当执行清除操作以便开始执行,并做onActivate
中相反的操作。
有效的状态切换;
- 如果
onDeactivate
回调函数成功执行,就会被切换到Active
状态。 - 如果执行出错就会切换到
ErrorProcessing
ShuttingDown
节点的onShutdown
回调函数会被调用。函数中应当执行销毁前的必要的清除。该状态应当可以从除了Finalized
的所有状态进入,函数中应当将节点返回到初始状态。
有效的状态切换;
- 如果
onShutdown
回调函数成功执行,就会被切换到Finalized
状态。 - 如果执行出错就会切换到
ErrorProcessing
ErrorProcessing
该状态是清除所有错误的地方。可以从所有状态进入该状态。如果错误被成功处理,那么会返回到Unconfigured
状态,如果没有执行所有的清理,那它必须失败然后切换到Finalized
状态并等待销毁。
到ErrorProcessing
切换可以是回调函数(或是回调函数中的函数)中生成的错误返回值以及未捕获的异常。
有效的状态切换;
- 如果
onError
回调函数成功执行,就会被切换到Unconfigured
状态。期望的是onError
会清除先前状态的所有状态。比如说如果是从Active
进入的,那么必须提供onDeactivate
和onCleanup
的来返回成功。 - 如果执行出错就会切换到
Finalized
实例
可以看下面的实例
#include <iostream>
#include <rclcpp/rclcpp.hpp>
#include <rclcpp_lifecycle/lifecycle_node.hpp>
#include "lifecycle_msgs/msg/transition.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class my_lifecyclenode : public rclcpp_lifecycle::LifecycleNode {
public:
// 构造函数
// lifecyclenode 的构造函数都有相同的参数
explicit my_lifecyclenode(const std::string& node_name, bool intra_process_comms = false)
: rclcpp_lifecycle::LifecycleNode(node_name,
rclcpp::NodeOptions().use_intra_process_comms(intra_process_comms)) {
}
void func() {
std::cout << "in func" << std::endl; }
// on_configure回调函数会在lifecyclenode进入configuring状态时被调用
// 根据返回值的不同,节点会进入inactive或者停留在unconfigured
// RANSITION_CALLBACK_SUCCESS transitions to "inactive"
// RANSITION_CALLBACK_FAILURE transitions to "unconfigured"
// TRANSITION_CALLBACK_ERROR or any uncaught exceptions to "errorprocessing"
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_configure(
const rclcpp_lifecycle::State&) {
RCLCPP_INFO(get_logger(), "on_configure() is called.");
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
}
// 没啥好说的,参考on_configure回调函数和前文
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_activate(
const rclcpp_lifecycle::State&) {
RCUTILS_LOG_INFO_NAMED(get_name(), "on_activate() is called.");
std::this_thread::sleep_for(2s);
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
}
//
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_deactivate(
const rclcpp_lifecycle::State&) {
RCUTILS_LOG_INFO_NAMED(get_name(), "on_deactivate() is called.");
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface