ROS2 LifecycleNode讲解及实例

LifecycleNode讲解及实例

文章目录

  • 前言
  • LifecycleNode是什么
    • 背景
    • 生命周期
    • 状态定义
      • Unconfigured
      • Inactive
      • Active
      • Finalized
    • 转换逻辑图示
    • 标准接口
  • 代码实现&测试
    • 代码
    • 测试
  • 总结

前言

本文用来记录什么是LifecycleNode,做背景介绍及基本原理的介绍及分析如何使用。1

LifecycleNode是什么

背景

节点的托管生命周期允许更好地控制ROS系统的状态。它将允许roslaunch在允许任何组件开始执行其行为之前确保所有组件都已正确实例化。它还允许重新启动或在线更换节点。

本文档最重要的概念是,受管节点提供已知接口,根据已知的生命周期状态机执行,否则可被视为黑盒。这使得节点开发人员可以自由决定如何提供托管生命周期功能,同时还确保为管理节点而创建的任何工具都可以与任何兼容的节点一起使用。

生命周期

有四个主要状态:

  • Unconfigured
  • Inactive
  • Active
  • Finalized

还存在6个过渡状态,它们是在所请求的过渡期间的中间状态。

  • Configuring
  • CleaningUp
  • ShuttingDown
  • Activating
  • Deactivating
  • ErrorProcessing

在转换状态中,将执行逻辑以确定转换是否成功。成功或失败应通过生命周期管理界面传达给生命周期管理软件。

有7个过渡暴露于监督流程,它们是:

  • create
  • configure
  • cleanup
  • activate
  • deactivate
  • shutdown
  • destroy

状态定义

Unconfigured

这是节点在实例化后立即处于的生命周期状态。这也是节点在发生错误后可能返回的状态。

  • 节点可以经由 configure 转换转换到 Inactive 状态
  • 节点可以经由 shutdown 转换转换到 Finalized 状态

Inactive

此状态表示当前未执行任何处理的节点。

此状态的主要目的是允许节点在运行时进行配置(更改配置参数、添加和删除主题发布/订阅等),而不更改其行为。

当处于这种状态时,节点将不会接收任何执行时间来读取主题、执行数据处理、响应功能服务请求等。

在非活动状态下,将不会读取和/或处理到达托管主题的任何数据。数据保留将受为主题配置的QoS策略的约束。

对处于非活动状态的节点的任何托管服务请求都不会被应答(对于调用者来说,它们将立即失败)。

  • 节点可以经由 shutdown 转换转换到 Finalized 状态
  • 节点可以经由 cleanup 转换转换到 Unconfigured 状态
  • 节点可以经由 activate 转换转换到 Active 状态

Active

这是节点生命周期的主要状态。在这种状态下,节点执行任何处理,响应服务请求,读取和处理数据,产生输出等。

如果在此状态下发生节点/系统无法处理的错误,则节点将转换到 ErrorProcessing

  • 节点可以经由 deactivate 转换转换到 Inactive 状态
  • 节点可以经由 shutdown 转换转换到 Finalized 状态

Finalized

Finalized 状态是节点在被销毁之前立即结束的状态。这个状态总是终结的,从这里开始的唯一转变就是被摧毁。

转换逻辑图示

下边这张图用来说明状态切换之间的关系,如果看不懂也没关系,可以根据后续的测试代码切换一遍流程即可理解。2

请添加图片描述

标准接口

服务(Service):3

  • /change_state - 调用触发合法转换

  • /get_available_transitions - 显示合法的转换

  • /get_state - 显示当前状态

  • /get_available_states - 列出所有状态

  • /get_transition_graph - 显示完整状态机

主题(Topic):

  • /transition_event - 发布正在进行的转换

代码实现&测试

代码

# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(my_lifecycle_node)if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic)
endif()# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_lifecycle REQUIRED)
find_package(lifecycle_msgs REQUIRED)
find_package(std_msgs REQUIRED)add_executable(my_lifecycle_nodesrc/my_lifecycle_node.cpp)
ament_target_dependencies(my_lifecycle_node rclcpp rclcpp_lifecycle lifecycle_msgs std_msgs)install(TARGETSmy_lifecycle_nodeDESTINATION lib/${PROJECT_NAME}
)if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)# the following line skips the linter which checks for copyrights# comment the line when a copyright and license is added to all source filesset(ament_cmake_copyright_FOUND TRUE)# the following line skips cpplint (only works in a git repo)# comment the line when this package is in a git repo and when# a copyright and license is added to all source filesset(ament_cmake_cpplint_FOUND TRUE)ament_lint_auto_find_test_dependencies()
endif()ament_package()
# package.xml<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"><name>my_lifecycle_node</name><version>0.0.0</version><description>TODO: Package description</description><maintainer email="https://blog.csdn.net/Bing_Lee">dev</maintainer><license>TODO: License declaration</license><buildtool_depend>ament_cmake</buildtool_depend><depend>rclcpp</depend><depend>rclcpp_lifecycle</depend><depend>lifecycle_msgs</depend><depend>std_msgs</depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_cmake</build_type></export>
</package>
#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_lifecycle_node : public rclcpp_lifecycle::LifecycleNode
{
public:explicit my_lifecycle_node(const std::string& node_name, bool intra_process_comms = false): rclcpp_lifecycle::LifecycleNode(node_name, rclcpp::NodeOptions().use_intra_process_comms(intra_process_comms)) {}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;}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::CallbackReturn::SUCCESS;}rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_cleanup(const rclcpp_lifecycle::State&){RCUTILS_LOG_INFO_NAMED(get_name(), "on cleanup() is called.");return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;}rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_shutdown(const rclcpp_lifecycle::State& state){RCUTILS_LOG_INFO_NAMED(get_name(), "on shutdown() is called from state %s.", state.label().c_str());return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;}
};int main(int argc, char** argv)
{rclcpp::init(argc, argv);auto node = std::make_shared<my_lifecycle_node>("my_lifecycle_node");rclcpp::spin(node->get_node_base_interface());rclcpp::shutdown();return 0;
}
# 文件结构
$ tree my_lifecycle_node/
my_lifecycle_node/
├── CMakeLists.txt
├── include
│   └── my_lifecycle_node
├── package.xml
└── src└── my_lifecycle_node.cpp

测试

# 编译
$ colcon build --packages-up-to my_lifecycle_node
# bash 安装配置
$ source install/setup.bash
# 运行
$ ros2 run my_lifecycle_node my_lifecycle_node

新开一个窗口

$ ros2 service list
/my_lifecycle_node/change_state
/my_lifecycle_node/describe_parameters
/my_lifecycle_node/get_available_states
/my_lifecycle_node/get_available_transitions
/my_lifecycle_node/get_parameter_types
/my_lifecycle_node/get_parameters
/my_lifecycle_node/get_state
/my_lifecycle_node/get_transition_graph
/my_lifecycle_node/list_parameters
/my_lifecycle_node/set_parameters
/my_lifecycle_node/set_parameters_atomically$ ros2 topic list
/my_lifecycle_node/transition_event
/parameter_events
/rosout

状态切换

# 当前状态
$ ros2 lifecycle get /my_lifecycle_node 
unconfigured [1]
# 配置节点
$ ros2 lifecycle set /my_lifecycle_node configure
Transitioning successful$ ros2 lifecycle get /my_lifecycle_node 
inactive [2]
# 激活节点
$ ros2 lifecycle set /my_lifecycle_node activate
Transitioning successful$ ros2 lifecycle get /my_lifecycle_node 
active [3]
# 停止节点
$ ros2 lifecycle set /my_lifecycle_node deactivate
Transitioning successful$ ros2 lifecycle get /my_lifecycle_node 
inactive [2]
# 获取当前节点可转换的状态
$ ros2 lifecycle list /my_lifecycle_node 
- cleanup [2]Start: inactiveGoal: cleaningup
- activate [3]Start: inactiveGoal: activating
- shutdown [6]Start: inactiveGoal: shuttingdown
# 杀掉节点
$ ros2 lifecycle set /my_lifecycle_node shutdown
Transitioning successful$ ros2 lifecycle get /my_lifecycle_node 
finalized [4]
# 尝试切换杀掉的(状态为finalized)节点,失败
$ ros2 lifecycle set /my_lifecycle_node configure
Unknown transition requested, available ones are:

总结

本文对于LifecycleNode做了整体的说明和测试,说明了中间的变换关系,方便大家理解和用于实际使用中。


  1. ros.rog Class LifecycleNode ↩︎

  2. Managed nodes (ros2.org) ↩︎

  3. ROS2----LifecycleNode生命周期节点总结 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/217455.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大数据】Doris 架构

Doris 架构 Doris 的架构很简洁&#xff0c;只设 FE&#xff08;Frontend&#xff09;、BE&#xff08;Backend&#xff09;两种角色、两个进程&#xff0c;不依赖于外部组件&#xff0c;方便部署和运维&#xff0c;FE、BE 都可线性扩展。 ✅ Frontend&#xff08;FE&#xff0…

十六 动手学深度学习v2计算机视觉 ——样式迁移

文章目录 基于CNN的样式迁移 基于CNN的样式迁移 我们通过前向传播&#xff08;实线箭头方向&#xff09;计算风格迁移的损失函数&#xff0c;并通过反向传播&#xff08;虚线箭头方向&#xff09;迭代模型参数&#xff0c;即不断更新合成图像。 风格迁移常用的损失函数由3部分组…

Linux - 进程间通信(中)- 管道的应用场景

前言 在上篇博客当中&#xff0c;对Linux 当中的进程通信&#xff0c;做了详细阐述&#xff0c;主要是针对父子进程的通信来阐述的同时&#xff0c;也进行了模拟实现。 对于管道也有了初步了解&#xff0c;但是这仅仅是 进程间通信的一部分&#xff0c;Linux 当中关于进程间通…

无人机风速风向仪-百科小天地

随着科技的不断进步&#xff0c;无人机技术已经广泛应用于各个领域&#xff0c;包括气象监测。近年来&#xff0c;无人机风速风向仪的出现&#xff0c;为气象监测带来了革命性的变革。本文将介绍无人机风速风向仪的原理、优势以及在气象监测领域的应用&#xff0c;让我们一起领…

golang 操作Jenkins

