你可能会看到机器人执行一些任务,比如抓取和放置物体,或者将物体从一个点移动到另一个点。这些任务对我们来说看似简单,但对于机器人来说却很难实现。我们人类拥有非常灵活的身体和智能的大脑,而机器人仍然受限于有限的硬件能力和智能,这些智能仅仅依赖于我们通过软件提供的指令。要让机器人达到类似人类的智能和能力,可能还需要数年的时间。如你所知,机器人主要由三个部分组成:传感器、执行器和计算机。计算机相当于机器人的"大脑",我们在这里加载各种软件应用程序来执行不同的任务。机器人软件的开发在使机器人具备智能和适应不同使用场景方面起着重要作用。
本章我们将重点介绍机器人操作系统(Robot Operating System,简称ROS),它是一种用于高效编程机器人的流行软件框架。ROS框架在学术界和工业界被广泛应用于机器人建模、仿真和开发各种机器人应用。本章为入门章节,旨在为你提供该框架的总体概览。无论你是已经了解ROS的读者,还是刚刚开始接触ROS的人,本章内容都会对你有所帮助。
本章主要涵盖以下几个主题:
- 作为机器人框架的ROS
- ROS的重要特性
- ROS 1与ROS 2的对比
- ROS 2中的通信栈
- ROS 2中的DDS厂商介绍
理解ROS作为机器人框架
从零开始开发复杂的机器人应用是一项繁琐的任务。即使我们开发出了软件,如果它不具备模块化且无法被他人复用,那么其他人就必须重复同样的过程,这无异于"重新发明轮子"。这种情况不仅存在于机器人领域,也普遍存在于其他技术领域。因此,我们会遇到许多软件框架和库。这些框架提供了现成的功能或常用算法的应用程序接口(API),可以集成到我们的程序中,帮助我们快速开发应用。
在机器人软件开发中,有多种软件框架可用于快速创建机器人应用。其中一个流行的框架就是ROS。利用ROS,我们可以通过复用其他开发者已开发的代码,快速开发机器人应用。在深入细节之前,我们先来回答一个问题:什么是ROS?
什么是ROS?
与其名称所暗示的不同,ROS并不是真正的操作系统(Operating System,简称OS),不像Windows、Linux或macOS那样。它具有某些类似操作系统的功能,但并不是真正的操作系统。ROS是一个开源框架,专门用于开发机器人软件应用。它提供了一套机器人专用的库、软件工具,以及机器人的高级能力实现。
ROS以包(package)的形式提供机器人软件,开发者可以创建并复用现有的包。每个包可以包含不同算法的实现、数据集、机器人配置文件、机器人模型等内容。
ROS主要有两个版本:ROS 1和ROS 2。ROS 1是早期版本,ROS 2是最新版本。ROS 1完全支持基于Linux的操作系统,而ROS 2兼容Windows、Linux和macOS。本书完全聚焦于ROS 2。图1.1展示了ROS框架的标志。

官方的ROS网站地址见[1]。Open Robotics[2]负责ROS项目的开发和维护,他们与全球ROS开发者社区、学术研究人员以及行业专家合作,加速ROS包的开发。借助ROS,我们几乎可以开发机器人的所有软件组件。
ROS的重要特性
以下是ROS的一些重要特性:
进程间通信(IPC)基础设施:编程机器人实际上是在机器人计算机上创建不同的应用程序来完成不同任务。该计算机可能安装了类似Ubuntu/Linux的操作系统。机器人的传感器和执行器通过USB或其他接口连接到计算机上。我们可能需要编写多个ROS程序(称为ROS节点)来采集和处理传感器数据,并向执行器发送控制指令。将所有任务都写在一个程序中并不是理想的做法,因为这会增加程序复杂性且调试困难。这时ROS就派上用场了。ROS库提供了多种API,用于这些运行在操作系统上的程序之间通信。这样,我们可以在操作系统中运行多个ROS节点,这些节点相互通信,共同完成机器人的全部操作。这个进程间通信基础设施是ROS 1和ROS 2最重要的特性。ROS 2的IPC基础设施与ROS 1有所不同,ROS 2采用了最新且更可靠的软件组件进行通信,提升机器人的整体性能。
复用性和模块化 :他人开发的软件可以方便地复用到我们的应用中,这是ROS最实用的特性之一,避免了"重新发明轮子",节省了开发时间。ROS的包设计为模块化,Open Robotics和ROS社区贡献了超过1万个包。每个包可以服务于一个或多个功能,我们可以将这些包复用到机器人软件栈中,大幅缩短开发周期。例如,如果需要合并机器人激光扫描数据列表,可以直接使用laser_scan_merger
[3]包并集成到机器人应用中。
开源许可:ROS 1和ROS 2软件主要采用BSD 3-Clause(伯克利软件分发)许可证,允许我们修改并以商业目的重新分发机器人应用。BSD许可证提供高度灵活性。但并非所有包都采用BSD许可证,一些包使用Apache 2.0许可证、MIT许可证或较宽松的LGPL许可证,具体取决于不同开发者的贡献和软件组件需求。建议查看具体包的许可证细节。
工具和库 :ROS配备了一套软件工具。ROS工具帮助开发者可视化ROS节点发送和接收的各种传感器数据。另一个重要用途是调试,由于多个ROS程序/节点间相互通信,通信中可能出现问题,这些问题可以借助ROS工具进行排查。ROS库针对特定功能设计,客户端库帮助ROS节点间通信。我们可以使用rclcpp
库编写ROS 2的C++节点,使用rclpy
编写Python节点。像TF(变换)库帮助开发者维护机器人各连接件和关节的坐标变换。ROS包含多个库,能加快机器人软件开发速度。下一节将展示一些ROS工具示例。
硬件抽象:机器人驱动程序是由一组节点组成,帮助开发者与执行器、传感器或嵌入式平台等不同硬件组件交互。ROS提供硬件抽象层,这意味着当硬件组件变化时,开发者可以轻松将其集成到机器人系统中。ROS提供了硬件驱动开发的标准接口,使机器人组件更换更加便捷。
现成的机器人能力:这是ROS流行的主要原因。ROS提供现成的高层任务实现模板,如自主导航、机械臂操作和感知。开发者可以使用这些模板,并根据具体应用进行定制。
跨平台支持:机器人中操作系统多数基于Linux发行版,如Ubuntu,但也可以使用Windows、macOS、Android等系统。ROS支持跨平台开发,开发者可以创建ROS包并部署到多个操作系统平台。ROS 1主要支持Linux发行版,ROS 2则支持Ubuntu Linux、Windows 10和macOS。
中间件独立性:ROS的核心组件之一是通信中间件。通信中间件的作用是支持不同节点间的通信。在ROS 1中,通信中间件是固定的;而在ROS 2中,通信中间件采用了可插拔架构,如数据分发服务(DDS)或零开销网络协议(Zenoh)。我们可以根据具体应用选择不同中间件。接下来的章节会详细介绍DDS,DDS的示例包括Fast DDS、Cyclone DDS和RTI Connext。
社区和生态系统:与其他机器人软件框架相比,ROS社区规模庞大。大多数ROS包由全球开发者贡献并维护,这些包可以复用,减少整体开发时间。除了包外,社区还提供论坛和博客支持新手开发者。ROSCon[4]是年度大会,社区成员汇聚一堂,共享ROS框架的创新成果。
测试与仿真:ROS配备测试框架和仿真工具,用于在部署前验证机器人应用。支持ROS 1和ROS 2的机器人仿真器包括Gazebo、Webots和Isaac Sim。
面向生产的框架:很多人在使用ROS开发机器人应用时都会问,ROS是否适合生产环境。ROS 1设计初衷是用于机器人科研应用,而ROS 2则不同。ROS 2采用更完善的架构,适合生产环境,可应用于自动化工业、医疗健康、自动驾驶等多个场景。
以上是ROS的一些重要特性。接下来,让我们看看ROS的核心架构。
ROS方程式
ROS方程式展示了ROS框架中的重要组成部分。ROS的关键元素如图1.2所示。

