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_node
  src/my_lifecycle_node.cpp)
ament_target_dependencies(my_lifecycle_node rclcpp rclcpp_lifecycle lifecycle_msgs std_msgs)

install(TARGETS
  my_lifecycle_node
  DESTINATION 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 files
  set(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 files
  set(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: inactive
        Goal: cleaningup
- activate [3]
        Start: inactive
        Goal: activating
- shutdown [6]
        Start: inactive
        Goal: 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生命周期节点总结 ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ARM:作业3

按键中断代码编写 代码: key_it.h #ifndef __KEY_IT_H__ #define __KEY_IT_H__#include "stm32mp1xx_gpio.h" #include "stm32mp1xx_exti.h" #include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gic.h"void key1_it_config(); voi…

2023年度盘点:AIGC、AGI、GhatGPT、人工智能大模型必读书单

2023年是人工智能大语言模型大爆发的一年&#xff0c;一些概念和英文缩写也在这一年里集中出现&#xff0c;很容易混淆&#xff0c;甚至把人搞懵。 LLM&#xff1a;Large Language Model&#xff0c;即大语言模型&#xff0c;旨在理解和生成人类语言。LLM的特点是规模庞大&…

【Maven技术专题】「入门到精通」教你如何使用Maven中引用依赖本地Jar包,并进行打包输出

前言 在使用Maven管理Java项目时&#xff0c;有时需要引入一些存放在系统特定位置的JAR文件。这些JAR文件可能是你自己编写的&#xff0c;也可能是其他来源的。无论是哪种情况&#xff0c;使用 Maven 的 system 范围和 systemPath 参数&#xff0c;可以方便地引入这些本地依赖…

2023-12-05 Qt学习总结10

点击 <C 语言编程核心突破> 快速C语言入门 Qt学习总结 前言二十六 学生信息管理系统插入介绍: QTableView和QSqlTableModelQTableViewQSqlTableModel 程序所用数据库表格程序组成以及界面学生端源码:管理员端源码: 总结 前言 要解决问题: 学习qt最核心知识, 多一个都不…

【MySQL】:数据类型

数据类型 一.数值类型1.整数1.tinyint2.bit类型 2.浮点类型1.float2.decimal 二.字符串类型1.char类型2.varchar类型3.char和varchar的区别4.日期和时间类型5.enum和set 三.集合查询 一.数值类型 1.整数 1.tinyint 正常插入 越界插入 如果我们向mysql特定的类型中插入不合法的…

[WMCTF2020]Make PHP Great Again require_once 特性

php源码分析 require_once 绕过不能重复包含文件的限制-安全客 - 安全资讯平台 这里是特性 我们首先来解释一下 <?php highlight_file(__FILE__); require_once flag.php; if(isset($_GET[file])) {require_once $_GET[file]; }这个是我们的源代码 PHP包含的格式是将 已…

SpringBoot系列之基于Jedis实现分布式锁

Redis系列之基于Jedis实现分布式锁 1、为什么需要分布式锁 在单机环境&#xff0c;我们使用最多的是juc包里的单机锁&#xff0c;但是随着微服务分布式项目的普及&#xff0c;juc里的锁是不能控制分布锁环境的线程安全的&#xff0c;因为单机锁只能控制同个进程里的线程安全&…

12月12日作业

设计一个闹钟 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimerEvent> #include <QTime> #include <QTime> #include <QTextToSpeech>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass …

开发提测?

前言 开发提测是正式开始测试的重要关卡&#xff0c;提测质量的好坏会直接影响测试阶段的效率&#xff0c;进而影响项目进度。较好的提测质量&#xff0c;对提高测试效率和优化项目进度有着事半功倍的作用。如何更好的推进开发提高提测质量呢&#xff1f;下面小编结合自己项目…

优化算法 学习记录

文章目录 相关资料 优化算法梯度下降学习率牛顿法 随机梯度下降小批量随机梯度下降动量法动量法解决上述问题 AdaGrad 算法RMSProp算法Adam学习率调度器余弦学习率调度预热 相关资料 李沐 动手学深度学习 优化算法 优化算法使我们能够继续更新模型参数&#xff0c;并使损失函…

【数据安全】金融行业数据安全保障措施汇总

数字化的今天&#xff0c;数据的价值不可估量&#xff0c;尤其是金融行业&#xff0c;数据不仅代表着企业的核心资产&#xff0c;还涉及到客户的隐私和信任。因此对于金融行业而言&#xff0c;保障数据安全至关重要。下面我们就来一起讨论为什么金融行业要保障数据安全&#xf…

基于Qt的蓝牙Bluetooth在ubuntu实现模拟

​# 前言 Qt 官方提供了蓝牙的相关类和 API 函数,也提供了相关的例程给我们参考。笔者根据 Qt官方的例程编写出适合我们 Ubuntu 和 gec6818开发板的例程。注意 Windows 上不能使用 Qt 的蓝牙例程,因为底层需要有 BlueZ协议栈,而 Windows 没有。Windows 可能需要去移植。笔者…

代码随想录算法训练营第三十六天|01背包问题 二维 ,01背包问题 一维 ,416. 分割等和子集

背包理论基础 01 背包&#xff08;二维&#xff09; 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 背包最大重量为4。 物品为&#x…

Docker入门指南:从基础到实践

在当今软件开发领域&#xff0c;Docker已经成为一种不可或缺的工具。通过将应用程序及其依赖项打包成轻量级的容器&#xff0c;Docker实现了开发、测试和部署的高度一致性。本文将深入研究Docker的基本概念&#xff0c;并通过详细的示例代码演示如何应用这些概念于实际场景中。…

学习IO的第八天

作业&#xff1a;使用信号灯循环输出ABC sem.c #include <head.h>union semun {int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminf…

InnoDB在SQL查询中的关键功能和优化策略

文章目录 前言存储引擎介绍存储引擎是干嘛的InnoDB的体系结构 InnoDB的查询操作InnoDB的查询原理引入 Buffer Pool引入数据页Buffer Pool 的结构数据页的加载Buffer Pool 的管理Buffer Pool 的优化 总结 前言 通过上篇文章《MySQL的体系结构与SQL的执行流程》了解了SQL语句的执…

IO第二天作业

1.用read write函数实现文件拷贝 程序 #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h> #include <stdlib.h> #include <string.h>int main(int argc, const char *argv[]){…

孩子还是有一颗网安梦——Bandit通关教程:Level 9 → Level 10

&#x1f575;️‍♂️ 专栏《解密游戏-Bandit》 &#x1f310; 游戏官网&#xff1a; Bandit游戏 &#x1f3ae; 游戏简介&#xff1a; Bandit游戏专为网络安全初学者设计&#xff0c;通过一系列级别挑战玩家&#xff0c;从Level0开始&#xff0c;逐步学习基础命令行和安全概念…

初学编程100个代码,python 基础 详细

本篇文章给大家谈谈初学编程100个代码&#xff0c;以及python 基础 详细&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 1.Python标识符 在 Python 里&#xff0c;标识符有字母、数字、下划线组成。 在 Python 中&#xff0c;所有标识符可以包括英文、数字以…

新版Spring Security6.2架构 (二) - Authentication

前言&#xff1a; 书接上文&#xff0c;继续官网的个人翻译和个人理解&#xff0c;有不对的请见谅。第一个篇博客中写到Sevlet appliation的总体架构&#xff0c;本博客是写Sevlet appliation中Authentication的架构&#xff0c;在后面第三篇博客将会写到新版spring security如…