美烦资源网

专注技术文章分享,涵盖编程教程、IT 资源与前沿资讯

ROS2 Jazzy:使用C++创建并运行一个包含ROS参数的类(C++)


目标

使用C++创建并运行一个包含ROS参数的类。

背景信息

在创建自己的节点时,有时需要添加可以从启动文件中设置的参数。

本文将向你展示如何在C++类中创建这些参数,以及如何在启动文件中设置它们。

先决条件

在之前的教程中,你学习了如何创建工作空间和软件包,也了解了参数及其在ROS2系统中的功能。

操作步骤

1. 创建软件包

打开一个新终端,加载ROS2安装环境,确保ros2命令能够正常使用。

创建一个名为ros2_ws的新工作空间,并在此目录下创建src目录。

进入ros2_ws/src目录并创建一个新软件包:

ros2 pkg create --build-type ament_cmake --license Apache-2.0 cpp_parameters --dependencies rclcpp

终端将返回一条消息,确认cpp_parameters软件包及其所有必要文件和文件夹已创建。

参数--dependencies会自动将必要的依赖项添加到package.xml和CMakeLists.txt中。

1.1 更新package.xml

由于在创建软件包时使用了--dependencies选项,因此无需手动向package.xml或CMakeLists.txt添加依赖项。

不过,和往常一样,要确保在package.xml中添加描述、维护者电子邮件和姓名以及许可证信息。

<description>C++ parameter tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache-2.0</license>

2. 编写C++节点


ros2_ws/src/cpp_parameters/src目录下,创建一个名为cpp_parameters_node.cpp的新文件,并粘贴以下代码:

#include <chrono>
#include <functional>
#include <string>

#include <rclcpp/rclcpp.hpp>

using namespace std::chrono_literals;

class MinimalParam : public rclcpp::Node
{
public:
  MinimalParam()
  : Node("minimal_param_node")
  {
    this->declare_parameter("my_parameter", "world");

    auto timer_callback = [this](){
      std::string my_param = this->get_parameter("my_parameter").as_string();

      RCLCPP_INFO(this->get_logger(), "Hello %s!", my_param.c_str());

      std::vector<rclcpp::Parameter> all_new_parameters{rclcpp::Parameter("my_parameter", "world")};
      this->set_parameters(all_new_parameters);
    };
    timer_ = this->create_wall_timer(1000ms, timer_callback);
  }

private:
  rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalParam>());
  rclcpp::shutdown();
  return 0;
}

2.1 代码分析

开头的#include语句是软件包的依赖项。

接下来的代码创建了类和构造函数。构造函数的第一行创建了一个名为my_parameter、默认值为world的参数。参数类型由默认值推断得出,因此在这种情况下它被设置为字符串类型。

接下来,声明了一个名为timer_callback的lambda函数。它通过引用捕获当前对象this,不接受输入参数且不返回值。timer_callback函数的第一行从节点获取参数my_parameter,并将其存储在my_param中。

然后RCLCPP_INFO函数打印输出该事件日志。

紧接着set_parameters函数将参数my_parameter重置为默认字符串值world。如果用户从外部更改了参数,则此处将它重置为原始值。

最后,timer_被初始化为周期1000毫秒,这使得timer_callback函数每秒执行一次。

class MinimalParam : public rclcpp::Node
{
public:
  MinimalParam()
  : Node("minimal_param_node")
  {
    this->declare_parameter("my_parameter", "world");

    auto timer_callback = [this](){
      std::string my_param = this->get_parameter("my_parameter").as_string();

      RCLCPP_INFO(this->get_logger(), "Hello %s!", my_param.c_str());

      std::vector<rclcpp::Parameter> all_new_parameters{rclcpp::Parameter("my_parameter", "world")};
      this->set_parameters(all_new_parameters);
    };
    timer_ = this->create_wall_timer(1000ms, timer_callback);
  }

最后是timer_的声明。

private:
  rclcpp::TimerBase::SharedPtr timer_;

在MinimalParam类之后是main函数。在这里,ROS2被初始化,然后构造了MinimalParam类的一个实例,并且rclcpp::spin开始处理来自节点的数据。

int main(int argc, char ** argv)
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalParam>());
  rclcpp::shutdown();
  return 0;
}

2.1.1(可选)添加ParameterDescriptor

