背景
通常,节点需要响应对其自身参数或其他节点参数的更改。ParameterEventHandler类可以很容易地监听参数更改,以便您的代码可以响应它们。本节介绍如何使用c++版本的ParameterEventHandler类来监视节点自身参数的更改以及对另一个节点参数的更改。
基础准备
在开始本教程之前,您应该首先熟悉以下教程:
理解参数6-理解参数-CSDN博客
在类中使用参数(c++)8-在类中使用参数-CSDN博客
任务
在本教程中,您将创建一个包含一些示例代码的新包,编写一些使用ParameterEventHandler类的c++代码,并测试生成的代码。
1. 创建一个包
首先,打开一个新的终端并source ROS 2,这样ros2命令就可以工作了。
创建一个名为ros2_ws的新工作目录。
回想一下,包应该在src目录中创建,而不是在工作区的根目录中。因此,进入到ros2_ws/src,然后在那里创建一个新包:
ros2 pkg create --build-type ament_cmake cpp_parameter_event_handler --dependencies rclcpp
您的终端将返回一条消息,验证包cpp_parameter_event_handler及其所有必要的文件和文件夹的创建。
--dependencies参数会自动将必要的依赖行添加到package.xml和CMakeLists.txt中。
1.1更新package.xml
因为您在包创建过程中使用了--dependencies选项,所以您不必手动向package.xml或CMakeLists.txt添加依赖项。但是,与往常一样,请确保在package.xml中添加描述、维护人员电子邮件和名称以及许可信息。
<description>C++ parameter events client tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>
2 编写c++节点
在ros2_ws/src/cpp_parameter_event_handler/src目录中,创建一个名为parameter_event_handler.cpp的新文件,并在其中粘贴以下代码:
#include <memory>
#include "rclcpp/rclcpp.hpp"
class SampleNodeWithParameters : public rclcpp::Node
{
public:
SampleNodeWithParameters()
: Node("node_with_parameters")
{
this->declare_parameter("an_int_param", 0);
// Create a parameter subscriber that can be used to monitor parameter changes
// (for this node's parameters as well as other nodes' parameters)
param_subscriber_ = std::make_shared<rclcpp::ParameterEventHandler>(this);
// Set a callback for this node's integer parameter, "an_int_param"
auto cb = [this](const rclcpp::Parameter & p) {
RCLCPP_INFO(
this->get_logger(), "cb: Received an update to parameter \"%s\" of type %s: \"%ld\"",
p.get_name().c_str(),
p.get_type_name().c_str(),
p.as_int());
};
cb_handle_ = param_subscriber_->add_parameter_callback("an_int_param", cb);
}
private:
std::shared_ptr<rclcpp::ParameterEventHandler> param_subscriber_;
std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle_;
};
int main(int argc, char ** argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<SampleNodeWithParameters>());
rclcpp::shutdown();
return 0;
}
2.1代码释义
包含第一个语句#include <memory>,以便代码可以利用std::make_shared模板。接下来,#include“rclcpp/rclcpp.hpp”允许代码引用rclcpp接口提供的各种功能,包括ParameterEventHandler类。
在类声明之后,代码定义了一个类SampleNodeWithParameters。该类的构造函数声明了一个整数形参an_int_param,默认值为0。接下来,代码创建一个ParameterEventHandler,它将用于监视参数的更改。最后,代码创建一个lambda函数,并将其设置为在an_int_param更新时调用的回调函数。
注意:保存add_parameter_callback返回的句柄是非常重要的;否则,回调将无法正确注册。
SampleNodeWithParameters()
: Node("node_with_parameters")
{
this->declare_parameter("an_int_param", 0);
// Create a parameter subscriber that can be used to monitor parameter changes
// (for this node's parameters as well as other nodes' parameters)
param_subscriber_ = std::make_shared<rclcpp::ParameterEventHandler>(this);
// Set a callback for this node's integer parameter, "an_int_param"
auto cb = [this](const rclcpp::Parameter & p) {
RCLCPP_INFO(
this->get_logger(), "cb: Received an update to parameter \"%s\" of type %s: \"%ld\"",
p.get_name().c_str(),
p.get_type_name().c_str(),
p.as_int());
};
cb_handle_ = param_subscriber_->add_parameter_callback("an_int_param", cb);
}
SampleNodeWithParameters之后是一个典型的main函数,它初始化ROS,旋转示例节点以便它可以发送和接收消息,然后在用户在控制台中输入^C后关闭。
int main(int argc, char ** argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<SampleNodeWithParameters>());
rclcpp::shutdown();
return 0;
}
2.2添加可执行文件
要构建此代码,首先打开CMakeLists.txt文件,并在依赖项find_package(rclcpp REQUIRED)下面添加以下代码行
add_executable(parameter_event_handler src/parameter_event_handler.cpp)
ament_target_dependencies(parameter_event_handler rclcpp)
install(TARGETS
parameter_event_handler
DESTINATION lib/${PROJECT_NAME}
)
3构建并运行
在构建之前,在工作区的根目录(ros2_ws)中运行rosdeep以检查缺失的依赖项是很好的做法:
rosdep install -i --from-path src --rosdistro $ROS_DISTRO -y
导航到工作区的根目录ros2_ws,并构建新包:
colcon build --packages-select cpp_parameter_event_handler
打开一个新终端,进入到ros2_ws,并source:
. install/setup.bash
现在运行节点:
ros2 run cpp_parameter_event_handler parameter_event_handler
该节点现在处于活动状态,有一个参数,并且在更新该参数时将打印一条消息。要对此进行测试,请打开另一个终端并像前面一样source(./install/setup.bash),并执行如下命令:
ros2 param set node_with_parameters an_int_param 43
运行该节点的终端将显示类似如下的消息:
[INFO] [1606950498.422461764] [node_with_parameters]: cb: Received an update to parameter "an_int_param" of type integer: "43"
我们之前在节点中设置的回调已被调用,并显示了更新后的新值。现在可以在终端中使用^C终止正在运行的parameter_event_handler示例。
3.1监控其他节点参数的变化
您还可以使用ParameterEventHandler监视另一个节点参数的参数更改。更新SampleNodeWithParameters类,以监视另一个节点中参数的更改。我们将使用parameter_blackboard demo来管理双参数,并且监视该参数的更新。
首先更新构造函数,在现有代码之后添加以下代码:
// Now, add a callback to monitor any changes to the remote node's parameter. In this
// case, we supply the remote node name.
auto cb2 = [this](const rclcpp::Parameter & p) {
RCLCPP_INFO(
this->get_logger(), "cb2: Received an update to parameter \"%s\" of type: %s: \"%.02lf\"",
p.get_name().c_str(),
p.get_type_name().c_str(),
p.as_double());
};
auto remote_node_name = std::string("parameter_blackboard");
auto remote_param_name = std::string("a_double_param");
cb_handle2_ = param_subscriber_->add_parameter_callback(remote_param_name, cb2, remote_node_name);
然后为额外的回调函数添加另一个成员变量cb_handle2:
private:
std::shared_ptr<rclcpp::ParameterEventHandler> param_subscriber_;
std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle_;
std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle2_; // Add this
};
在终端中,进入到工作区的根目录ros2_ws,并像前面一样编译更新后的包:
colcon build --packages-select cpp_parameter_event_handler
然后source一下:
source install/setup.bash
现在,为了测试参数的监控,首先运行新编译的parameter_event_handler代码:
ros2 run cpp_parameter_event_handler parameter_event_handler
接下来,从另一个终端(已初始化ROS)运行parameter_blackboard demo,如下所示:
ros2 run demo_nodes_cpp parameter_blackboard
最后,在第三个终端(已初始化ROS),在parameter_blackboard节点上设置一个参数:
ros2 param set parameter_blackboard a_double_param 3.45
执行此命令后,您应该在parameter_event_handler窗口中看到输出,表明在参数更新时调用了回调函数:
[INFO] [1606952588.237531933] [node_with_parameters]: cb2: Received an update to parameter "a_double_param" of type: double: "3.45"
总结
创建了一个带有参数的节点,并使用ParameterEventHandler类设置了一个回调,以监视对该参数的更改。还使用相同的类来监视对远程节点的更改。ParameterEventHandler是监视参数变化的一种方便的方法,这样就可以对更新后的值做出响应。