navigation2基础-lifecycle_node 的使用

1 前言

由于ROS2没有提供杀死node方法,但是提供LifecycleNode,它允许对节点的生命周期进行详细管理。这种节点类似于状态机,可以在几种不同的状态之间切换。LifecycleNode的状态主要分为基本状态(Primary States)和切换状态(Transition States)。

1.1 基本状态

  • 未配置(Unconfigured):节点刚启动时的状态,未执行任何操作。
  • 非活跃(Inactive):节点持有资源但不执行任何操作,允许重新配置。
  • 活跃(Active):节点正常执行任务。
  • 已完成(Finalized):节点已被销毁,仅用于调试。

1.2 切换状态

  • 配置(Configuring):执行onConfigure()回调函数,加载配置和资源。

  • 清理(CleaningUp):执行onCleanup()回调函数,释放资源。

  • 激活(Activating):执行onActivate()回调函数,准备开始执行任务。

  • 停用(Deactivating):执行onDeactivate()回调函数,暂停执行任务。

  • 关闭(ShuttingDown):执行onShutdown()回调函数,进行销毁前的清理。

  • 错误处理(ErrorProcessing):执行onError()回调函数,处理错误。

2 写一个类继承nav2_util::LifecycleNode,实现状态的切换。

2.1 生成功能包:

ros2 pkg create ros_two_lifecycle_node --build-type ament_cmake --dependencies rclcpp rclcpp_lifecycle lifecycle_msgs nav2_util nav2_msgs std_msgs geometry_msgs  

生成配置文件:my_params.yaml

my_lifecycle_node:
  ros__parameters:
    publish_topic: "/print_log"
    subscribe_topic: "/cmd_vel"
    my_string_param: "world"

2.2 创建my_lifecycle_node.hpp文件

#ifndef MY_LIFECYCLE_PKG__MY_LIFECYCLE_NODE_HPP_
#define MY_LIFECYCLE_PKG__MY_LIFECYCLE_NODE_HPP_

#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/lifecycle_node.hpp"
#include "nav2_util/lifecycle_node.hpp"
#include "std_msgs/msg/string.hpp"
#include "geometry_msgs/msg/twist.hpp"

namespace my_lifecycle_pkg
{
class MyLifecycleNode : public nav2_util::LifecycleNode
{
public:
  explicit MyLifecycleNode(const rclcpp::NodeOptions & options = rclcpp::NodeOptions());
  ~MyLifecycleNode();
  // 生命周期管理
  nav2_util::CallbackReturn on_configure(const rclcpp_lifecycle::State & state) override;
  nav2_util::CallbackReturn on_activate(const rclcpp_lifecycle::State & state) override;
  nav2_util::CallbackReturn on_deactivate(const rclcpp_lifecycle::State & state) override;
  nav2_util::CallbackReturn on_cleanup(const rclcpp_lifecycle::State & state) override;
  nav2_util::CallbackReturn on_shutdown(const rclcpp_lifecycle::State & state) override;
private:
  // 定时器回调函数
  void timer_callback();  
  // 订阅者回调函数
  void subscription_callback(const geometry_msgs::msg::Twist::SharedPtr msg);
  // ROS2相关成员变量  std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<std_msgs::msg::String>> publisher_;
  rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr subscription_;
  rclcpp::TimerBase::SharedPtr timer_;  
  // 计数器
  size_t count_;  
  // 话题名称
  std::string publish_topic_;
  std::string subscribe_topic_;  
};
}  // namespace my_lifecycle_pkg

#endif  // MY_LIFECYCLE_PKG__MY_LIFECYCLE_NODE_HPP_

2.3 创建my_lifecycle_node.cpp文件

#include "ros_two_lifecycle_node/my_lifecycle_node.hpp"

#include <chrono>
#include <memory>
#include <string>

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/lifecycle_node.hpp"
#include <lifecycle_msgs/msg/state.hpp> 
#include "std_msgs/msg/string.hpp"
#include "geometry_msgs/msg/twist.hpp"

using namespace std::chrono_literals;

