180 lines
4.9 KiB
Markdown
180 lines
4.9 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) |