ROS2通信DDS 最核心的特性之一 QoS(Quality of Service,服务质量)

DDS 中的 QoS(Quality of Service,服务质量) 是其最核心的特性之一,它允许开发者精确控制数据通信的行为,满足不同场景对可靠性、实时性、资源使用的差异化需求。


一、QoS 核心概念

什么是 QoS?

复制代码
QoS = 一组可配置的策略参数,用于控制:
├── 数据可靠性(Reliability)
├── 传输实时性(Latency)
├── 资源使用(Resource limits)
├── 数据持久性(Durability)
└── 网络行为(Liveliness, Deadline 等)

QoS 设计哲学

复制代码
传统通信:One size fits all(一刀切)
DDS QoS:为每个 Topic 量身定制通信契约

比喻:
- TCP = 可靠但慢(如快递,必达但慢)
- UDP = 快但不可靠(如短信,可能丢)
- DDS QoS = 灵活选择(急件用专机,普通件用快递)

二、QoS 策略分类(23+ 种)

按功能分类

类别 策略 作用
可靠性 RELIABILITY 可靠传输 vs 尽力传输
持久性 DURABILITY 数据是否保存给后加入者
实时性 DEADLINE, LATENCY_BUDGET 时效性保证
生命周期 LIFESPAN, LIVELINESS 数据/节点存活检测
资源控制 HISTORY, RESOURCE_LIMITS 缓存大小、队列深度
传输配置 TRANSPORT_PRIORITY, OWNERSHIP 优先级、所有权

三、核心 QoS 策略详解

1. RELIABILITY(可靠性)

控制数据是否保证送达。

cpp 复制代码
// DDS 配置示例(伪代码)
ReliabilityQosPolicy reliability;

// 选项 1:可靠传输(RELIABLE)
reliability.kind = RELIABLE;
// 行为:类似 TCP,丢包会重传,保证送达
// 适用:关键指令、控制信号

// 选项 2:尽力传输(BEST_EFFORT)
reliability.kind = BEST_EFFORT;
// 行为:类似 UDP,不保证送达,低延迟
// 适用:传感器数据、视频流、高频数据

ROS 2 示例

python 复制代码
# Python 中设置 QoS
from rclpy.qos import QoSProfile, ReliabilityPolicy

qos = QoSProfile(
    reliability=ReliabilityPolicy.RELIABLE,  # 或 BEST_EFFORT
    depth=10
)

publisher = node.create_publisher(String, '/cmd_vel', qos)

2. DURABILITY(持久性)

控制数据是否保存给"后加入"的订阅者。

复制代码
场景:订阅者启动比发布者晚,能否收到之前的数据?

┌─────────────────────────────────────────┐
│  Durability: VOLATILE(易失)            │
│  └── 不保存历史数据                      │
│  └── 后加入者只能收到新数据               │
│  └── 默认设置,低资源占用                 │
│                                         │
│  Durability: TRANSIENT_LOCAL(本地持久) │
│  └── 发布者保存历史数据                  │
│  └── 后加入者能收到缓存的历史数据         │
│  └── 适用:配置参数、状态信息             │
│                                         │
│  Durability: TRANSIENT/PERSISTENT        │
│  └── 数据持久化到存储(需外部服务)       │
└─────────────────────────────────────────┘

3. HISTORY(历史记录)

控制缓存多少历史样本。

cpp 复制代码
HistoryQosPolicy history;

// KEEP_LAST: 只保留最近 N 个样本(环形缓冲区)
history.kind = KEEP_LAST;
history.depth = 10;  // 保留最近 10 条消息

// KEEP_ALL: 保留所有样本(直到资源限制)
history.kind = KEEP_ALL;
// 配合 RESOURCE_LIMITS 使用

实际效果

复制代码
订阅者处理速度慢于发布者时:

KEEP_LAST(depth=10):
发布:[1][2][3][4][5][6][7][8][9][10][11][12]
订阅:处理 [1]... 处理完时,收到 [3][4]...[12]
      丢失 [2](缓冲区满了,最老的被覆盖)

KEEP_ALL:
发布:[1][2][3]...
订阅:处理 [1] 时,[2][3]... 排队等待
      直到内存耗尽或 RESOURCE_LIMITS 触发

4. DEADLINE(截止期限)

检测数据是否按时到达。

cpp 复制代码
DeadlineQosPolicy deadline;
deadline.period.sec = 1;  // 期望每 1 秒收到一次数据

// 如果超过 1 秒没收到新数据,触发回调通知

应用场景

  • 心跳检测:机器人 1 秒必须发一次状态,否则认为失联
  • 传感器监控:激光雷达 100ms 必须输出一帧

5. LIFESPAN(数据有效期)

控制数据的有效时间,过期自动丢弃。

cpp 复制代码
LifespanQosPolicy lifespan;
lifespan.duration.sec = 5;  // 数据 5 秒后过期

// 发布者发送数据后,如果订阅者 5 秒内没收到,数据失效
// 适用:实时性要求高的数据,旧数据无意义

6. LIVELINESS(活跃度)

检测节点是否存活。

复制代码
┌─────────────────────────────────────────┐
│  AUTOMATIC(自动)                       │
│  └── DDS 自动管理,只要进程在就视为存活    │
│                                         │
│  MANUAL_BY_TOPIC(手动按话题)            │
│  └── 应用层必须定期声明"我还活着"         │
│  └── 适用:需要应用级心跳检测              │
│                                         │
│  MANUAL_BY_PARTICIPANT(手动按节点)      │
│  └── 应用层为整个节点声明存活             │
└─────────────────────────────────────────┘

