news 2025/12/25 0:58:43

ROS2概念之DDS

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ROS2概念之DDS

我们在《ROS2概述和基于RK3588的环境搭建》中对ROSROS2做了对比,其中最多的变化就是DDS。我们在前面文章中介绍的话题、服务、动作,他们底层通信的具体实现过程,都是靠DDS来完成的,它相当于是ROS机器人系统中的神经网络。

一、通信模型

DDS的核心是通信,能够实现通信的模型和软件框架非常多,这里我们列出常用的四种模型。

1.1 点对点模型

许多客户端连接到一个服务端,每次通信时,通信双方必须建立一条连接,当通信节点增多时,连接数也会增多。

而且每个客户端都需要知道服务器的具体地址和所提供的服务,一旦服务器地址发生变化,所有客户端都会受到影响。

1.2Broker模型

针对点对点模型进行了优化,由Broker集中处理所有人的请求,并进一步找到真正能响应该服务的角色,这样客户端就不用关心服务器的具体地址了。

不过问题也很明显,Broker作为核心,它的处理速度会影响所有节点的效率,当系统规模增长到一定程度,Broker就会成为整个系统的性能瓶颈。更麻烦是,如果Broker发生异常,可能导致整个系统都无法正常运转,之前的ROS1系统,使用的就是类似这样的架构。

1.3 广播模型

所有节点都可以在通道上广播消息,并且节点都可以收到消息。这个模型解决了服务器地址的问题,而且通信双方也不用单独建立连接,但是广播通道上的消息太多了,所有节点都必须关心每条消息,其实很多是和自己没有关系的。

1.4 以数据为中心的DDS模型

这种模型与广播模型有些类似,所有节点都可以在DataBus上发布和订阅消息。但它的先进之处在于,通信中包含了很多并行的通路,每个节点可以只关心自己感兴趣的消息,忽略不感兴趣的消息,有点像是一个旋转火锅,各种好吃的都在这个DataBus传送,我们只需要拿自己想吃的就行,其他的和我们没有关系。

以数据为中心更本质的体现是数据域(Domain)概念。一个DDS Domain定义了一个独立的虚拟网络空间,只有拥有相同Domain ID的参与者(对应ROS2节点)才能相互发现和通信。这就像一栋办公楼,不同的Domain ID是不同的楼层,同楼层的公司(节点)可以自由交流,不同楼层则完全隔离,互不干扰。

二、DDS

DDS并不是一个新的通信方式,在ROS2之前,DDS已经广泛应用在很多领域,比如航空,国防,交通,医疗,能源等。

比如在自动驾驶领域,通常会存在感知,预测,决策和定位等模块,这些模块都需要非常高速和频繁地交换数据。借助DDS,可以很好地满足它们的通信需求。

2.1DDS定义

DDS的全称是Data Distribution Service,也就是数据分发服务,2004年由对象管理组织OMG发布和维护,是一套专门为实时系统设计的数据分发/订阅标准,最早应用于美国海军, 解决舰船复杂网络环境中大量软件升级的兼容性问题,现在已经成为强制标准。

DDS强调以数据为中心,可以提供丰富的服务质量策略,以保障数据进行实时、高效、灵活地分发,可满足各种分布式实时通信应用需求。

这里也提一下对象管理组织OMG,成立于1989年,它的使命是开发技术标准,为数以千计的垂直行业提供真实的价值,比如我们可能听说过的统一建模语言SYSMLUML,还有中间件标准CORBA等,当然还有DDS

2.2 在ROS2中的应用

DDSROS2系统中的位置至关重要,所有上层建设都建立在DDS之上。在这个ROS2的架构图中,蓝色和红色部分就是DDS

DDS其实是物联网中广泛应用的一种通信协议,类似于我们常听说的5G通信一样,DDS是一个国际标准,能够实现该标准的软件系统并不是唯一的,所以我们可以选择多个厂家提供的DDS系统,比如这里的OpenSpliceFastRTPS,还有更多厂家提供的,每一家的性能不同,适用的场景也不同。

