From Bits to the Physical World

A Full-Stack Robotics Guide for AI and Software Developers

01The Big Picture

What Is a Robot, Really?The Full-Stack Map of RoboticsWho's Who in the Industry?

02Hardware

SensorsActuatorsCompute Platforms

03Operating System

ROS 2DDS Deep Dive

04Algorithms

SLAMNav2MoveIt 2PerceptionBehavior Trees

05Simulation & Training

Why Simulation?NVIDIA Isaac Sim

06AI Meets Robotics

Reinforcement LearningImitation LearningFoundation Models

07Toolchain

Visualization & DebuggingDev Environment & DevOps

08The Harsh Reality of Deployment

Real-Robot DeploymentReliability EngineeringFleet Management

09Industry Reality

Business ModelsChina vs. GlobalCareer Advice

Part 3: Operating System · The robot's nervous system

Chapter 8

DDS - 机器人内部的快递系统

上一章我们搞清楚了 ROS 2 里的角色 - Node 是员工,Topic 是 Slack 频道,Service 是工单系统。但有一件事没讲:这些消息在物理上到底是怎么从一个 Node 送到另一个 Node 的?

想象一家公司有几十号人,分布在不同楼层。他们需要一套内部快递系统:有人发一份文件,快递系统负责送到所有需要这份文件的人手上。这套快递系统还得够聪明 - 有些文件丢了无所谓(比如每小时更新的数据报表,反正一小时后又来一份新的),有些文件一份都不能丢(比如 CEO 签字的合同)。而且新员工入职的时候,快递系统应该自动知道”哦你订阅了这个频道,我把最新一期给你补上”。

DDS(Data Distribution Service) 就是 ROS 2 里的这套快递系统。

你写代码时感觉不到它 - 还是publisher.publish(msg) 和 create_subscription(...)。DDS 在底下默默干两件事:自动发现(新节点上线后自动跟相关节点建立连接,不需要中央注册中心,有点像 AirDrop)和 QoS 策略(针对每条通信线路单独控制”这条消息有多重要”)。

QoS 是你最需要理解的部分。


QoS - 不是所有快递都要签收

回到快递系统的类比。一家公司内部每天流转的文件性质天差地别:

LiDAR 每秒发来 10-20 帧扫描数据,就像行政部每小时群发的办公室温度报告 - 丢了一份?无所谓,下一份马上就来。你肯定不希望快递员因为”上一份报告没送到”就停下来重新跑一趟,那只会耽误后面所有的递送。

但控制指令不一样。”立刻停下来”这条命令就像 CEO 签字的紧急通知 - 丢了会出大事。这种文件必须确认送达,没送到就得重发。

QoS(Quality of Service) 就是你给每条通信线路贴的标签,告诉快递系统:”这类文件怎么处理。”

最关键的几个标签:

要不要保证送达? 传感器数据设成 Best Effort(尽力送,丢了算了),控制指令设成 Reliable(必须送到,丢了重发)。这是你最常打交道的一个。

新人入职能不能看历史? 地图数据设成 Transient Local - 你的定位节点比建图节点晚启动,它连上来时需要拿到已经建好的那张地图,而不是从零开始等。传感器数据设成 Volatile - 历史帧没有意义,只关心最新的。

缓存多少份? 传感器数据只留最新一份(Keep Last(1)),旧的直接扔掉。你不会想让快递室里堆满过期的温度报告。

断供了怎么办? 如果传感器超过 200ms 没有新数据,说明出了问题 - Deadline 让你设一个”最长等待时间”,超时了系统可以触发减速或急停。

这些标签的常见搭配:

数据类型要保证送达吗新人要看历史吗缓存几份典型 topic
传感器数据不用(Best Effort)不用(Volatile)1 份/scan, /image_raw, /imu
控制指令必须(Reliable)不用(Volatile)1 份/cmd_vel, /joint_commands
地图数据必须(Reliable)要(Transient Local)1 份/map, /costmap

最阴险的坑:标签不匹配。 如果发布者贴的是 Best Effort(”我只能尽力送”),订阅者贴的是 Reliable(”我要求必须送到”) - DDS 觉得谈不拢,直接不建立连接。最要命的是,它不报错。你的订阅者就是收不到消息,终端里干干净净。排查方法:ros2 topic info /your_topic --verbose,一眼看出两边的标签对不对得上。


CycloneDDS 和 FastDDS - 不用纠结

DDS 是标准,不是软件。ROS 2 有两个主流实现:CycloneDDS(Jazzy 起的默认选择,轻量、配置简单)和 FastDDS(Humble 及更早版本的默认,功能更多但也更复杂)。你用哪个版本的 ROS 2,就用它的默认实现,不用想太多。

唯一要记住的:同一个网络里所有节点必须用同一种 DDS 实现,否则互相看不见。如果你的机器人厂商的 SDK 指定了 FastDDS,而你的节点默认是 CycloneDDS,消息就通不了。切换只需要一个环境变量:

export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp   # 或 rmw_fastrtps_cpp

“topic 对了、QoS 对了、还是收不到” - 查这个变量。


你会在什么时候碰到 DDS 的问题

单机开发阶段,DDS 的默认配置基本够用。但随着你的系统变复杂,有几个时刻你会被迫跟 DDS 打交道:

数据量大了。 一个 3D LiDAR 每秒产生 100-200 MB 的点云数据,再加上深度相机和 RGB 相机,总带宽轻松突破千兆以太网的上限。这时候你要么降采样再发布、要么降低发布频率、要么配置 DDS 走共享内存(同一台机器上的节点之间绕过网络栈,直接在内存里交换数据)。

机器人多了。 DDS 的自动发现靠组播 - 每个节点定期广播”我在这里”。5 台机器人、每台 30 个节点,网络上就有 150 个节点同时在喊。ROS 2 用 ROS_DOMAIN_ID 来隔离:不同 domain 的节点互相看不见。每台机器人一个 ID,就不会互相干扰。

export ROS_DOMAIN_ID=1   # 机器人 1
export ROS_DOMAIN_ID=2   # 机器人 2

网段不同了。 机器人在仓库 WiFi 上,你的开发机在办公室有线网上 - 组播过不了路由器。这时候需要手动配置 DDS 的对端 IP,让它用单播发现节点。

这些都是你做到那一步时才需要处理的问题。现阶段,记住排查 DDS 的三板斧就够了:ros2 topic info --verbose(查 QoS 匹配)、检查 RMW_IMPLEMENTATION(查 DDS 实现一致性)、检查 ROS_DOMAIN_ID(查网络隔离)。

← Previous07. ROS 2Next→09. SLAM