ROS 1 和 ROS 2 的重要组成部分如下:
管道(Plumbing) :管道指的是进程间通信(IPC),这由ROS通信中间件支持。在ROS 1中,节点间通信使用TCPROS(一种基于TCP的协议);而在ROS 2中,则使用DDS。
工具(Tools) :ROS中包含图形界面工具和命令行工具。主要的GUI工具有ROS可视化器(RViz)[6]和rqt[7],它们用于可视化ROS节点间的数据交换以及调试节点通信。命令行工具可以在Linux终端中调用。
能力(Capabilities) :ROS的重要能力包括导航、操作和感知。在ROS 2中,机器人导航作为一个开源项目Nav2[8]实现,机器人操作作为开源项目MoveIt[9]实现。ROS的感知栈与流行的感知库如OpenCV[10]、点云库(PCL)[11]、BT.CPP[4]以及Open3D[12]紧密集成。
社区(Community) :ROS拥有庞大活跃的开源社区。ROS中有一份社区贡献的包和库列表[13],包括Nav2和MoveIt 2。ROS社区的交流平台托管在Discourse[14],我们可以在这里获得最新动态。此外,Robotics Stack Exchange[15]用于解决ROS相关问题,还有ROS Discord[16]支持实时沟通。这个强大的社区是ROS框架的基石。
下面一节将详细介绍ROS项目的发展时间线,帮助理解其演进历程。
ROS发展时间线
到目前为止,我们已经回顾了ROS的主要特性和ROS方程式。现在,让我们快速了解ROS的发展历程:这个项目何时开始,最新版本是什么?
- 2007年:ROS开发始于斯坦福人工智能实验室,随后由Willow Garage继续并大幅扩展[17]。
- 2008年:Willow Garage发布ROS早期版本0.4(Mango Tango)。
- 2010年:发布第一个官方ROS 1.0版本Box Turtle,同年发布ROS C Turtle。
- 2011年:发布ROS Diamondback和Electric Emys。
- 2012年:发布ROS Fuerte和Groovy。
- 2013年:发布ROS Hydro Medusa,包含重要的包和文档更新。
- 2014年:发布ROS Indigo。Hydro之后,ROS开始由开源机器人基金会(OSRF)开发和维护,其首个发行版即为Indigo。
- 2015年:发布ROS Jade Turtle。
- 2016年:发布ROS Kinetic Kame。
- 2017年:发布ROS Lunar Loggerhead;同年,首个ROS 2发行版ROS Ardent Apalone发布。ROS 2是与ROS 1独立的项目,许多组件重新设计和实现,以解决ROS 1的限制。
- 2018年:发布ROS 1.0 Melodic Morenia和ROS 2 Bouncy Bolson。
- 2019年:发布ROS 2 Dashing和Eloquent。
- 2020年:发布ROS 1.0 Noetic Ninjemys和ROS 2 Foxy Fitzroy。Noetic Ninjemys是ROS 1.0的最终发行版,支持到2025年。
- 2021年:发布ROS 2.0 Galactic。
- 2022年:发布ROS 2.0 Humble Hawksbill。
- 2023年:发布ROS 2.0 Iron Irwini。
- 2024年:发布ROS 2.0 Jazzy Jalisco,该版本的生命周期截止于2029年。本书使用的即是该版本。
- 2025年:发布ROS 2.0 Kilted Kaiju。
以下是ROS 1发行版[18]和ROS 2发行版[19]的链接。
现在你已经对ROS框架有了总体了解,接下来让我们比较其两个版本。
ROS 1 与 ROS 2 架构对比
本节将探讨ROS 1与ROS 2的基本架构变化,以及ROS 2项目启动的重要原因。图1.3展示了ROS 1和ROS 2的架构。