1.創建Agent/Node func CreateAgent(username string, password string, nodeName string, nodeDescription string, numExecutors string, remoteFS string, labelString string, host string) {var obj stringobj "{name:" nodeName ",nodeDescription:&q…

YOLOv4 学习笔记

文章目录 前言一、YOLOv4贡献和改进二、YOLOv4核心概念三、YOLOv4网络架构四、YOLOv4数据增强五、YOLOv4的损失函数总结 前言 在近年来的目标检测领域&#xff0c;YOLOv4的出现标志着一个重要的技术突破。YOLOv4不仅继承了YOLO系列快速、高效的特点&#xff0c;还引入了一系列…

CSS | 文档流 | Box盒模型 | FC BFC、IFC、FFC、GFC

文档流 “在一个块格式区域中,盒子会从包含块的顶部开始,按序垂直排列(受书写模式影响)。同级盒子间的垂直距离会由“margin”属性决定。相邻两个块级盒子之间的垂直间距会遵循外边距折叠原则被折叠。在一个块格式区域中,每个盒子的左外边缘会与包含块左边缘重合(如果是从右…

《微信小程序开发从入门到实战》学习四十九

4.5 实现投票小程序服务端功能 4.5.1 完成获取投票信息功能 修改pages/vote/vote.js文件中getVoteDataFromServer函数&#xff0c;代码如下&#xff1a; getVoteDataFromServer(voteID) { const db wx.cloud.database() db.collection(votes).doc(voteID).get().then(res &…

【启扬方案】启扬储能管理平板助力储能电站实现智能且高效化运行

在储能领域&#xff0c;储能电站扮演着重要角色&#xff0c;储能电站技术的应用贯穿于电力系统发电、输电、配电、用电的各个环节。实现电力系统削峰填谷、可再生能源发电波动平滑与跟踪计划处理、高效系统调频&#xff0c;增加供电的可靠性。 但随着储能电⼒系统建设发展得越来…

Java网络编程,使用UDP实现TCP(三), 基本实现四次挥手

简介 四次挥手示意图 在四次挥手过程中&#xff0c;第一次挥手中的Seq为本次挥手的ISN&#xff0c; ACK为 上一次挥手的 Seq1&#xff0c;即最后一次数据传输的Seq1。挥手信息由客户端首先发起。 实现步骤&#xff1a; 下面是TCP四次挥手的步骤&#xff1a; 第一次挥手&…

记录一下如何使用python生成二维码 并简单练习命令行参数供初学者参考

主代码main.py 后面是演示效果图&#xff1a; import argparse import sysimport qrcode import os qr qrcode.QRCode(version1,error_correctionqrcode.constants.ERROR_CORRECT_L,box_size10,border4, ) fileList[] fileName[]parserargparse.ArgumentParser(description生…

Ubuntu20.04降低linux版本到5.4.0-26-generic

前言 试用ubuntu20.04安装昇腾的驱动和cann的时&#xff0c;出现如下问题&#xff1a; (base) rootubuntu:/home/work# ./Ascend-hdk-910-npu-driver_23.0.rc3_linux-aarch64.run --full Verifying archive integrity... 100% SHA256 checksums are OK. All good. Uncompr…

基于Python+WaveNet+MFCC+Tensorflow智能方言分类—深度学习算法应用(含全部工程源码)(三)

目录 前言引言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 模型构建1&#xff09;定义模型结构2&#xff09;优化损失函数 3. 模型训练及保存1&#xff09;模型训练2&#xff09;模型保存3&#xff09;映射保存 相关其它博客工程源代码下载其它资料下载…

“百里挑一”AI原生应用亮相,百度智能云千帆AI加速器首个Demo Day来了!

作者简介&#xff1a; 辭七七&#xff0c;目前大二&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

亚马逊云科技:向量数据存储在生成式人工智能应用程序中的作用

生成式人工智能深受大众喜爱&#xff0c;并且由于具备回答问题、写故事、创作艺术品甚至生成代码的功能&#xff0c;推动了行业的转变&#xff0c;那么如何才能在自己的企业中充分地利用生成式人工智能等应运而生问题。许多客户已经积累了大量特定领域的数据&#xff08;财务记…

深入理解Disruptor - 无锁并发框架的革命

1. Disruptor框架简介 概述&#xff1a; Disruptor是一种高性能的内存队列&#xff0c;最初由LMAX开发&#xff0c;目的是在低延迟交易系统中替代传统的阻塞队列。它通过使用环形数组和无锁的发布/订阅模式&#xff0c;显著降低了线程间通信的延迟。这种设计使得它在多生产者-…

【1day】​万户协同办公平台 iWebPDF/DocumentEdit.jsp文件 SQL注入漏洞学习

注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现

如何构建和安装Go程序

引言 到目前为止,在我们的[如何在Go中编码]系列中,您已经使用命令[go run]自动编译源代码并运行生成的可执行文件。尽管这个命令对于在命令行中测试你的代码很有用,但发布或部署你的应用程序需要你将代码构建为可共享的二进制可执行文件,或包含可以运行你的应用程序的机器…

LangChain学习二:提示-实战(下半部分)

文章目录 上一节内容&#xff1a;LangChain学习二&#xff1a;提示-实战&#xff08;上半部分&#xff09;学习目标&#xff1a;提示词中的示例选择器和输出解释器学习内容一&#xff1a;示例选择器1.1 LangChain自定义示例选择器1.2 实现自定义示例选择器1.2.1实战&#xff1a…

静态路由的原理和配置

一.路由器的工作原理 首先我们知道路由器是工作在网络层的&#xff0c;那就是三层设备。网络层的功能主要为&#xff1a;不同网段之间通信、最佳路径选择也就是逻辑地址&#xff08;ip地址&#xff09;寻址、转发数据。 1.路由器是什么 路由器是能将数据包转发到正确的目的地…