ros2 从零开始17 编写可组合节点
ros2 从零开始17 编写可组合节点
前言
背景
之前我们提到,同一个进程有多个节点,这些节点之间的通信是线程同步通信,基于此通信效率很高效。本节我们讨论一下可组合节点。
本节也会对比之前的普通节点和组合节点的区别。
起点
假如我们有一个普通的节点,包含main函数的。如下:
namespace palomino
{
class VincentDriver : public rclcpp::Node
{
// ...
};
}
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<palomino::VincentDriver>());
rclcpp::shutdown();
return 0;
}
其CMakeList文件也通常如下:
# ...
add_executable(vincent_driver src/vincent_driver.cpp)
# ...
install(TARGETS vincent_driver
DESTINATION lib/${PROJECT_NAME}
)
工程更新
假如要将它修改成组合节点,则需要有几项修改。
1. 添加包依赖
package.xml应该依赖于,比如rclcpp_components ,所以在package.xml里面添加如下:
<depend>rclcpp_components</depend>
你也可以手动添加如下依赖<build_depend>和<exec_depend>
2. 类定义变化
类定义唯一需要改变的是,需要一个带参数的构造函数,如下:
VincentDriver(const rclcpp::NodeOptions & options) : Node("vincent_driver", options)
{
// ...
}
3. 没有main函数。
去掉main函数,替换为下面的代码
#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(palomino::VincentDriver)
如果你的main函数使用了MultiThreadedExecutor,则确保你的运行容器同样也是多线程的(multithreaded)。后续章节会讨论。
4. CMakeList变动
4.1 第一步,需要添加依赖rclcpp_components,如下:
find_package(rclcpp_components REQUIRED)
4.2 第二步,编译目标变化。
编译目标从add_executable(编译进程)变成add_library(编译链接库), 如下,add_executable已被我注释掉:
#add_executable(vincent_driver src/vincent_driver.cpp)
add_library(vincent_driver_component SHARED src/vincent_driver.cpp)
4.3 第三步,替换旧目标的其他选项,应用到新目标上。
例如ament_target_dependencies(vincent_driver …)变成 ament_target_dependencies(vincent_driver_component rclcpp_components …), 同时别忘记了多出来的rclcpp_components。同样,下面注释掉的是之前配置项,未被注释的是当前使用的
#ament_target_dependencies(vincent_driver tutorial_interfaces)
ament_target_dependencies(vincent_driver_component tutorial_interfaces rclcpp_components)
4.4 第四步,添加一个声明,注册你的组合节点:
rclcpp_components_register_node(
vincent_driver_component
PLUGIN "palomino::VincentDriver"
EXECUTABLE vincent_driver
)
其中rclcpp_components_register_node有三个参数:
- 组合节点,这里是vincent_driver_component
- 组合节点的命名空间,这里是palomino::VincentDriver
- 组合节点名,这里是vincent_driver
4.5 第五步,也是最后一步,将CMake中运行在旧目标上的安装命令改为安装库版本。
旧的安装命令(注释掉的部分)是将vincent_driver安装到lib/${PROJECT_NAME}目录中, 而现在的安装命令是直接安装到lib目录中。
# install(TARGETS vincent_driver
# DESTINATION lib/${PROJECT_NAME}
# )
ament_export_targets(export_vincent_driver_component)
install(TARGETS vincent_driver_component
EXPORT export_vincent_driver_component
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
运行你的节点
经过上面修改后,用colcon进行编译及安装,这里不再赘述。
关于合成节点的深入介绍,请参见合成教程。按如下编写你的启动脚本。PS:根据官方教程做,到运行节点时翻车了,运行一直报错,以为是哪里写的有问题,而官方的python启动脚本又描述很少。后来看是python启动脚本的原因。这里附上的可运行的python脚本
#!/usr/bin/env python3
from launch import LaunchDescription
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode
from launch.actions import ExecuteProcess, TimerAction
from launch.substitutions import FindExecutable
def generate_launch_description():
# 创建组件节点容器
container = ComposableNodeContainer(
name='my_container',
namespace='',
package='rclcpp_components',
executable='component_container',
composable_node_descriptions=[
ComposableNode(
package='palomino',
plugin='palomino::VincentDriver',
name='VincentDriver',
extra_arguments=[{'use_intra_process_comms': True}]
),
],
output='screen',
)
return LaunchDescription([
container,
])
实际运行效果:
root@bc2bf85b2e4a:~/ros2_ws# ros2 launch src/palomino/launch/launch.py
[INFO] [launch]: All log files can be found below /root/.ros/log/2026-04-27-06-53-18-169175-bc2bf85b2e4a-19235
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [component_container-1]: process started with pid [19247]
[component_container-1] [INFO] [1777272798.537723957] [my_container]: Load Library: /root/ros2_ws/install/palomino/lib/libvincent_driver_component.so
[component_container-1] [INFO] [1777272798.547384246] [my_container]: Found class: rclcpp_components::NodeFactoryTemplate<palomino::VincentDriver>
[component_container-1] [INFO] [1777272798.547458915] [my_container]: Instantiate class: rclcpp_components::NodeFactoryTemplate<palomino::VincentDriver>
[INFO] [launch_ros.actions.load_composable_nodes]: Loaded node '/VincentDriver' in container '/my_container'
[component_container-1] [INFO] [1777272799.063800446] [VincentDriver]: Publishing: '0'
[component_container-1] [INFO] [1777272799.563895176] [VincentDriver]: Publishing: '1'
[component_container-1] [INFO] [1777272800.063988902] [VincentDriver]: Publishing: '2'
[component_container-1] [INFO] [1777272800.564248809] [VincentDriver]: Publishing: '3'
总结
可组合节点没有main函数,需要通过容器或者其他的方式才能加载和运行,下一章节将继续讨论其运行方式。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)