在类中使用参数(C++)

目标: 使用 C++ 创建并运行带有 ROS 参数的类。

教程级别: 初学者

时间: 20 分钟

背景

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

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

先决条件

在之前的教程中,您学习了如何 创建工作区创建包

您还了解了 参数 及其在 RO​​S 2 系统中的功能。

任务

1 创建一个包

打开一个新终端并 source your ROS 2 installation,以便 ros2 命令可以正常工作。

按照 these instructions 创建一个名为 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_callbacklambda 函数。 它执行当前对象 this 的按引用捕获,不接受输入参数并返回 void。 我们的 timer_callback 函数的第一行从节点获取参数 my_parameter,并将其存储在 my_param 中。 然后 RCLCPP_INFO 函数确保记录事件。 set_parameters 函数将参数 my_parameter 重新设置为默认字符串值 world

如果用户从外部更改了参数,这可确保始终将其重置回原始值。

最后,timer_ 以 1000ms 的周期初始化,这会导致 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”。 这里初始化了 ROS 2,构造了“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 (可选)添加参数描述符

您也可以选择为参数设置描述符。 描述符允许您指定参数及其约束的文本描述,例如将其设为只读、指定范围等。 为了实现此功能,必须将构造函数中的代码更改为:

// ...

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 rolling -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 通过控制台更改

本部分将使用您从 tutorial about parameters 获得的知识并将其应用于您刚刚创建的节点。

确保节点正在运行:

ros2 run cpp_parameters minimal_param_node

打开另一个终端,再次从“ros2_ws”内部获取安装文件,然后输入以下行:

ros2 param list

您将在那里看到自定义参数“my_parameter”。 要更改它,只需在控制台中运行以下行:

ros2 param set /minimal_param_node my_parameter earth

如果输出“设置参数成功”,则说明一切顺利。

如果查看另一个终端,则应该看到输出更改为“[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=[
                {"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!”。

摘要

您创建了一个具有自定义参数的节点,该参数可以从启动文件或命令行进行设置。

您将依赖项、可执行文件和启动文件添加到包配置文件中,以便您可以构建和运行它们,并查看参数的实际作用。

后续步骤

现在您有了一些自己的包和 ROS 2 系统,下一个教程 将向您展示如何在遇到问题时检查您的环境和系统中的问题。