namespace my_lifecycle_pkg
{

MyLifecycleNode::MyLifecycleNode(const rclcpp::NodeOptions & options)
: nav2_util::LifecycleNode("my_lifecycle_node", "", options),
  count_(0)
{
  // 声明参数
  this->declare_parameter("publish_topic", "/motion_state");
  this->declare_parameter("subscribe_topic", "/cmd_vel");
  
  // 获取参数值
  publish_topic_ = this->get_parameter("publish_topic").as_string();
  subscribe_topic_ = this->get_parameter("subscribe_topic").as_string();
  
  RCLCPP_INFO(this->get_logger(), "MyLifecycleNode constructed");
}

MyLifecycleNode::~MyLifecycleNode()
{
  RCLCPP_INFO(this->get_logger(), "MyLifecycleNode destroyed");
}

nav2_util::CallbackReturn MyLifecycleNode::on_configure(const rclcpp_lifecycle::State & state)
{
  (void)state;
  RCLCPP_INFO(this->get_logger(), "on_configure() called");
  
  // 创建发布者(生命周期发布者)
  publisher_ = this->create_publisher<std_msgs::msg::String>(publish_topic_, 10);
  
  // 创建订阅者
  subscription_ = this->create_subscription<geometry_msgs::msg::Twist>(
    subscribe_topic_, 10,
    std::bind(&MyLifecycleNode::subscription_callback, this, std::placeholders::_1));
  
  // 创建定时器(但不立即启动)
  timer_ = this->create_wall_timer(
    1000ms, std::bind(&MyLifecycleNode::timer_callback, this));
  
  // 初始状态下停止定时器
  timer_->cancel();
  
  RCLCPP_INFO(this->get_logger(), "Configuration completed successfully");
  return nav2_util::CallbackReturn::SUCCESS;
}

nav2_util::CallbackReturn MyLifecycleNode::on_activate(const rclcpp_lifecycle::State & state)
{
  (void)state;
  RCLCPP_INFO(this->get_logger(), "on_activate() called");
  
  // 激活发布者
  publisher_->on_activate();
  
  // 启动定时器
  timer_->reset();
  
  RCLCPP_INFO(this->get_logger(), "Node activated");
  return nav2_util::CallbackReturn::SUCCESS;
}

nav2_util::CallbackReturn MyLifecycleNode::on_deactivate(const rclcpp_lifecycle::State & state)
{
  (void)state;
  RCLCPP_INFO(this->get_logger(), "on_deactivate() called");
  
  // 停止定时器
  timer_->cancel();
  
  // 停用发布者
  publisher_->on_deactivate();
  
  RCLCPP_INFO(this->get_logger(), "Node deactivated");
  return nav2_util::CallbackReturn::SUCCESS;
}

nav2_util::CallbackReturn MyLifecycleNode::on_cleanup(const rclcpp_lifecycle::State & state)
{
  (void)state;
  RCLCPP_INFO(this->get_logger(), "on_cleanup() called");
  
  // 清理资源
  timer_.reset();
  publisher_.reset();
  subscription_.reset();
  
  count_ = 0;
  
  RCLCPP_INFO(this->get_logger(), "Node cleaned up");
  return nav2_util::CallbackReturn::SUCCESS;
}

nav2_util::CallbackReturn MyLifecycleNode::on_shutdown(const rclcpp_lifecycle::State & state)
{
  (void)state;
  RCLCPP_INFO(this->get_logger(), "on_shutdown() called");
  
  // 关闭时清理资源
  timer_.reset();
  publisher_.reset();
  subscription_.reset();
  
  RCLCPP_INFO(this->get_logger(), "Node shutdown completed");
  return nav2_util::CallbackReturn::SUCCESS;
}

void MyLifecycleNode::timer_callback()
{
  auto message = std_msgs::msg::String();
  message.data = "Hello, ROS2! Count: " + std::to_string(count_++);
  
  // 只有在激活状态下才发布消息
  if (publisher_->is_activated()) {
    publisher_->publish(message);
    RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
  }
}

void MyLifecycleNode::subscription_callback(const geometry_msgs::msg::Twist::SharedPtr msg)
{
  RCLCPP_INFO(
    this->get_logger(), 
    "Received Twist: linear.x=%.2f, angular.z=%.2f", 
    msg->linear.x, msg->angular.z
  );
}

}  // namespace my_lifecycle_pkg

