Files
ROS2_learn/doc/19-qos.md
T

195 lines
5.3 KiB
Markdown

# 19 · QoS (服务质量) 完全指南
> **目标**: 理解 ROS2 QoS 的 5 个维度、兼容规则、9 种常用组合、能独立为节点选 QoS。
---
## 目录
- [1. 是什么](#1-是什么)
- [2. 5 大维度](#2-5-大维度)
- [3. 兼容规则](#3-兼容规则)
- [4. 9 种常用组合](#4-9-种常用组合)
- [5. Python API](#5-python-api)
- [6. C++ API](#6-c-api)
- [7. rclpy QoSProfile 详解](#7-rclpy-qosprofile-详解)
- [8. 调试 QoS 不兼容](#8-调试-qos-不兼容)
- [9. 推荐阅读](#9-推荐阅读)
---
## 1. 是什么
**QoS (Quality of Service)** 控制 DDS 通信的可靠性、实时性、持久性等。
ROS2 默认 QoS = `RELIABLE + VOLATILE + KEEP_LAST(10)`,适合大多数场景。
但**高频传感器流** / **控制指令** / **参数发布**等场景需要**自定义 QoS**
## 2. 5 大维度
| 维度 | 取值 | 默认 | 含义 |
|---|---|---|---|
| **Reliability** | RELIABLE / BEST_EFFORT | RELIABLE | 必须投递 / 丢一帧无所谓 |
| **History** | KEEP_LAST(N) / KEEP_ALL | KEEP_LAST(10) | 队列策略 |
| **Durability** | VOLATILE / TRANSIENT_LOCAL | VOLATILE | 晚订阅者是否收到旧数据 |
| **Deadline** | Duration | ∞ | 最长多久发一次 |
| **Lifespan** | Duration | ∞ | 多旧的消息失效 |
## 3. 兼容规则
**关键规则** — RELIABLE ↔ BEST_EFFORT 单向兼容:
| Publisher ↓ \ Subscriber → | RELIABLE | BEST_EFFORT |
|---|---|---|
| RELIABLE | ✅ | ❌ |
| BEST_EFFORT | ✅ | ✅ |
**为什么 RELIABLE → BEST_EFFORT 不兼容**:
- RELIABLE pub 等 ACK(确保投递)
- BEST_EFFORT sub 不发 ACK
- pub 等不到 ACK → 报 "QoS incompatible"
**报错样例**:
```
[WARN] ... New subscription discovered on this topic with incompatible QoS ...
```
## 4. 9 种常用组合
| Reliability | Durability | History | 适用场景 |
|---|---|---|---|
| RELIABLE | VOLATILE | KEEP_LAST(10) | **默认 / 跨语言互通基线** |
| RELIABLE | VOLATILE | KEEP_LAST(1) | 控制指令(只关心最新) |
| RELIABLE | TRANSIENT_LOCAL | KEEP_LAST(1) | 参数 / 配置(晚订阅者也能拿到) |
| RELIABLE | VOLATILE | KEEP_ALL | 日志(必须投递,不丢) |
| RELIABLE | TRANSIENT_LOCAL | KEEP_ALL | 启动期参数 |
| BEST_EFFORT | VOLATILE | KEEP_LAST(1) | 视频流(丢一帧无所谓) |
| BEST_EFFORT | VOLATILE | KEEP_LAST(10) | Lidar / 雷达 |
| BEST_EFFORT | TRANSIENT_LOCAL | KEEP_LAST(1) | 较老的状态快照 |
| SYSTEM_DEFAULT | VOLATILE | KEEP_LAST(10) | 由 RMW 决定 |
## 5. Python API
```python
from rclpy.qos import (
QoSProfile,
ReliabilityPolicy,
HistoryPolicy,
DurabilityPolicy,
)
# 视频流:BEST_EFFORT + 深度 1
sensor_qos = QoSProfile(
reliability=ReliabilityPolicy.BEST_EFFORT,
history=HistoryPolicy.KEEP_LAST,
depth=1,
)
# 控制指令:RELIABLE + 深度 1
control_qos = QoSProfile(
reliability=ReliabilityPolicy.RELIABLE,
history=HistoryPolicy.KEEP_LAST,
depth=1,
)
# 参数:TRANSIENT_LOCAL(晚订阅者能拿历史)
param_qos = QoSProfile(
reliability=ReliabilityPolicy.RELIABLE,
durability=DurabilityPolicy.TRANSIENT_LOCAL,
depth=1,
)
# 用
publisher_ = self.create_publisher(String, 'topic', sensor_qos)
```
## 6. C++ API
```cpp
#include "rclcpp/qos.hpp"
using namespace rclcpp;
// 视频流
auto sensor_qos = QoS(1)
.reliability(RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT)
.history(RMW_QOS_POLICY_HISTORY_KEEP_LAST);
// 参数
auto param_qos = QoS(1)
.reliability(RMW_QOS_POLICY_RELIABILITY_RELIABLE)
.durability(RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
// 用
publisher_ = this->create_publisher<String>("topic", sensor_qos);
```
## 7. rclpy QoSProfile 详解
完整参数:
```python
QoSProfile(
# Reliability
reliability=ReliabilityPolicy.RELIABLE, # or BEST_EFFORT, SYSTEM_DEFAULT
# History
history=HistoryPolicy.KEEP_LAST, # or KEEP_ALL
depth=10, # 仅 KEEP_LAST 时有效
# Durability
durability=DurabilityPolicy.VOLATILE, # or TRANSIENT_LOCAL
# Deadline(可省)
deadline=Duration(seconds=0), # 0 = 无
# Lifespan(可省)
lifespan=Duration(seconds=0), # 0 = 无
# Liveliness(可省)
liveliness=LivelinessPolicy.SYSTEM_DEFAULT,
liveliness_lease_duration=Duration(seconds=0),
)
```
## 8. 调试 QoS 不兼容
**症状**: `ros2 topic echo` 没输出,`ros2 topic info -v` 显示 QoS incompatible 警告。
**调试步骤**:
```bash
# 1) 看 pub/sub 各自 QoS
ros2 topic info /topic -v
# 2) 检查 pub/sub 是否在同 domain
echo $ROS_DOMAIN_ID
# 3) 看具体 incompatibility
# 错误信息: PolicyKind=RMW_QOS_POLICY_RELIABILITY
```
**修法**: 改一边 QoS 匹配,或用 SYSTEM_DEFAULT。
## 9. 推荐阅读
- [ROS2 QoS 设计稿](https://design.ros2.org/articles/qos.html)
- [ROS2 Humble QoS 文档](https://docs.ros.org/en/humble/Concepts/About-Quality-of-Service.html)
- [OMG DDS 规范 v1.4](https://www.omg.org/spec/DDS/1.4/) — QoS 源头
- [FastDDS QoS 配置](https://fast-dds.docs.eprosima.com/)
- [`cpp_qos_demo` 包](../src/cpp_qos_demo/README.md)
---
---
## 📖 阅读路径导航
> 💡 这是仓库 `doc/` 下所有文档的推荐阅读顺序。[返回 README 总导航](../README.md#-23-篇文档怎么读)
>
> ⏱ **本文预计阅读时间**: 25 分钟
> 📍 **当前位置**: 第 10 / 24 篇
-**上一篇**: [Composable Node](../18-composable.md)
-**下一篇**: [Topic pub/sub 深度](../20-topics.md)