第3章:ROS2基础:架构、节点与话题、编译系统、工作空间搭建
各位同学,欢迎来到ROS2的世界。
说实话,我第一次接触ROS2的时候,心里是有点抵触的。毕竟ROS1用了那么多年,顺手得很。但后来在智驾项目里,ROS1的实时性短板和单点故障问题,让我吃了不少苦头。嗯,从那以后,我就彻底转向ROS2了。
这一章,我们不讲虚的。直接上手,把ROS2的骨架搭起来。你想想看,中间件就像汽车的底盘,底盘不稳,上面装再好的算法也是白搭。
3.1 ROS2架构:从“主节点”到“去中心化”
ROS1有个致命问题——它依赖一个叫roscore的主节点。一旦roscore挂了,整个系统就瘫痪了。我在一个园区物流项目里就遇到过,车跑到一半,roscore进程莫名其妙崩了,车直接停在路中间……
ROS2把这个设计彻底推翻了。它基于DDS(数据分发服务)协议,每个节点都是对等的,没有中心节点。说白了,就是每个节点自己就能发现别人、跟别人通信。
核心架构分层:
- 应用层:你的算法节点、控制节点、感知节点
- 中间件层:ROS2客户端库(rclcpp、rclpy)
- DDS层:真正的通信骨干,负责发现、序列化、传输
- 传输层:UDP/TCP/共享内存,根据QoS策略选择
我个人的习惯是,把DDS想象成一个“智能的快递网络”。每个节点只管往网络里扔包裹(消息),网络会自动把包裹送到订阅了它的人手里。不需要快递总站(roscore)来调度。
避坑指南:我曾经在调试多机通信时,发现两个机器上的节点互相发现不了。折腾了半天,原来是DDS的发现协议被公司防火墙拦了。解决办法是设置DDS的发现端口,或者用共享内存模式。
下面这张图,是我自己画的ROS2架构简图,帮你理清关系:
3.2 节点与话题:ROS2的“细胞”和“血管”
节点(Node)是ROS2里最小的执行单元。每个节点只干一件事,比如摄像头节点只管采集图像,激光雷达节点只管发点云。我经常跟团队说:一个节点只做一件事,把它做好。
话题(Topic)是节点之间通信的“血管”。发布者往话题里发消息,订阅者从话题里收消息。这是一种异步的、一对多的通信方式。
节点与话题的关系:
- 发布者(Publisher): 只管发,不管谁在收
- 订阅者(Subscriber): 只管收,不管谁在发
- 话题名: 字符串,比如 /camera/image_raw
- 消息类型: 定义好的数据结构,比如 sensor_msgs/Image
举个例子,我在做自动泊车项目时,超声波节点发布 /ultrasonic/raw 话题,融合节点订阅它。如果以后想换更好的超声波雷达,只要保证话题名和消息类型不变,融合节点一行代码都不用改。这就是解耦的好处。
个人经验:话题命名要规范。我见过有人用 /a、/b 这种名字,三个月后自己都看不懂。建议用 功能域/模块/数据 的格式,比如 /perception/lidar/points。
3.3 编译系统:Colcon 的使用
ROS1用catkin,ROS2用colcon。说白了,colcon就是catkin的升级版,编译更快,依赖管理更智能。
我第一次用colcon时,最直观的感受是:它不会把编译产物和源码混在一起。所有编译出来的东西都放在 install 目录里,源码目录干干净净。这对版本管理来说太友好了。
常用的colcon命令,我列个表:
| 命令 | 作用 | 我常用的场景 |
|---|---|---|
colcon build |
编译所有包 | 第一次编译,或者改了很多代码 |
colcon build --packages-select 包名 |
只编译指定包 | 只改了一个包,不想等全部编译 |
colcon build --symlink-install |
使用符号链接安装 | 开发阶段,改Python代码不用重新编译 |
colcon test |
运行测试 | 提交代码前,跑一遍单元测试 |
注意:每次编译前,记得先 source 一下环境变量。我见过太多人编译完发现找不到包,就是因为忘了 source install/setup.bash。建议把这个命令写到 ~/.bashrc 里。
3.4 工作空间搭建:从零开始
搭建工作空间,说白了就是建几个文件夹。但顺序不能乱,否则后面会出各种奇怪的问题。
我一般按这个步骤来:
- 创建工作空间目录:
mkdir -p ~/ros2_ws/src - 进入src目录:
cd ~/ros2_ws/src - 创建功能包:
ros2 pkg create my_pkg --build-type ament_cmake --dependencies rclcpp std_msgs - 编译:
cd ~/ros2_ws && colcon build - 生效环境:
source install/setup.bash
这里有个细节:--build-type 参数决定了你的包是用CMake还是Python。C++项目用 ament_cmake,纯Python项目用 ament_python。我建议智驾项目里,性能关键模块用C++,工具脚本用Python。
一个完整的工作空间结构:
ros2_ws/
├── src/ # 源码目录
│ ├── pkg_a/ # 功能包A
│ ├── pkg_b/ # 功能包B
│ └── ...
├── build/ # 编译中间文件(不用管)
├── install/ # 编译产物(source这个目录)
└── log/ # 编译日志(出问题时看这里)
避坑指南:我曾经在同一个工作空间里混用了ROS1和ROS2的包,结果编译报了一堆莫名其妙的错。后来我养成了习惯:一个工作空间只放一个ROS版本的包。如果你需要同时开发ROS1和ROS2项目,用不同的工作空间,切换时source对应的setup.bash。
嗯,到这里,ROS2的基础骨架就搭好了。你有了架构认知,知道了节点和话题怎么用,学会了colcon编译,也亲手建了一个工作空间。这些是后面所有实战内容的地基。
记住一句话:中间件不生产数据,它只是数据的搬运工。但怎么搬得稳、搬得快、不出错,就是我们要学的本事。