如图1.3所示,ROS 1和ROS 2架构中都有三个主要层次,它们分别是:
- 操作系统层(OS Layer)
- 中间件层(Middleware Layer)
- 应用层(Application Layer)
下面让我们详细了解每一层。
操作系统层
左侧是ROS 1的架构,右侧是ROS 2。底层是操作系统层。正如你所知道的,ROS是一个可以安装在操作系统上的软件框架。ROS 1主要兼容Ubuntu/Linux,而ROS 2则兼容Linux、Windows、macOS、实时操作系统(RTOS)等。
中间件层
下一层是中间件层,它包含了ROS的主要组件。观察ROS 1架构,可以看到其核心中间件组件如TCPROS/UDPROS以及Nodelet API。ROS 1的中间件层是自定义构建的,并随ROS一起发布。而ROS 2的通信中间件是DDS。DDS是由不同厂商通过不同库实现的协议,ROS 2开发者采用这些实现。DDS已被用于开发面向生产的基于进程间通信的自动机器人、航天及国防软件。ROS 2基于DDS实现构建。常见的DDS实现包括Fast DDS、Cyclone DDS和RTI Connext[20]。
在ROS 1的中间件层中,我们可以看到Nodelet API部分,它用于在ROS节点内实现进程内通信(intra-process communication)。进程内通信不同于进程间通信(IPC),前者是单个进程内不同部分(如线程、模块)通过共享内存交换数据,实现快速高效的数据传输;而后者是不同进程之间的数据交换。ROS 1中的Nodelet带来了显著的性能优势,例如零拷贝数据传输、避免序列化减轻CPU负载、避免数据复制降低内存使用,以及加速低延迟通信,提升高频数据(如图像或点云)的吞吐率。
ROS 1和ROS 2的客户端库提供了ROS节点间通信的API。节点可用不同编程语言实现,如C++、Python、Java等。每种语言有独立的客户端库,例如:
- ROS 1中,
roscpp
是C++客户端库,rospy
是Python客户端库。 - ROS 2中,
rclcpp
和rclpy
分别是C++和Python客户端库。
ROS 2中的所有客户端库都基于ROS客户端库(ROS Client Library,RCL)构建。RCL实现了ROS 2的核心概念,其他编程语言可调用此API进行封装使用。这样避免了从零构建客户端库,提高了开发效率和便利性。
类似于ROS 1中的Nodelet API,ROS 2也有对应的进程内通信API,功能相同。ROS 2新增了一个连接DDS与客户端库的中间层,称为抽象DDS层(abstract DDS layer)或ROS中间件层(ROS Middleware,RMW)。这一层不仅支持DDS,也适用于其他通信协议,如Eclipse Zenoh。它将ROS 2核心库与DDS及其它协议解耦,允许开发者随时更换DDS实现。
简而言之,抽象DDS层作为ROS 2 API与多种DDS或其他中间件实现之间的接口。此设计赋予ROS 2开发者更多灵活性和模块化能力。
应用层
应用层是开发者使用客户端库中的ROS API创建各种机器人应用的地方。我们可以编写不同的ROS节点,节点之间可以相互通信。
在ROS 1架构中,应用层包含一个称为master节点的节点。master节点随ROS 1安装而来,本质上是一个中介程序。借助这个中介程序,ROS 1节点可以发现其他节点并相互通信。因此,在启动任何ROS 1节点之前,必须先在操作系统中运行master节点。如果master节点无法运行,将影响整个ROS 1机器人应用的正常运行,这是一个重大问题,而ROS 2对此进行了修正。
在ROS 2中,没有master节点,但节点依然可以相互通信。这是ROS 2的一大变革,因为ROS 2采用了DDS作为中间件。在ROS 2中,开发者可以编写节点,节点通过DDS进行发现并开始通信。
ROS 1与ROS 2功能对比
特性 | ROS 1 | ROS 2 |
---|---|---|
通信中间件 | 自定义基于TCP的通信中间件。master节点负责节点注册和查找,可能成为单点故障。 | 使用DDS及类似Zenoh的通信协议。 |
实时性能 | 设计时不支持实时处理,需要大量调整才能实现。 | 通过一定调整和努力,可实现实时应用。 |
安全性 | 缺乏内置安全功能,不适合敏感或关键应用。 | 通过DDS安全功能实现内置的身份认证、加密和访问控制,适用于工业和商业应用。 |
模块化与可扩展性 | 高度模块化,兼容多种编程语言。 | 模块化增强,兼容多种编程语言,提供更灵活的开发支持。 |
平台支持 | 主要支持基于Linux的操作系统。 | 支持多种操作系统,如Windows、Linux和macOS。 |
社区与生态系统 | 社区庞大且成熟,拥有丰富的库和工具,广泛应用于学术研究。 | 社区快速增长,因ROS 1架构缺陷,社区逐步转向ROS 2。 |
表1.1:ROS 1与ROS 2功能对比
接下来,让我们了解为什么需要从ROS 1迁移到ROS 2。
为什么要从ROS 1迁移到ROS 2?
本节将讨论从ROS 1迁移到ROS 2的重要原因。这里不涉及技术细节,而是更广泛地说明为什么迁移到ROS 2更为有利。
以下是需要注意的关键点:
- ROS 1 Noetic Ninjemys将在2025年达到生命周期终止(EOL) 。EOL之后,ROS 1包将不再获得新功能、漏洞修复或安全更新。ROS 1也不会有新的版本发布,Noetic是ROS 1的最后一个官方发行版。ROS 1 Noetic主要支持的操作系统是Ubuntu 20.04,该系统也将在2025年达到EOL,届时不会有操作系统更新。2025年以后,只会有ROS 2的发行版存在。
- ROS 2可用于任何机器人应用,包括科研和商业应用。而ROS 1主要针对学术和研究用途设计。如果你计划原型开发并商业化机器人,ROS 2是更好的选择,因为它具备增强的安全性、鲁棒性以及协调复杂机器人任务的能力。
- 功能比较中,ROS 2全面领先。从安全性、实时性、服务质量(QoS)和可扩展性来看,ROS 2远胜于ROS 1。
- ROS 1平台特定,主要兼容Linux操作系统。虽然有移植到Windows和macOS的ROS 1版本,但不稳定且缺乏维护。而ROS 2是跨平台的,适合在Windows和macOS平台上进行机器人应用开发。
- 如果你已经是ROS 1开发者,迁移到ROS 2的学习曲线非常低。两者的通信概念相同,主要变化在API层面。只需将ROS 1节点替换为ROS 2 API即可。虽然这需要一定时间,但相较于ROS 2初学者,迁移过程较为容易,因为两者有共通的概念。ROS 2中也引入了一些较复杂的新概念,理解起来需要更多时间,但通常ROS 1的经验能帮助你快速上手ROS 2并开始开发。
我们已经讨论了为什么需要从ROS 1迁移到ROS 2。接下来,让我们探讨ROS 2的核心概念。
深入了解ROS 2中的DDS
本节将详细介绍ROS 2的核心模块------DDS,它作为ROS 2的通信中间件,如图1.3所示。
什么是DDS?
DDS(Data Distribution Service)【21】是由对象管理组织(OMG,Object Management Group)【22】于2004年制定的发布/订阅通信标准。它主要应用于诸如空中交通管理、金融交易和复杂遥测系统等关键任务领域。DDS支持发布者与订阅者之间可扩展、实时、可靠且高性能的数据交换。
OMG是一个全球性的、开放会员制的非盈利联盟,负责制定和维护众多技术与业务领域的标准。
发布/订阅通信涉及数据的发送与接收。发布者负责发送数据,订阅者负责监听和接收数据。
DDS标准的诞生,源于一批公司开发自己的中间件解决方案时,期望其应用程序能够互操作且兼容其他中间件。
DDS的主要应用场景包括:
- 航空航天与国防:用于指挥与控制系统,以及无人机(UAV)的实时通信。
- 医疗健康:应用于病人监护系统、健康信息系统等。
- 交通运输:自动驾驶车辆、铁路信号和控制系统。
- 金融领域:高频交易系统和市场数据分发。
- 机器人:自主机器人和工业机器人。
DDS在众多领域均有广泛应用。以下链接列出了采用DDS技术的组织和产品:www.dds-foundation.org/who-is-usin...
DDS标准组件
图1.4展示了DDS各个组件的框图。

