当前位置: 首页 > news >正文

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有三个参数:

  1. 组合节点,这里是vincent_driver_component
  2. 组合节点的命名空间,这里是palomino::VincentDriver
  3. 组合节点名,这里是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 python3fromlaunchimportLaunchDescriptionfromlaunch_ros.actionsimportComposableNodeContainerfromlaunch_ros.descriptionsimportComposableNodefromlaunch.actionsimportExecuteProcess,TimerActionfromlaunch.substitutionsimportFindExecutabledefgenerate_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',)returnLaunchDescription([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函数,需要通过容器或者其他的方式才能加载和运行,下一章节将继续讨论其运行方式。

http://www.cnnetsun.cn/news/2146814.html

相关文章:

  • YooAsset资源管理框架:解决Unity游戏开发中资源加载痛点的完整解决方案
  • 别再踩坑了!Vue项目里用vue-pdf-app预览PDF,这个CSS样式不设置它就不显示
  • PPTist在线演示文稿制作:零基础到专业级的免费幻灯片编辑器完全指南
  • 如何用Subtitle Edit免费开源工具快速制作专业字幕:完整指南
  • 基于深度学习的cnn口罩识别 改进的yolov5+口罩检测+gui界面+代码+数据集+权重+训练曲线指标
  • 手把手教你:基于EN IEC 62660-2:2019,如何规划电动车电池的可靠性测试方案?
  • 2026卷绕式扣式电池产业洞察:智能制造如何重塑微型储能格局?
  • 【最新教程】2026年OpenClaw/Hermes Agent腾讯云2分钟简易搭建教程
  • 思源宋体:零成本打造专业中文排版的完整指南
  • 计算机网络知识应用:诊断与优化StructBERT模型API的网络延迟
  • 从XYZ到ORCA inp:Multiwfn批量处理中的那些‘坑’与高效配置心得
  • WarcraftHelper:魔兽争霸III兼容性增强插件完全指南
  • 从直播基地到奶酪小镇 奇富科技乌兰察布乡村振兴再落子 十五五开局新作为 奇富科技赋能乌兰察布特色产业高质量发展
  • 零GC有限状态机(FSM)与 基于代码的轻量级行为树
  • Python 新手入门,第一个排序算法怎么写
  • 【无标题政企携手谋新篇:清溪镇委领导与光电通讯协会代表莅临金利威调研座谈】
  • 终极指南:5分钟快速掌握TensorFlow Lite Micro嵌入式AI部署
  • 别再买分立元件了!用Matlab脚本快速设计微带线等效电感电容(附ADS验证)
  • ProperTree:3步快速上手跨平台plist编辑神器
  • 【图像加密】基于一维增强Log-logistic混沌映射与改进型重力扩散的图像加密解密(含信息熵)附Matlab代码和参考文献
  • NetBeans 8.2 效率翻倍:除了Ctrl+/,这15个冷门但超实用的快捷键你用过几个?
  • 别再只盯着ChatGLM3-6B了!手把手教你用BGE大模型为你的AI应用注入‘记忆’
  • 银威云进销存ERP系统|PHP多仓管理+双端APP(PC/手机)|小微商家专用进销存软件
  • AM32电调盲启动与堵转保护:从代码看如何让你的穿越机电机稳定起转
  • 别再写一堆if-else了!Matlab的piecewise函数,5分钟搞定复杂分段函数
  • IntelliJ IDEA 2021.1安装后必做的10项高效设置(含Maven/Tomcat/数据库连接)
  • PDF提取效率提升:MinerU 2.5镜像实测,三步完成文档结构化
  • 2026年权威发布:杭州AI搜索优化解决方案如何选?深度测评AI搜索优化服务商避坑指南
  • 终极Obsidian标题自动编号指南:3分钟让笔记结构瞬间专业化 [特殊字符]
  • 如何用Layerdivider将单张图片一键转换为专业PSD分层文件