不过这就带来一个问题,每个DDS厂家的软件接口肯定是不一样的,如果我们按照某一家的接口写完了程序,想要切换其他厂家的DDS,不是要重新写代码么?这当然不符合ROS提高软件复用率的目标。

为了解决这个问题,ROS2设计了一个ROS Middleware,简称RMW,也就是指定一个标准的接口,比如如何发数据,如何收数据,数据的各种属性如何配置,都定义好了,如果厂家想要接入ROS社区,就得按照这个标准写一个适配的接口,把自家的DDS给移植过来,这样就把问题交给了最熟悉自家DDS的厂商。对于我们这些用户来讲,某一个DDS用的不爽,只要安装另一个,然后做一个简单的配置,程序一行的都不用改,轻松更换底层的通信系统。

举一个例子,比如我们在产品开发时,可以先用开源版本的DDS满足基本需求,部署交付的产品时,再更换为商业版本更稳定的DDS,这样可以减少开发成本。

总之,DDS的加入,让ROS2系统更加稳定,也更加灵活,当然复杂度也会高一些。这样,我们不用再纠结ROS的通信系统是否稳定、该如何优化等问题,更多精力都可以放在其他三个部分,专注优化我们的机器人应用功能。

2.3 服务质量QoS

DDSROS的通信系统提供提供了哪些特性呢?我们通过这个通信模型图来看下;

DDS中的基本结构是DomainDomain将各个应用程序绑定在一起进行通信,回忆下之前我们配置NanoPC-T6开发板和ubuntu虚拟机通信的时候,配置的那个Domain ID,就是对全局数据空间的分组定义,只有处于同一个Domain小组中的节点才能互相通信,这样可以避免无用数据占用的资源。

DDS中另外一个重要特性就是质量服务策略QoSQoS是一种网络传输策略,应用程序指定所需要的网络传输质量行为,QoS服务实现这种行为要求,尽可能地满足客户对通信质量的需求,可以理解为数据提供者和接收者之间的合约。

具体会有哪些策略?比如:

  • DEADLINE:表示通信数据必须要在每次截止时间内完成一次通信;
  • HISTORY:表示针对历史数据的一个缓存大小;
  • RELIABILITY:表示数据通信的模式;
    • 配置成BEST_EFFORT,就是尽力传输模式,网络情况不好的时候,也要保证数据流畅,此时可能会导致数据丢失;
    • 配置成RELIABLE,就是可信赖模式,可以在通信中尽量保证图像的完整性,我们可以根据应用功能场景选择合适的通信模式;
  • DURABILITY:可以配置针对晚加入的节点,也保证有一定的历史数据发送过去,可以让新节点快速适应系统。
2.3.1 机器人案例

举一个机器人的例子便于大家理解;

2.3.1 无人机案例

比如我们遥控一个无人机航拍,如果网络情况不好的话,遥控器向无人机发送运动指令的过程,可以用reliable通信模式,保证每一个命令都可以顺利发送给无人机,但是可能会有一些延时,无人机传输图像的过程可以用best effort模式,保证视频的流畅性,但是可能会有掉帧。

如果此时出现一个黑客黑入我们的网络,也没有关系,我们可以给ROS2的通信数据进行加密,黑客也没有办法直接控制无人机。

DDS的加入,让ROS2的通信系统焕然一新,多众多样的通信配置,可以更好的满足不同场景下的机器人应用。

三、DDS案例

3.1 在命令行中配置DDS

我们先来试一试在命令行中配置DDS的参数。

3.1.1 发布者

启动第一个终端,我们使用best_effort创建一个发布者节点,循环发布任意数据;