我们可以看到三个主要层次:平台层、中间件层和应用层。以下是对每个层次的说明。
平台层
这是DDS标准图中的底层,包含操作系统、网络协议以及以太网等网络接口。我们必须在操作系统中安装DDS实现,并配置网络协议和接口使其正常运行。可以说,平台层是DDS工作的基础。平台层的其他组成部分简述如下:
- 互联网协议(IP) :网络层协议集合,用于路由数据到正确目的地【23】。
- 传输协议:位于IP层之上,帮助应用程序通信而无需直接操作IP层。DDS在不同场景使用不同传输协议。
- 传输控制协议(TCP) :在需要可靠通信和有序消息传递时使用。
- 用户数据报协议(UDP) :用于低延迟和实时系统,如机器人、航空航天和国防领域,优先保证消息及时送达而非完全可靠。
- 传输层安全(TLS) :用于安全的TCP通信。
- 时间敏感网络(TSN) :支持实时通信。
- 共享内存:用于同一台机器内的高速数据传输,适用于发布者和订阅者运行在同一机器的场景,可降低延迟,提高吞吐量。
中间件层
这一层包含DDS标准的实现。下面介绍中间件层的几个核心组成部分。
-
实时发布-订阅协议(RTPS) :DDS底层协议,利用标准协议保证不同DDS实现间的互操作性。RTPS主要为实时系统设计,适用于机器人、国防等关键应用。
-
DDS层:使用发布/订阅模式管理数据分发,确保发布者和订阅者解耦通信。DDS的关键特性包括:
- 以数据为中心的发布/订阅模型:实现发布者与订阅者解耦,支持灵活、可扩展的数据分发。
- 服务质量(QoS)策略:DDS提供多种易配置的QoS策略,控制通信的可靠性、持久性、延迟和资源使用。
- 互操作性:DDS设计为平台无关,支持不同操作系统和硬件平台。DDS实现提供标准化API,确保不同实现间互操作并便于集成现有系统。
- 实时通信:DDS优化低延迟、高吞吐量数据交换,提供确定性数据传输,适合时间敏感应用。
- 可扩展性:支持发布者和订阅者节点的动态发现,实现自动连接,无需配置,适用于大规模系统。
- 安全性:内置身份认证、加密和访问控制,保障通信安全。
- 语言特定实现:发布者和订阅者可使用多种编程语言实现,如C++、Java、Python等。DDS层为这些语言提供支持API,如图1.4所示,DDS-C++、DDS-JAVA等。还有DDS-IDL-C和DDS-IDL-C#,IDL(接口定义语言)用于定义通信参与者间的数据类型和接口。DDS-IDL-C通过IDL定义C语言API中的数据类型。
附加DDS规范,这些规范与DDS标准配合使用:
- DDS-WEB:将Web技术集成进DDS。
- DDS-OPC UA:支持与OPC统一架构(工业机器间通信协议)兼容。
- DDS-RPC:支持DDS中的远程过程调用。
- DDS-XTYPES:扩展复杂数据建模能力。
- IDL 4:本DDS架构中使用的IDL版本,定义数据类型。
- DDS-Security:确保数据交换和访问控制安全的一套规范。
下一节将介绍DDS中的应用层。
应用层
这里是用户应用程序所在的层次。我们可以使用DDS中针对不同编程语言提供的API,创建适用于各种应用场景的发布者和订阅者程序。
DDS是如何工作的?
本节将探讨DDS的工作原理以及用户应用程序之间如何通信。以下是我们在继续学习之前必须了解的一些关键概念。

