从ROS1老鸟到ROS2新手:我踩过的那些‘兼容性’坑和高效迁移指南

张开发
2026/4/19 16:03:58 15 分钟阅读

分享文章

从ROS1老鸟到ROS2新手:我踩过的那些‘兼容性’坑和高效迁移指南
从ROS1老鸟到ROS2新手我踩过的那些‘兼容性’坑和高效迁移指南第一次在ROS2中运行那个本该简单的发布订阅demo时终端里跳出的rclcpp未定义错误让我愣了三秒——这明明是在ROS1中跑过无数次的代码。作为有五年ROS1开发经验的老鸟我低估了这两个版本间的鸿沟。本文将分享我在将一个基础ROS1包迁移到ROS2 Humble过程中遇到的真实问题以及如何系统性地规避这些兼容性陷阱。1. 包结构从catkin到ament的思维转换ROS1的catkin构建系统在ROS2中被ament取代这种底层架构的变更直接影响着整个开发流程。迁移时第一个要重构的就是package.xml和CMakeLists.txt这两个核心文件。1.1 package.xml的隐藏陷阱ROS1中常见的run_depend标签在ROS2中已完全废弃取而代之的是更简洁的depend统一管理所有依赖。但更易被忽视的是export标签的变化!-- ROS1典型配置 -- export nodelet plugin${prefix}/nodelets.xml / /export !-- ROS2正确配置 -- export build_typeament_cmake/build_type /export特别注意ROS2强制要求声明构建工具类型否则会导致colcon build失败。我在首次迁移时花了半小时才定位到这个看似简单的配置项。1.2 CMakeLists.txt的重构要点ROS2的CMake配置更模块化最显著的变化是find_package的调用方式。下表对比关键差异功能ROS1写法ROS2写法基础依赖find_package(catkin REQUIRED)find_package(ament_cmake REQUIRED)添加消息add_message_files(...)rosidl_generate_interfaces(...)节点安装catkin_install_python(...)install(TARGETS ...)提示ROS2中所有可执行文件必须显式声明安装规则否则ros2 run会报找不到节点错误2. API调用roscpp到rclcpp的范式迁移通信API的变更可能是最具破坏性的修改点。以最常见的发布者创建为例// ROS1风格 (roscpp) ros::Publisher pub nh.advertisestd_msgs::String(chatter, 10); // ROS2风格 (rclcpp) auto pub node-create_publisherstd_msgs::msg::String(chatter, 10);关键差异解析命名空间ROS2的消息类型必须包含msg子命名空间QoS参数ROS2默认的队列深度策略更严格需要显式配置// 匹配ROS1行为的QoS配置 auto qos rclcpp::QoS(10).reliable(); auto pub node-create_publisherstd_msgs::msg::String(chatter, qos);2.1 定时器API的坑点ROS1的ros::Timer在ROS2中拆分为多种类型最常用的create_wall_timer与ROS1行为差异较大// ROS1: 使用模拟时间 ros::Timer timer nh.createTimer(ros::Duration(1.0), callback); // ROS2: 默认使用真实时间容易导致测试不一致 auto timer node-create_wall_timer(1s, callback); // ROS2正确做法显式指定时钟类型 auto timer node-create_timer( node-get_clock(), rclcpp::Duration(1, 0), callback );3. DDS中间件最隐蔽的兼容性杀手ROS2采用DDS作为通信中间件这带来了ROS1不存在的配置维度。我在测试时遇到的最棘手问题是不同DDS实现的默认行为差异。3.1 选择适合的DDS实现主流DDS实现对比实现优点缺点适用场景Fast DDS内存占用低实时性一般资源受限设备Cyclone DDS延迟稳定配置复杂实时控制系统RTI Connext功能完整商业许可企业级应用通过环境变量切换DDS实现export RMW_IMPLEMENTATIONrmw_fastrtps_cpp # 默认选项 # 或 export RMW_IMPLEMENTATIONrmw_cyclonedds_cpp3.2 QoS策略的实战配置ROS1中隐式的通信策略在ROS2中必须显式声明。以下是一个兼容ROS1行为的配置示例// 创建兼容ROS1的QoS配置 auto ros1_compatible_qos rclcpp::QoS( rclcpp::QoSInitialization( RMW_QOS_POLICY_HISTORY_KEEP_LAST, // 历史策略 10 // 队列深度 ) ); ros1_compatible_qos.reliable(); // 可靠传输 ros1_compatible_qos.durability_volatile(); // 非持久化 // 应用配置 auto pub node-create_publisherstd_msgs::msg::String( chatter, ros1_compatible_qos );4. 工具链迁移从roslaunch到ros2 launchROS2的启动系统完全重构.launch文件现在使用Python语法编写。一个常见的发布订阅demo启动文件对比!-- ROS1 launch示例 -- launch node pkgdemo_pkg typetalker nametalker/ node pkgdemo_pkg typelistener namelistener/ /launch# ROS2 launch示例 from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ Node( packagedemo_pkg, executabletalker, nametalker ), Node( packagedemo_pkg, executablelistener, namelistener ) ])经验之谈ROS2的启动文件支持更复杂的逻辑控制但需要适应Python语法。建议创建模板文件库加速开发。5. 调试技巧ROS2特有问题的排查方法迁移过程中这些工具能极大提升效率5.1 通信诊断工具# 查看话题列表比ROS1多了类型信息 ros2 topic list -t # 详细检查话题连接状态 ros2 topic info /chatter --verbose # 监控QoS配置 ros2 topic echo --qos-profile /chatter5.2 性能分析命令# 测量端到端延迟ROS2新增功能 ros2 run demo_nodes_cpp latency_test --size 1024 # 监控节点资源使用 ros2 run system_metrics_collector memory_monitor6. 渐进式迁移策略对于大型ROS1项目推荐采用混合运行方案逐步迁移桥接方案使用ros1_bridge包建立通信# 启动桥接服务 ros2 run ros1_bridge dynamic_bridge组件化拆分按功能模块逐个迁移优先迁移数据预处理等独立模块最后迁移核心控制逻辑CI/CD适配更新测试框架# GitHub Actions示例 - uses: ros-tooling/setup-rosv0.3 with: required-ros-distributions: humble迁移过程中最耗时的往往不是代码修改而是对ROS2新特性的理解消化。建议在开发环境搭建完成后先用小样例验证所有关键功能点。

更多文章