pi@NanoPC-T6:~$ ros2 topic pub /chatter std_msgs/msg/Int32 "data: 42" --qos-reliability best_effort publisher: beginning loop publishing #1: std_msgs.msg.Int32(data=42) publishing #2: std_msgs.msg.Int32(data=42) publishing #3: std_msgs.msg.Int32(data=42) publishing #4: std_msgs.msg.Int32(data=42)
3.1.2 订阅者

在另外一个终端中,如果我们使用reliable模型订阅同一话题,则无法实现数据通信;

pi@NanoPC-T6:~$ ros2 topic echo /chatter --qos-reliability reliable [WARN] [1765976222.618569414] [_ros2cli_2137]: New publisher discovered on topic '/chatter', offering incompatible QoS. No messages will be received from it. Last incompatible policy: RELIABILITY

修改为同样的best_effort,才能实现数据传输;

Cpi@NanoPC-T6:~ros2 topic echo /chatter --qos-reliability best_effortrt data: 42 --- data: 42 --- data: 42 --- data: 42 --- data: 42 --- data: 42 --- data: 42 ---
3.1.3 查看QoS策略

如何去查看ROS2系统中每一个发布者或者订阅者的QoS策略呢,在topic命令后边跟一个--verbose参数就行了;

pi@NanoPC-T6:~$ ros2 topic info /chatter --verbose Type: std_msgs/msg/Int32 Publisher count: 1 Node name: _ros2cli_2064 Node namespace: / Topic type: std_msgs/msg/Int32 Endpoint type: PUBLISHER GID: 01.0f.50.2b.10.08.90.1b.00.00.00.00.00.00.05.03.00.00.00.00.00.00.00.00 QoS profile: Reliability: BEST_EFFORT History (Depth): UNKNOWN Durability: TRANSIENT_LOCAL Lifespan: Infinite Deadline: Infinite Liveliness: AUTOMATIC Liveliness lease duration: Infinite Subscription count: 1 Node name: _ros2cli_2200 Node namespace: / Topic type: std_msgs/msg/Int32 Endpoint type: SUBSCRIPTION GID: 01.0f.50.2b.98.08.ab.93.00.00.00.00.00.00.05.04.00.00.00.00.00.00.00.00 QoS profile: Reliability: BEST_EFFORT History (Depth): UNKNOWN Durability: VOLATILE Lifespan: Infinite Deadline: Infinite Liveliness: AUTOMATIC Liveliness lease duration: Infinite
3.2DDS编程示例

接下来,我们尝试在代码中配置DDS,以之前Hello World话题通信为例。

我们首先创建my_learning_qosPython版本的功能包;

pi@NanoPC-T6:~/dev_ws$ cd src pi@NanoPC-T6:~/dev_ws/src$ ros2 pkg create --build-type ament_python my_learning_qos
3.2.1 发布者

my_learning_qos文件夹下创建qos_helloworld_pub.py

""" ROS2 QoS示例-发布“Hello World”话题 @author: zy @since : 2025/12/17 """ import rclpy # ROS2 Python接口库 from rclpy.node import Node # ROS2 节点类 from std_msgs.msg import String # 字符串消息类型 from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy # ROS2 QoS类 """ 创建一个发布者节点 """ class PublisherNode(Node): def __init__(self, name): super().__init__(name) # ROS2节点父类初始化 qos_profile = QoSProfile( # 创建一个QoS原则 # reliability=QoSReliabilityPolicy.BEST_EFFORT, reliability=QoSReliabilityPolicy.RELIABLE, history=QoSHistoryPolicy.KEEP_LAST, depth=1 ) self.pub = self.create_publisher(String, "chatter", qos_profile) # 创建发布者对象(消息类型、话题名、QoS原则) self.timer = self.create_timer(0.5, self.timer_callback) # 创建一个定时器(单位为秒的周期,定时执行的回调函数) def timer_callback(self): # 创建定时器周期执行的回调函数 msg = String() # 创建一个String类型的消息对象 msg.data = 'Hello World' # 填充消息对象中的消息数据 self.pub.publish(msg) # 发布话题消息 self.get_logger().info('Publishing: "%s"' % msg.data)# 输出日志信息,提示已经完成话题发布 def main(args=None): # ROS2节点主入口main函数 rclpy.init(args=args) # ROS2 Python接口初始化 node = PublisherNode("qos_helloworld_pub") # 创建ROS2节点对象并进行初始化 rclpy.spin(node) # 循环等待ROS2退出 node.destroy_node() # 销毁节点对象 rclpy.shutdown() # 关闭ROS2 Python接口