图1.5展示了DDS架构中的各个概念。我们首先讨论的概念是全局数据空间(Global Data Space,GDS):
全局数据空间(GDS) :在DDS中,GDS指的是一个虚拟的共享内存或网络,所有参与者(节点)之间的数据交换都发生在这里。它就像一个共享的数据池,无论DDS参与者位于何处,都可以访问该数据池。GDS是以数据为中心的,意味着它优先关注数据本身,而非使用数据的应用程序。这也确保了数据的发布和订阅与应用逻辑相互解耦。

域(Domains) :在DDS中,域是全局数据空间(GDS)中的逻辑划分。它创建了数据交换发生的边界。一个GDS中可以存在多个域。域内的参与者可以相互发现并轻松通信,但与其他域隔离。根据应用需求,域有助于扩展、保障安全以及分离数据空间。图1.6展示了域的示意图,多个机器人在同一域内围绕不同主题进行通信。
主题(Topics) :如图1.5所示,每个域包含多个主题。主题是一个具名的数据总线或通道,作为发布者与订阅者之间的桥梁。每个主题有名称、数据类型和一组QoS策略。数据通过主题名称进行发布和订阅,且只能发布已定义的数据类型,其他数据类型不能通过同一主题名称发布。QoS策略确保数据在指定参数范围内可靠传输。主题的数据类型使用IDL格式定义,下一章将详细介绍IDL。发布者和订阅者需就该格式达成一致以交换数据。一个域内可包含多个主题,单个主题可有多个发布者和多个订阅者。
发布者和订阅者(Publishers and Subscribers) :使用DDS通信的应用通常称为域参与者。向主题发送数据的应用称为发布者,接收主题数据的应用称为订阅者。域参与者可以是发布者、订阅者,或同时兼具两者功能。发布者包含多个数据写入器,订阅者包含多个数据读取器。
数据写入器和数据读取器(Data Writers and Data Readers) :数据写入器是DDS中负责向特定主题写入数据的组件,是主题数据的来源;数据读取器负责从特定主题读取数据。数据写入器和读取器均可通过QoS策略配置,以指定数据发布和订阅的行为。
服务质量(QoS) :QoS策略定义数据交换的行为。我们可以为主题、发布者、订阅者、数据读取器或数据写入器设置QoS策略。这些策略帮助定义数据的传输方式。QoS策略可以单独分配给各组件,也可以成套分配,称为QoS配置文件。下一章的DDS特性列表中将详细讨论QoS。
我们已讨论DDS的工作原理并了解其重要组件。下一节将展示使用DDS的发布-订阅示例工作流。
探索使用DDS发送和接收数据的工作流
既然你已经理解了DDS的基本术语,我们开始探索一个使用DDS进行数据发送和接收的工作流。下面是一个利用DDS发布和订阅温度值的示例。