lease_duration: 声明间隔,超时则认为节点死亡

7. OWNERSHIP(所有权)

多发布者竞争同一 Topic 时的行为。

复制代码
┌─────────────────────────────────────────┐
│  SHARED(共享)                          │
│  └── 多个发布者同时有效                  │
│  └── 订阅者收到所有发布者的数据           │
│  └── 默认设置                            │
│                                         │
│  EXCLUSIVE(独占)                       │
│  └── 只有"所有权强度"最高的发布者有效     │
│  └── 其他发布者被静默                    │
│  └── 适用:主备切换、冗余设计             │
└─────────────────────────────────────────┘

四、ROS 2 常用 QoS 预设配置

ROS 2 提供了常用场景的 QoS 预设:

预设名称 特点 适用场景
qos_profile_sensor_data 尽力传输、小队列、低延迟 传感器数据(激光、图像)
qos_profile_parameters 可靠、持久、大队列 参数配置
qos_profile_default 可靠、易失、中等队列 一般通信
qos_profile_services_default 可靠、易失 服务调用
qos_profile_parameter_events 可靠、持久 参数变更事件
qos_profile_system_default 使用 DDS 默认设置 底层系统
python 复制代码
# 使用预设
from rclpy.qos import qos_profile_sensor_data

publisher = node.create_publisher(
    LaserScan, 
    '/scan', 
    qos_profile_sensor_data  # 传感器优化配置
)

五、QoS 兼容性规则

关键原则:发布者和订阅者的 QoS 必须兼容才能建立连接。

兼容性矩阵

发布者 QoS 订阅者 QoS 是否兼容 实际行为
RELIABLE RELIABLE 可靠传输
RELIABLE BEST_EFFORT 降级为尽力传输
BEST_EFFORT RELIABLE 不兼容,无法连接
VOLATILE VOLATILE 无历史数据
VOLATILE TRANSIENT_LOCAL 不兼容
TRANSIENT_LOCAL VOLATILE 订阅者不要历史,不给
TRANSIENT_LOCAL TRANSIENT_LOCAL 提供历史数据

兼容性口诀

复制代码
"订阅者不能要求比发布者更高的可靠性"
"订阅者不能要求发布者没有的能力"

六、实际应用示例

场景 1:机器人遥控指令

python 复制代码
# 要求:绝对不能丢,但实时性次要
qos_cmd = QoSProfile(
    reliability=ReliabilityPolicy.RELIABLE,
    durability=DurabilityPolicy.VOLATILE,
    depth=1,  # 只保留最新指令
    deadline=Deadline(deadline_period=Duration(seconds=0.5))  # 500ms 超时检测
)

场景 2:激光雷达数据

python 复制代码
# 要求:高频、低延迟,丢几帧无所谓
qos_lidar = QoSProfile(
    reliability=ReliabilityPolicy.BEST_EFFORT,
    durability=DurabilityPolicy.VOLATILE,
    history=HistoryPolicy.KEEP_LAST,
    depth=5  # 保留最近 5 帧
)

场景 3:地图数据(大文件,后加入者需要)

python 复制代码
# 要求:可靠、持久,新节点启动能收到地图
qos_map = QoSProfile(
    reliability=ReliabilityPolicy.RELIABLE,
    durability=DurabilityPolicy.TRANSIENT_LOCAL,
    history=HistoryPolicy.KEEP_ALL,
    lifespan=Lifespan(lifespan_duration=Duration(seconds=0))  # 永不过期
)

七、总结

核心概念 要点
QoS 是什么 可配置的通信策略集合,精确控制数据行为
为什么重要 同一系统内不同数据有不同需求(控制指令 vs 传感器 vs 配置)
关键策略 RELIABILITY、DURABILITY、HISTORY、DEADLINE、LIVELINESS
兼容性 发布者和订阅者 QoS 必须匹配,否则无法通信
ROS 2 简化 提供预设配置,覆盖 90% 场景

QoS 是 DDS 区别于其他中间件的核心竞争力,它让 ROS 2 能同时满足实时控制大数据传输的矛盾需求,在同一系统中灵活配置。

相关推荐
LS_learner4 小时前
OpenSSH 服务器并启动/启用服务的完整流程
ros2
LS_learner4 小时前
ROS2的通信方式DDS—机器人的神经网络
ros2
zylyehuo16 小时前
Windows11 & Ubuntu22.04 双系统
ros2
liwulin05062 天前
【ESP32-S3】ESP32-S3 + YDLIDAR X2 + ROS2 远程导航完整落地方案
esp32·ros2·ydlidar
kyle~3 天前
ROS2----组件(Components)
开发语言·c++·机器人·ros2
元让_vincent4 天前
DaliyCoding C++ ROS | C++ 避坑指南:ROS 回调函数中的对象生命周期陷阱 (Use-After-Free)
开发语言·c++·机器人·ros·ros2
kyle~4 天前
ROS2---生命周期节点(Lifecycle Node)
c++·计算机视觉·机器人·ros2
kyle~7 天前
ROS2---QoS策略
c++·机器人·ros2
lucky-billy9 天前
Ubuntu 下一键部署 ROS2
linux·ubuntu·ros2