在单个进程中组合多个节点
基础使用
查找可用组件
ros2 component types
运行时组合ROS服务的pub与sub
# 终端1中启动组件容器
ros2 run rclcpp_components component_container
# 终端2中确定在运行的容器
ros2 component list
# 你应该看到有 /ComponentManager 组件名称
# 在终端2中加载talker组件
ros2 component load /ComponentManager composition composition::Talker
# 该命令返回加载组件的唯一ID以及节点名称 Loaded component 1 into '/ComponentManager' container node as '/talker'
# 现在终端1 应该显示 已加载组件的消息以及用于发布消息的重复消息
[INFO] [1721370343.552024029] [talker]: Publishing: 'Hello World: 1'
[INFO] [1721370344.552077267] [talker]: Publishing: 'Hello World: 2'
[INFO] [1721370345.552069042] [talker]: Publishing: 'Hello World: 3'
[INFO] [1721370346.552111748] [talker]: Publishing: 'Hello World: 4'
[INFO] [1721370347.552224869] [talker]: Publishing: 'Hello World: 5'
[INFO] [1721370348.552158623] [talker]: Publishing: 'Hello World: 6'
[INFO] [1721370349.552194409] [talker]: Publishing: 'Hello World: 7'
[INFO] [1721370350.552245410] [talker]: Publishing: 'Hello World: 8'
# 终端2中加载listener组件
ros2 component load /ComponentManager composition composition::Listener
# 返回 Loaded component 2 into '/ComponentManager' container node as '/listener'

# 终端2
ros2 component list
# 现在应该显示以下结果
/ComponentManager
1 /talker
2 /listener
运行时组合ROS服务的server与client
客户端向服务器发送请求,服务器处理请求并返回响应,客户端打印接收到的响应。
# 终端1
ros2 run rclcpp_components component_container

# 终端2
ros2 component load /ComponentManager composition composition::Server
ros2 component load /ComponentManager composition composition::Client
编译时组合hardcoded nodes
-
此实例演示可以使用相同的共享库来编译运行多个组件的单个可执行文件,而无需使用共享接口。
-
此实例包含上述所有四个组件:pub、sub、server、client,这些组件在mian函数中是
hardcoded
。
ros2 run composition manual_composition
- 手动组成的组件不会被
ros2 component list
输出出来。
运行时组合dlopen
- 此实例演示了运行时组合的代替方案,即创建一个通用的容器进程,并显式传递要加载的库,而不是使用ros接口。该过程打开每个库,并在库中创建每个
rclcpp::Node
类的实例。
ros2 run composition dlopen_composition `ros2 pkg prefix composition`/lib/libtalker_component.so `ros2 pkg prefix composition`/lib/liblistener_component.so
- 由
dlopen
组成的组件不会被ros2 component list
输出出来。
使用launch进行组合
ros2 launch composition composition_demo.launch.py
进阶操作
卸载组件
# 终端1 启动组件
ros2 run rclcpp_components component_container
# 终端2 list运行中的容器
ros2 component list
# 应输出组件名称 /ComponentManager

# 终端2 加载 talker 和 listener
ros2 component load /ComponentManager composition composition::Talker
ros2 component load /ComponentManager composition composition::Listener
# 终端2 使用唯一id从组件容器中卸载节点
ros2 component unload /ComponentManager 1 2
# 终端应返回
Unloaded component 1 from '/ComponentManager' container
Unloaded component 2 from '/ComponentManager' container
# 在终端1中,消息已停止
重新映射容器名称和命名空间
- 组件管理器名称和命名空间可以通过命令行参数重新映射
ros2 run rclcpp_components component_container --ros-args -r __node:=MyContainer -r __ns:=/ns
- 重映射完成后可以使用更新后的容器名来加载
ros2 component load /ns/MyContainer composition composition::Listener
重映射组件名称和命名空间
- 启动组件容器
ros2 run rclcpp_components component_container
- 重映射节点名称
ros2 component load /ComponentManager composition composition::Talker --node-name talker2
- 重映射命名空间名称
ros2 component load /ComponentManager composition composition::Talker --node-namespace /ns
- 全部重映射
ros2 component load /ComponentManager composition composition::Talker --node-name talker3 --node-namespace /ns2
- ros2 component list
ros2 component list
# 应输出
/ComponentManager
1 /talker2
2 /ns/talker
3 /ns2/talker3
将参数值传递给组件
ros2 component load
支持在构造节点时向节点传递任意参数。
ros2 component load /ComponentManager image_tools image_tools::Cam2Image -p burger_mode:=true
向组件传递附加参数
ros2 component load
支持将特定选项传递给组件管理器,以便在构造节点时使用。 到目前为止,支持的唯一命令行选项是使用进程内通信实例化节点。
ros2 component load /ComponentManager composition composition::Talker -e use_intra_process_comms:=true
可组合节点作为共享库
https://docs.ros.org/en/humble/Tutorials/Intermediate/Composition.html#composable-nodes-as-shared-libraries
编写非节点派生组件
https://docs.ros.org/en/humble/Tutorials/Intermediate/Composition.html#composing-non-node-derived-components
监控参数变化
crate pkg
cd ~/ros2_ws/src && ros2 pkg create --build-type ament_cmake --license Apache-2.0 cpp_parameter_event_handler --dependencies rclcpp
cpp
- ~/ros2_ws/src/cpp_parameter_event_handler/src/parameter_event_handler.cpp
#include <memory> // 使用std::make_shared模板
#include "rclcpp/rclcpp.hpp" // 需要使用 rclcpp::ParameterEventHandler
class SampleNodeWithParameters : public rclcpp::Node
{
public:
SampleNodeWithParameters()
: Node("node_with_parameters")
{
// 声明一个默认值为0的参数
this->declare_parameter("an_int_param", 0);
// 实例化一个ParameterEventHandler用于监控参数更改
param_subscriber_ = std::make_shared<rclcpp::ParameterEventHandler>(this);
// 一个内联函数,在参数更改时调用
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());
};
// 保存add_parameter_callback返回的句柄非常重要,否则回调将无法正常注册
cb_handle_ = param_subscriber_->add_parameter_callback("an_int_param", cb);
// 监控节点parameter_blackboard上的参数变化
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);
}
private:
std::shared_ptr<rclcpp::ParameterEventHandler> param_subscriber_;
std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle_;
std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle2_;
};
int main(int argc, char ** argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<SampleNodeWithParameters>());
rclcpp::shutdown();
return 0;
}
CMakeLists.txt
- ~/ros2_ws/src/cpp_parameter_event_handler/CMakeLists.txt
# add
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}
)
run
# 终端1
cd ~/ros2_ws
rosdep install -i --from-path src --rosdistro $ROS_DISTRO -y # 检查依赖项是否缺失
colcon build --packages-select cpp_parameter_event_handler
. install/setup.bash
ros2 run cpp_parameter_event_handler parameter_event_handler
# 终端2
ros2 run demo_nodes_cpp parameter_blackboard
# 终端3 设置参数
ros2 param set node_with_parameters an_int_param 43
ros2 param set parameter_blackboard a_double_param 3.45