让我们深入了解这个工作流:
定义主题:第一步是为具体应用定义一个主题。例如,如果我们想发送机器人本体的温度,可以定义一个名为"Temperature"的主题,数据结构包含温度值、时间戳和传感器ID等字段。
创建发布者:接下来,我们创建发布者节点,该节点读取传感器数据并通过名为"Temperature"的主题发送数据。发布主题前,必须配置域ID(domain ID),发布者通过域ID识别其发布的域。这里我们将域ID设为0。设置域ID后,定义用于可靠传输的QoS策略,然后为"Temperature"主题设置数据写入器。完成后,持续发布温度数据。
创建订阅者:订阅者端需先设置域ID,然后配置QoS策略。完成后,为"Temperature"主题定义数据读取器,利用数据读取器接收温度数据并进行后续处理。
我们已通过DDS了解了一个发布-订阅工作流,接下来看看一些知名的DDS厂商及其特点。
DDS厂商列表
DDS有商业厂商和免费开源厂商。大多数商业DDS厂商提供更高性能、更好的控制、先进的安全性、支持和认证。开源DDS更多用于科研和教育,且因ROS 2集成被广泛应用于机器人领域。商业DDS主要应用于关键任务领域,如国防、航天和医疗,适合需要高稳定性、认证及长期支持的场景。
以下是不同组织对DDS标准的实现:
Real-Time Innovations (RTI) [25]
- DDS名称:Connext DDS [26]
- 描述:广泛使用的DDS实现,以高性能和可扩展性著称,支持从嵌入式设备到云端的广泛应用。
- 核心特性:提供丰富的设计、监控和分析工具,完善的文档和支持,以及与其他DDS实现的互操作性。
ADLINK Technology [27]
- DDS名称:Vortex OpenSplice [28]
- 描述:以高性能、可靠性和丰富功能(如QoS、实时数据传播及与其他DDS实现集成)闻名,广泛用于航天、国防和工业自动化等领域。
- 核心特性:高可用性和可靠性,支持多种编程语言和操作系统,丰富的QoS功能。
Eclipse Foundation [29]
- DDS名称:Eclipse Cyclone DDS [30]
- 描述:Eclipse基金会下的开源DDS实现,主要针对物联网和边缘计算应用设计。
- 核心特性:轻量高效,支持多操作系统平台,社区驱动开发。
Twin Oaks Computing [31]
- DDS名称:CoreDX DDS [32]
- 描述:适合小体积、高性能的DDS实现,适用于嵌入式和实时系统。
- 核心特性:内存占用小,吞吐量高,延迟低,支持安全关键和实时系统,与其他DDS实现兼容。提供轻量版本CoreDX DDS Lite。
eProsima [33]
- DDS名称:Fast DDS(前身Fast RTPS)[34]
- 描述:开源DDS实现,以效率和性能著称。
- 核心特性:高性能、低延迟,开源且社区支持,自定义QoS设置,通过集成服务支持与其他协议的集成。
Object Computing, Inc. (OCI) [35]
- DDS名称:Open DDS [36]
- 描述:高性能数据分发的开源DDS实现。
- 核心特性:开源社区驱动,可定制QoS,支持与其他DDS实现互操作,功能全面,文档和支持完善。
Zettascale [37]
- DDS名称:Cyclone DDS [38]
- 描述:开源DDS实现,针对实时分布式系统设计,注重可靠性和可扩展性。
- 核心特性:开源社区驱动,全面QoS配置,适合小体积高性能应用,高吞吐低延迟,与其他DDS实现兼容。
我们已经详细介绍了DDS及其厂商,接下来将探讨构建在DDS之上的不同层次。
解析一些重要的ROS 2层次
我们已经了解了DDS的基础知识并探讨了其各种特性。本节将深入探索构建在DDS之上的ROS 2各层。我们从RMW抽象层开始详细讨论,它是连接DDS与ROS 2框架的重要层次之一。
RMW层(ROS中间件抽象接口)
图1.8展示了ROS 2框架的详细架构及其各个层次。

我们之前在图1.2中讨论过DDS框架。我们了解到DDS拥有应用层或API,可以用来构建我们自己的应用程序,而这正是ROS相关的部分。ROS 2框架构建在DDS API层之上。如果你查看图1.8,会发现DDS框架层之上就是ROS 2框架。
DDS有不同的实现,比如Cyclone DDS、Fast DDS等。ROS 2支持不同DDS之间的互操作性,因此ROS 2节点应能兼容任何DDS。RMW层是ROS 2中的重要层次,它实现了不同ROS 2节点之间的通信,而这些节点独立于底层中间件(如DDS实现)。RMW层提供了灵活性和互操作性,屏蔽了DDS的通信细节。ROS 2中针对不同中间件有多种RMW实现。默认情况下我们使用DDS,但未来可能会有针对非DDS中间件的不同RMW实现。
以下是支持不同DDS厂商的一些流行RMW实现:
- rmw_fastrtps_cpp:基于eProsima Fast DDS(前称Fast RTPS)的实现,设计目标是高性能和易用性,适用于低延迟和高吞吐量应用。
- rmw_cyclonedds_cpp:基于Eclipse Cyclone DDS,主要用于资源受限环境,如嵌入式系统和物联网设备。
- rmw_connextdds_cpp:基于RTI Connext,这是一个以鲁棒性和丰富功能著称的商业DDS方案,用于关键任务应用。
- rmw_opensplice_cpp:基于ADLINK的OpenSplice DDS,具备高可扩展性和实时能力。
- rmw_zenoh:ROS 2中使用Zenoh作为中间件的RMW。Zenoh[39]是一种轻量级的发布/订阅协议,帮助不同设备和系统高效通信、共享数据和计算。Zenoh不是DDS,而是另一种可作为ROS 2中间件的协议。在某些场景,尤其是带宽受限环境中,Zenoh表现出与DDS相当的性能。选择Zenoh还是DDS取决于具体需求,如网络状况、数据重要性和系统可扩展性。此页面提供了多种发布/订阅框架的性能对比[40]。基准测试结果显示,Zenoh是工业、物联网、机器人和汽车应用的最佳选择。Open Robotics已选择Zenoh作为ROS 2 DDS的替代中间件,未来可能成为开发者的热门选择。
- rmw_email:甚至还有一个名为rmw_email的RMW,实现了通过电子邮件发送和接收字符串的中间件,允许ROS 2使用该中间件交换消息[44]。
我们已经看到连接DDS与ROS 2框架的不同RMW实现,但在RMW实现之上,还有一个RCL层,该层提供ROS核心API用于编写ROS 2应用程序。
注意
我们将在第3章中看到Zenoh作为RMW的实际实现。
RCL层与客户端库
RCL【41】是连接ROS客户端库(如C++的rclcpp、Python的rclpy以及C语言的rclc)与底层RMW层的重要层次。客户端库用于用特定编程语言编写ROS节点。ROS 2中的主要客户端库包括rclcpp
、rclpy
和rclc
。此外,还有由社区维护的客户端库,如Node.js、Rust、Dart和C#【42】。
RCL采用纯C语言编写,为客户端库提供稳定的API,开发者无需直接操作底层的DDS API。基于C的API可以被不同编程语言封装,进而扩展ROS 2对更多语言的支持。
ROS 2应用层
这是所有ROS 2节点和包所在的层次。ROS 2包是包含ROS 2节点、配置文件、数据等的软件模块。在应用层,我们可以看到已有许多实现的包、工具和机器人能力模块,如导航、操作和感知栈。