int main(int argc, char **argv) 
{
    rclcpp::init(argc, argv);
    auto node = std::make_shared<my_lifecycle_pkg::MyLifecycleNode>();
    
    // 加载参数
    auto synchronous_client = std::make_shared<rclcpp::SyncParametersClient>(node);
    synchronous_client->load_parameters("/home/yahboom/ros2_ws/src/ros_two_lifecycle_node/config/my_params.yaml");

    nav2_util::CallbackReturn ret_;

    // 获取当前状态
    auto current_state = node->get_current_state();
    
    // 如果当前状态是 UNCONFIGURED,则配置节点
    if (current_state.id() == lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED)
    {
        node->configure(ret_);
        if (ret_ != nav2_util::CallbackReturn::SUCCESS) 
        {
            RCLCPP_ERROR(rclcpp::get_logger("main"), "Configure failed");
            return 1;
        }
        RCLCPP_INFO(node->get_logger(), "Configured successfully.");
        
        // 更新状态
        current_state = node->get_current_state();
    }

    // 如果当前状态是 INACTIVE,则激活节点
    if (current_state.id() == lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE)
    {
        node->activate(ret_);
        if (ret_ != nav2_util::CallbackReturn::SUCCESS) {
            RCLCPP_ERROR(rclcpp::get_logger("main"), "Activate failed");
            return 1;
        }
        RCLCPP_INFO(node->get_logger(), "Activated successfully.");
        
        // 更新状态
        current_state = node->get_current_state();
    }

    // 等待一段时间
    RCLCPP_INFO(node->get_logger(), "Node running for 10 seconds...");
    std::this_thread::sleep_for(std::chrono::seconds(10));
    
    // 正确的状态转换顺序:active -> inactive -> unconfigured -> finalized
    if (current_state.id() == lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE)
    {
        // 先停用
        node->deactivate(ret_);
        if (ret_ != nav2_util::CallbackReturn::SUCCESS) {
            RCLCPP_ERROR(rclcpp::get_logger("main"), "Deactivate failed");
            return 1;
        }
        RCLCPP_INFO(node->get_logger(), "Deactivated successfully.");
        
        // 更新状态
        current_state = node->get_current_state();
    }
    
    if (current_state.id() == lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE)
    {
        // 再清理
        node->cleanup(ret_);
        if (ret_ != nav2_util::CallbackReturn::SUCCESS) {
            RCLCPP_ERROR(rclcpp::get_logger("main"), "Cleanup failed");
            return 1;
        }
        RCLCPP_INFO(node->get_logger(), "Cleaned up successfully.");
        
        // 更新状态
        current_state = node->get_current_state();
    }
    
    if (current_state.id() == lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED)
    {
        // 最后关闭
        node->shutdown(ret_);
        if (ret_ != nav2_util::CallbackReturn::SUCCESS) {
            RCLCPP_ERROR(rclcpp::get_logger("main"), "Shutdown failed");
            return 1;
        }
        RCLCPP_INFO(node->get_logger(), "Shutdown completed successfully.");
    }

    rclcpp::shutdown();
    return 0;
}

2.4 配置 CMakeLists.txt
修改 CMakeLists.txt 文件:


include_directories(
  include 
  ${rclcpp_INCLUDE_DIRS}
) 

set(dependencies
  rclcpp 
  std_msgs 
  rclcpp_lifecycle 
  geometry_msgs 
  lifecycle_msgs 
  nav2_util
  nav2_msgs
)

add_executable(lifecycle_node src/my_lifecycle_node.cpp)
ament_target_dependencies(lifecycle_node ${dependencies})
install(TARGETS lifecycle_node
  DESTINATION lib/${PROJECT_NAME})

3.编译并执行

编译

colcon build --packages-select ros_two_lifecycle_node

执行:

source install/local_setup.sh
ros2 run ros_two_lifecycle_node lifecycle_node

执行结果:
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值