你可以选择为参数设置描述符。描述符允许你指定参数的文本描述及其约束条件,例如将其设置为只读、指定范围等。要实现这一点,构造函数中的代码就需要更改为:

// ...

class MinimalParam : public rclcpp::Node
{
public:
  MinimalParam()
  : Node("minimal_param_node")
  {
    auto param_desc = rcl_interfaces::msg::ParameterDescriptor{};
    param_desc.description = "This parameter is mine!";

    this->declare_parameter("my_parameter", "world", param_desc);

    auto timer_callback = [this](){
      std::string my_param = this->get_parameter("my_parameter").as_string();

      RCLCPP_INFO(this->get_logger(), "Hello %s!", my_param.c_str());

      std::vector<rclcpp::Parameter> all_new_parameters{rclcpp::Parameter("my_parameter", "world")};
      this->set_parameters(all_new_parameters);
    };
    timer_ = this->create_wall_timer(1000ms, timer_callback);

  }

其余代码保持不变。运行节点后,你可以运行ros2 param describe /minimal_param_node my_parameter查看参数类型和描述。

2.2 添加可执行文件

现在打开CMakeLists.txt文件。在依赖项find_package(rclcpp REQUIRED)下方添加以下代码行。

add_executable(minimal_param_node src/cpp_parameters_node.cpp)
ament_target_dependencies(minimal_param_node rclcpp)

install(TARGETS
    minimal_param_node
  DESTINATION lib/${PROJECT_NAME}
)

3. 编译并运行

在编译之前,在工作空间根目录(ros2_ws)运行rosdep检查缺失的依赖项是个好习惯:

rosdep install -i --from-path src --rosdistro jazzy -y

回到工作空间根目录ros2_ws,编译新软件包:

colcon build --packages-select cpp_parameters

打开一个新终端,进入ros2_ws目录并加载设置文件:

source install/setup.bash

现在运行节点:

ros2 run cpp_parameters minimal_param_node

终端应每秒返回以下消息:

[INFO] [minimal_param_node]: Hello world!

现在你看到了参数的默认值,但你可能希望能够自行设置它。有两种方法可以实现这一点。

3.1 通过控制台更改

这部分将运用你从参数相关教程中学到的知识,并将其应用到刚刚创建的节点上。

确保节点正在运行:

ros2 run cpp_parameters minimal_param_node

打开另一个终端,再次在ros2_ws目录下加载设置文件,然后输入以下命令:

ros2 param list

你将在其中看到自定义参数my_parameter。要更改它,只需在控制台中运行以下命令:

ros2 param set /minimal_param_node my_parameter earth

如果得到输出Set parameter successful,则表示更改成功。如果查看另一个终端,你应该会看到输出变为[INFO] [minimal_param_node]: Hello earth! 。

3.2 通过启动文件更改

你也可以在启动文件中设置参数,但首先需要添加启动目录。在
ros2_ws/src/cpp_parameters/目录下,创建一个名为launch的新目录。在其中创建一个名为cpp_parameters_launch.py的新文件:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='cpp_parameters',
            executable='minimal_param_node',
            name='custom_minimal_param_node',
            output='screen',
            emulate_tty=True,
            parameters=[custom_minimal_param_node
                {'my_parameter': 'earth'}
            ]
        )
    ])

在这里可以看到,在启动节点minimal_param_node时,我们将my_parameter设置为earth。通过添加以下两行,确保输出打印在控制台中。

output="screen",
emulate_tty=True,

现在打开CMakeLists.txt文件。在之前添加的代码行下方,添加以下代码行。

install(
  DIRECTORY launch
  DESTINATION share/${PROJECT_NAME}
)

打开一个控制台,进入工作空间根目录ros2_ws,构建新软件包:

colcon build --packages-select cpp_parameters

然后在新终端中加载设置文件:

source install/setup.bash

现在使用刚刚创建的启动文件运行节点:

ros2 launch cpp_parameters cpp_parameters_launch.py

终端首次应返回以下消息:

[INFO] [custom_minimal_param_node]: Hello earth!

后续输出应每秒显示[INFO] [minimal_param_node]: Hello world! 。

总结

你创建了一个带有自定义参数的节点,该参数可通过启动文件或命令行进行设置。你将依赖项、可执行文件和启动文件添加到软件包配置文件中,以便编译和运行它们,并观察参数的实际效果。


关注【智践行】公众号,发送 【机器人】 获得机器人经典学习资料

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言