完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:

entry_points={ 'console_scripts': [ 'qos_helloworld_pub = my_learning_qos.qos_helloworld_pub:main', ], },
3.2.2 订阅者

my_learning_qos文件夹下创建qos_helloworld_sub.py

""" ROS2 QoS示例-订阅“Hello World”话题消息 @author: zy @since : 2025/12/17 """ import rclpy # ROS2 Python接口库 from rclpy.node import Node # ROS2 节点类 from std_msgs.msg import String # ROS2标准定义的String消息 from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy # ROS2 QoS类 """ 创建一个订阅者节点 """ class SubscriberNode(Node): def __init__(self, name): super().__init__(name) # ROS2节点父类初始化 qos_profile = QoSProfile( # 创建一个QoS原则 # reliability=QoSReliabilityPolicy.BEST_EFFORT, reliability=QoSReliabilityPolicy.RELIABLE, history=QoSHistoryPolicy.KEEP_LAST, depth=1 ) self.sub = self.create_subscription( String, "chatter", self.listener_callback, qos_profile) # 创建订阅者对象(消息类型、话题名、订阅者回调函数、QoS原则) def listener_callback(self, msg): # 创建回调函数,执行收到话题消息后对数据的处理 self.get_logger().info('I heard: "%s"' % msg.data) # 输出日志信息,提示订阅收到的话题消息 def main(args=None): # ROS2节点主入口main函数 rclpy.init(args=args) # ROS2 Python接口初始化 node = SubscriberNode("qos_helloworld_sub") # 创建ROS2节点对象并进行初始化 rclpy.spin(node) # 循环等待ROS2退出 node.destroy_node() # 销毁节点对象 rclpy.shutdown() # 关闭ROS2 Python接口

完成代码的编写后需要设置功能包的编译选项,让系统知道Python程序的入口,打开功能包的setup.py文件,加入如下入口点的配置:

entry_points={ 'console_scripts': [ 'qos_helloworld_pub = my_learning_qos.qos_helloworld_pub:main', 'qos_helloworld_sub = my_learning_qos.qos_helloworld_sub:main', ], },

DDS本身是一个非常复杂的系统,ROS2使用的也只是冰山一角,这一节我们主要认识了DDS,更多使用方法和相关内容,可以参考文章最后的链接进行学习。

3.2.3 编译运行

编译程序:

pi@NanoPC-T6:~/dev_ws$ colcon build --paths src/my_learning_qos

启动第一个终端,运行发布者节点;

pi@NanoPC-T6:~/dev_ws$ ros2 run my_learning_qos qos_helloworld_pub [INFO] [1765977701.017109522] [qos_helloworld_pub]: Publishing: "Hello World" [INFO] [1765977701.481142094] [qos_helloworld_pub]: Publishing: "Hello World" [INFO] [1765977701.981325128] [qos_helloworld_pub]: Publishing: "Hello World" [INFO] [1765977702.481208424] [qos_helloworld_pub]: Publishing: "Hello World" [INFO] [1765977702.980783816] [qos_helloworld_pub]: Publishing: "Hello World" [INFO] [1765977703.481164427] [qos_helloworld_pub]: Publishing: "Hello World"

启动第二个终端,运行订阅者节点;