图1.9展示了DDS如何连接ROS 2中的不同模块,如工具、仿真器和能力模块。
理论上,ROS 2开发者可以完全专注于应用层,而无需过多关注底层DDS实现。然而,实际在大规模网络中部署ROS 2时,通常需要大量调试,这与ROS 1不同。这也促使了对诸如Zenoh这类替代方案的关注,Zenoh于去年被选为ROS 2的替代中间件【43】。
到此为止,我们已经了解了ROS 2架构的绝大多数重要方面,并详细探讨了作为ROS 2核心的DDS。
总结
本章介绍了ROS 2,这是一款广受欢迎的机器人应用开发框架。章节概述了ROS在平台模块化和复用性方面的作用,使开发者能够通过复用已有代码快速创建和适配机器人应用。介绍了ROS的关键元素,包括进程间通信基础设施、硬件抽象、开源许可以及丰富的库和工具,用于可视化、调试和机器人各部分间通信。
本章还比较了ROS 1和ROS 2,指出ROS 2因DDS而更加稳健,具备增强的安全功能和跨平台兼容性。深入讲解了ROS 2架构改进,重点介绍DDS作为通信中间件,如何在实时应用中提供灵活性和高性能。章节回顾了ROS的发展历程,从斯坦福AI实验室的初始版本,到最新的ROS 2 Kilted Kaiju版本,并讨论了从ROS 1向ROS 2迁移的必要性。随后详细解析了DDS的组成及其与ROS 2的集成,实现机器人应用中可扩展且高效的通信。
本章为后续章节的学习奠定了基础。下一章我们将讨论ROS 2的安装及其详细概念。
参考文献
1\] [www.ros.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.ros.org%2F "https://www.ros.org/") \[2\] [www.openrobotics.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.openrobotics.org%2F "https://www.openrobotics.org/") \[3\] [www.openrobotics.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.openrobotics.org%2F "https://www.openrobotics.org/") \[4\] [roscon.ros.org/](https://link.juejin.cn?target=https%3A%2F%2Froscon.ros.org%2F "https://roscon.ros.org/") \[5\] [www.openrobotics.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.openrobotics.org%2F "https://www.openrobotics.org/") \[6\] [github.com/ros2/rviz](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fros2%2Frviz "https://github.com/ros2/rviz") \[7\] [github.com/ros-visuali...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fros-visualization%2Frqt "https://github.com/ros-visualization/rqt") \[8\] [nav2.org/](https://link.juejin.cn?target=https%3A%2F%2Fnav2.org%2F "https://nav2.org/") \[9\] [moveit.picknik.ai/](https://link.juejin.cn?target=https%3A%2F%2Fmoveit.picknik.ai%2F "https://moveit.picknik.ai/") \[10\] [opencv.org/](https://link.juejin.cn?target=https%3A%2F%2Fopencv.org%2F "https://opencv.org/") \[11\] [pointclouds.org/](https://link.juejin.cn?target=https%3A%2F%2Fpointclouds.org%2F "https://pointclouds.org/") \[12\] [www.open3d.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.open3d.org%2F "https://www.open3d.org/") \[13\] [www.ros.org/blog/commun...](https://link.juejin.cn?target=https%3A%2F%2Fwww.ros.org%2Fblog%2Fcommunity%2F "https://www.ros.org/blog/community/") \[14\] [discourse.ros.org/](https://link.juejin.cn?target=https%3A%2F%2Fdiscourse.ros.org%2F "https://discourse.ros.org/") \[15\] [robotics.stackexchange.com/](https://link.juejin.cn?target=https%3A%2F%2Frobotics.stackexchange.com%2F "https://robotics.stackexchange.com/") \[16\] [www.ros.org/blog/discor...](https://link.juejin.cn?target=https%3A%2F%2Fwww.ros.org%2Fblog%2Fdiscord%2F "https://www.ros.org/blog/discord/") \[17\] [www.linkedin.com/company/wil...](https://link.juejin.cn?target=https%3A%2F%2Fwww.linkedin.com%2Fcompany%2Fwillow-garage%2F "https://www.linkedin.com/company/willow-garage/") \[18\] [wiki.ros.org/Distributio...](https://link.juejin.cn?target=https%3A%2F%2Fwiki.ros.org%2FDistributions "https://wiki.ros.org/Distributions") \[19\] [docs.ros.org/en/jazzy/Re...](https://link.juejin.cn?target=https%3A%2F%2Fdocs.ros.org%2Fen%2Fjazzy%2FReleases.html "https://docs.ros.org/en/jazzy/Releases.html") \[20\] [docs.ros.org/en/jazzy/In...](https://link.juejin.cn?target=https%3A%2F%2Fdocs.ros.org%2Fen%2Fjazzy%2FInstallation%2FDDS-Implementations.html "https://docs.ros.org/en/jazzy/Installation/DDS-Implementations.html") \[21\] [www.dds-foundation.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.dds-foundation.org%2F "https://www.dds-foundation.org/") \[22\] [www.omg.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.omg.org%2F "https://www.omg.org/") \[23\] [www.cloudflare.com/en-gb/learn...](https://link.juejin.cn?target=https%3A%2F%2Fwww.cloudflare.com%2Fen-gb%2Flearning%2Fnetwork-layer%2Finternet-protocol%2F "https://www.cloudflare.com/en-gb/learning/network-layer/internet-protocol/") \[24\] [www.researchgate.net/](https://link.juejin.cn?target=https%3A%2F%2Fwww.researchgate.net%2F "https://www.researchgate.net/") \[25\] [www.rti.com/en/](https://link.juejin.cn?target=https%3A%2F%2Fwww.rti.com%2Fen%2F "https://www.rti.com/en/") \[26\] [www.rti.com/products](https://link.juejin.cn?target=https%3A%2F%2Fwww.rti.com%2Fproducts "https://www.rti.com/products") \[27\] [www.adlinktech.com/en/data-dis...](https://link.juejin.cn?target=https%3A%2F%2Fwww.adlinktech.com%2Fen%2Fdata-distribution-service "https://www.adlinktech.com/en/data-distribution-service") \[28\] [www.adlinktech.com/en/vortex-o...](https://link.juejin.cn?target=https%3A%2F%2Fwww.adlinktech.com%2Fen%2Fvortex-opensplice-data-distribution-service "https://www.adlinktech.com/en/vortex-opensplice-data-distribution-service") \[29\] [www.eclipse.org/](https://link.juejin.cn?target=https%3A%2F%2Fwww.eclipse.org%2F "https://www.eclipse.org/") \[30\] [projects.eclipse.org/projects/io...](https://link.juejin.cn?target=https%3A%2F%2Fprojects.eclipse.org%2Fprojects%2Fiot.cyclonedds "https://projects.eclipse.org/projects/iot.cyclonedds") \[31\] [www.twinoakscomputing.com/](https://link.juejin.cn?target=https%3A%2F%2Fwww.twinoakscomputing.com%2F "https://www.twinoakscomputing.com/") \[32\] [www.twinoakscomputing.com/coredx](https://link.juejin.cn?target=https%3A%2F%2Fwww.twinoakscomputing.com%2Fcoredx "https://www.twinoakscomputing.com/coredx") \[33\] [www.eprosima.com/](https://link.juejin.cn?target=https%3A%2F%2Fwww.eprosima.com%2F "https://www.eprosima.com/") \[34\] [fast-dds.docs.eprosima.com/en/stable/](https://link.juejin.cn?target=https%3A%2F%2Ffast-dds.docs.eprosima.com%2Fen%2Fstable%2F "https://fast-dds.docs.eprosima.com/en/stable/") \[35\] [objectcomputing.com/](https://link.juejin.cn?target=https%3A%2F%2Fobjectcomputing.com%2F "https://objectcomputing.com/") \[36\] [objectcomputing.com/platforms/o...](https://link.juejin.cn?target=https%3A%2F%2Fobjectcomputing.com%2Fplatforms%2Fopendds "https://objectcomputing.com/platforms/opendds") \[37\] [www.zettascale.tech/](https://link.juejin.cn?target=https%3A%2F%2Fwww.zettascale.tech%2F "https://www.zettascale.tech/") \[38\] [cyclonedds.io/](https://link.juejin.cn?target=https%3A%2F%2Fcyclonedds.io%2F "https://cyclonedds.io/") \[39\] [zenoh.io/](https://link.juejin.cn?target=https%3A%2F%2Fzenoh.io%2F "https://zenoh.io/") \[40\] [zenoh.io/blog/2023-0...](https://link.juejin.cn?target=https%3A%2F%2Fzenoh.io%2Fblog%2F2023-03-21-zenoh-vs-mqtt-kafka-dds%2F "https://zenoh.io/blog/2023-03-21-zenoh-vs-mqtt-kafka-dds/") \[41\] [github.com/ros2/rcl/](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fros2%2Frcl%2F "https://github.com/ros2/rcl/") \[42\] [docs.ros.org/en/jazzy/Co...](https://link.juejin.cn?target=https%3A%2F%2Fdocs.ros.org%2Fen%2Fjazzy%2FConcepts%2FBasic%2FAbout-Client-Libraries.html "https://docs.ros.org/en/jazzy/Concepts/Basic/About-Client-Libraries.html") \[43\] [newsroom.eclipse.org/eclipse-new...](https://link.juejin.cn?target=https%3A%2F%2Fnewsroom.eclipse.org%2Feclipse-newsletter%2F2023%2Foctober%2Feclipse-zenoh-selected-alternate-ros-2-middleware "https://newsroom.eclipse.org/eclipse-newsletter/2023/october/eclipse-zenoh-selected-alternate-ros-2-middleware") \[44\] [github.com/christopheb...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fchristophebedard%2Frmw_email "https://github.com/christophebedard/rmw_email") \[45\] [www.behaviortree.dev/](https://link.juejin.cn?target=https%3A%2F%2Fwww.behaviortree.dev%2F "https://www.behaviortree.dev/")