当前位置:   article > 正文

【ROS2机器人入门到实战】参数之RCLCPP实现

rclcpp

2.参数之RCLCPP实现

写在前面

  1. 当前平台文章汇总地址:ROS2机器人从入门到实战
  2. 获取完整教程及配套资料代码,请关注公众号<鱼香ROS>获取
  3. 教程配套机器人开发平台:两驱版| 四驱版
  4. 为方便交流,搭建了机器人技术问答社区:地址 fishros.org.cn

上节我们通过参数控制了小乌龟模拟器的背景色,但是我们并不知道小乌龟模拟器是如何接收到参数并将其应用的,本节我们就学习使用ROS2的RCLCPP中参数相关的API实现对ROS2打印的日志级别控制。

ROS2将日志分为五个级别,在RCLCPP中通过不同的宏可以实现不同日志级别日志的打印,例程如下:

RCLCPP_DEBUG(this->get_logger(), "我是DEBUG级别的日志,我被打印出来了!");
RCLCPP_INFO(this->get_logger(), "我是INFO级别的日志,我被打印出来了!");
RCLCPP_WARN(this->get_logger(), "我是WARN级别的日志,我被打印出来了!");
RCLCPP_ERROR(this->get_logger(), "我是ERROR级别的日志,我被打印出来了!");
RCLCPP_FATAL(this->get_logger(), "我是FATAL级别的日志,我被打印出来了!");
  • 1
  • 2
  • 3
  • 4
  • 5

有时候日志太多,会让人眼花缭乱找不到重要信息,所以我们需要对日志的级别进行过滤,比如只看INFO以上级别的,ROS2中可以通过已有的API设置日志的级别,RCLCPP中API如下:

this->get_logger().set_level(log_level);
  • 1

1.创建功能包和节点

我们创建一个功能包和测试节点,声明参数并实现动态修改打印的日志级别功能。

mkdir -p chapt4/chapt4_ws/
ros2 pkg create example_parameters_rclcpp --build-type ament_cmake --dependencies rclcpp --destination-directory src --node-name parameters_basic --maintainer-name "fishros" --maintainer-email "fishros@foxmail.com"
  • 1
  • 2

parameters_basic.cpp

#include <chrono>
#include "rclcpp/rclcpp.hpp"

class ParametersBasicNode : public rclcpp::Node {
 public:
  explicit ParametersBasicNode(std::string name) : Node(name) {
    RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());
  }
 private:
};

int main(int argc, char** argv) {
  rclcpp::init(argc, argv);
  /*创建对应节点的共享指针对象*/
  auto node = std::make_shared<ParametersBasicNode>("parameters_basic");
  /* 运行节点,并检测退出信号*/
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

构建测试

colcon build  --packages-select example_parameters_rclcpp
source install/setup.bash
ros2 run example_parameters_rclcpp parameters_basic
  • 1
  • 2
  • 3

2.RCLCPP参数API

在RCLCPP的API中,关于参数相关的函数比较多些,但都是围绕参数获取参数设置参数描述列出参数添加移除参数回调事件。

3.使用参数控制节点日志级别

#include <chrono>
#include "rclcpp/rclcpp.hpp"
/*
    # declare_parameter	        声明和初始化一个参数
    # describe_parameter(name)  通过参数名字获取参数的描述
    # get_parameter	            通过参数名字获取一个参数
    # set_parameter	            设置参数的值
*/
class ParametersBasicNode : public rclcpp::Node {
 public:
  // 构造函数,有一个参数为节点名称
  explicit ParametersBasicNode(std::string name) : Node(name) {
    RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());
    this->declare_parameter("rcl_log_level", 0);     /*声明参数*/
    this->get_parameter("rcl_log_level", log_level); /*获取参数*/
    /*设置日志级别*/
    this->get_logger().set_level((rclcpp::Logger::Level)log_level);
    using namespace std::literals::chrono_literals;
    timer_ = this->create_wall_timer(
        500ms, std::bind(&ParametersBasicNode::timer_callback, this));
  }

 private:
  int log_level;
  rclcpp::TimerBase::SharedPtr timer_;

  void timer_callback() {
    this->get_parameter("rcl_log_level", log_level); /*获取参数*/
    /*设置日志级别*/
    this->get_logger().set_level((rclcpp::Logger::Level)log_level);
    std::cout<<"======================================================"<<std::endl;
    RCLCPP_DEBUG(this->get_logger(), "我是DEBUG级别的日志,我被打印出来了!");
    RCLCPP_INFO(this->get_logger(), "我是INFO级别的日志,我被打印出来了!");
    RCLCPP_WARN(this->get_logger(), "我是WARN级别的日志,我被打印出来了!");
    RCLCPP_ERROR(this->get_logger(), "我是ERROR级别的日志,我被打印出来了!");
    RCLCPP_FATAL(this->get_logger(), "我是FATAL级别的日志,我被打印出来了!");
  }
};

int main(int argc, char** argv) {
  rclcpp::init(argc, argv);
  /*创建对应节点的共享指针对象*/
  auto node = std::make_shared<ParametersBasicNode>("parameters_basic");
  /* 运行节点,并检测退出信号*/
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

代码解析

这里我们使用了三个参数相关的函数和一个设置节点日志级别的函数

  • declare_parameter,参数有两个参数名和参数值。
  • get_parameter,参数有两个,参数名和放入结果的变量。

设置日志级别

  • set_level,设置日志级别,ROS2的日志级别定义在文件/opt/ros/humble/include/rcutils/rcutils/logging.h的167-175行。

    /// The severity levels of log messages / loggers.
    enum RCUTILS_LOG_SEVERITY
    {
      RCUTILS_LOG_SEVERITY_UNSET = 0,  ///< The unset log level
      RCUTILS_LOG_SEVERITY_DEBUG = 10,  ///< The debug log level
      RCUTILS_LOG_SEVERITY_INFO = 20,  ///< The info log level
      RCUTILS_LOG_SEVERITY_WARN = 30,  ///< The warn log level
      RCUTILS_LOG_SEVERITY_ERROR = 40,  ///< The error log level
      RCUTILS_LOG_SEVERITY_FATAL = 50,  ///< The fatal log level
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

4.编译测试

colcon build --packages-select example_parameters_rclcpp
source install/setup.bash
ros2 run example_parameters_rclcpp parameters_basic
  • 1
  • 2
  • 3

运行后你会发现DEBUG级别的日志并没有被打印出来,原因在于我们将节点的日志级别设置为了0,0对应的日志级别为RCUTILS_LOG_SEVERITY_UNSET即未设置使用默认级别,节点默认的日志级别就是INFO级别的,所以只能打印INFO以上的日志信息。

在这里插入图片描述

运行节点的时候可以指定参数的值,我们尝试将log_level的值改成10DEBUG级别。

ros2 run example_parameters_rclcpp parameters_basic --ros-args -p rcl_log_level:=10
  • 1

在这里插入图片描述

再试试其他级别-FATAL

在这里插入图片描述

除了在节点运行前通过CLI传递参数,在运动的过程中也可以动态的修改参数

#查看参数列表
ros2 param list 
#设置参数级别
ros2 param set /parameters_basic rcl_log_level 10
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

5.总结

上面我们通过参数实现了动态控制节点日志级别的功能,其实像这样的功能ROS2早已为我们准备好了,在运行任意节点时候可以通过CLI传递日志级别配置。

ros2 run package-name node-name --ros-args --log-level debug
  • 1

除了命令行设置参数和查看日志,通过rqt也可以可视化设置和查看

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/727236
推荐阅读
  

闽ICP备14008679号