pi@NanoPC-T6:~/dev_ws$ ros2 run my_learning_qos qos_helloworld_sub [INFO] [1765977718.509490470] [qos_helloworld_sub]: I heard: "Hello World" [INFO] [1765977718.981377865] [qos_helloworld_sub]: I heard: "Hello World" [INFO] [1765977719.483689245] [qos_helloworld_sub]: I heard: "Hello World" [INFO] [1765977719.982267400] [qos_helloworld_sub]: I heard: "Hello World" [INFO] [1765977720.483497158] [qos_helloworld_sub]: I heard: "Hello World" [INFO] [1765977720.983902698] [qos_helloworld_sub]: I heard: "Hello World" [INFO] [1765977721.484018419] [qos_helloworld_sub]: I heard: "Hello World" [INFO] [1765977721.981400832] [qos_helloworld_sub]: I heard: "Hello World" [INFO] [1765977722.483140196] [qos_helloworld_sub]: I heard: "Hello World"

看效果确实差不多,不过底层通信机理上可是有所不同的。

[1] 古月居ROS2入门教程学习笔记

[2]ROS on DDS

[3]https://docs.ros.org/en/humble/Concepts/About-Different-Middleware-Vendors.html

[4]https://docs.ros.org/en/humble/How-To-Guides/Working-with-multiple-RMW-implementations.html

[5]https://www.bilibili.com/video/BV12z4y167w2

[6]DDS通信中间件——QoS策略

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/18 2:56:41

Flutter Engine长文本渲染优化:从卡顿到流畅的实战指南

你是否曾遇到过Flutter应用在渲染长篇对话记录或电子书时出现明显卡顿?当文本内容超过10万字,应用首屏加载缓慢,滑动体验更是令人沮丧。Flutter Engine通过其先进的渲染架构,为长文本场景提供了完整的性能优化方案,让海…

作者头像 李华
网站建设 2025/12/24 6:54:25

2025终极JUCE音频开发实战:从新手到专家的完整成长路径

2025终极JUCE音频开发实战:从新手到专家的完整成长路径 【免费下载链接】JUCE 项目地址: https://gitcode.com/gh_mirrors/juc/JUCE JUCE(Jules Utility Class Extensions)作为业界领先的跨平台C音频应用框架,为开发者提供…

作者头像 李华
网站建设 2025/12/18 2:55:42

实战精通CPUID指令:5个场景掌握处理器信息获取核心技术

实战精通CPUID指令:5个场景掌握处理器信息获取核心技术 【免费下载链接】linux-insides-zh Linux 内核揭秘 项目地址: https://gitcode.com/gh_mirrors/lin/linux-insides-zh 在Linux系统开发中,你是否曾困惑如何准确识别处理器特性、优化代码性能…

作者头像 李华
网站建设 2025/12/18 2:53:16

革命性Rust跨平台性能测试方案:企业级多架构性能基准实践

革命性Rust跨平台性能测试方案:企业级多架构性能基准实践 【免费下载链接】cross “Zero setup” cross compilation and “cross testing” of Rust crates 项目地址: https://gitcode.com/gh_mirrors/cro/cross 在当今多架构并行的技术环境中,R…

作者头像 李华
网站建设 2025/12/19 20:01:23

洛谷 P10468 兔子与兔子

题目描述很久很久以前,森林里住着一群兔子。有一天,兔子们想要研究自己的 DNA 序列。我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母)。然后我们每次选择两个区间&#xf…

作者头像 李华
网站建设 2025/12/18 2:52:03

终极智能设备管理平台:ThingsGateway完整指南

终极智能设备管理平台:ThingsGateway完整指南 【免费下载链接】ThingsGateway ThingsGateway 是基于Net6/7/8的跨平台边缘采集网关,提供底层PLC通讯库,通讯调试软件等。 项目地址: https://gitcode.com/gh_mirrors/th/ThingsGateway 在…

作者头像 李华