docs: 按 humanizer 重写项目文档并同步 RMIC::2026 现状
This commit is contained in:
+21
-21
@@ -3,9 +3,9 @@
|
||||
摄像头 UDP 图传的线路格式,**固件与两端客户端共用**。
|
||||
|
||||
```
|
||||
protocol/ 线路格式 + 帧重组 (13 个单元测试,无 ESP-IDF 依赖)
|
||||
protocol/ 线路格式 + 帧重组 (23 个单元测试,无 ESP-IDF 依赖)
|
||||
. 固件 -> ESP32-S3 (交叉编译,Xtensa)
|
||||
client/ 桌面客户端 (Slint,两种身份)
|
||||
desktop/ 桌面客户端 (RMIC::2026,Tauri v2 + React + Rust,两种身份)
|
||||
```
|
||||
|
||||
这是本仓库里最该被测试的部分:帧重组和编码都极易出微妙错误,而这两件事都无法
|
||||
@@ -17,23 +17,25 @@ client/ 桌面客户端 (Slint,两种身份)
|
||||
cd protocol && cargo test
|
||||
```
|
||||
|
||||
非 macOS / Apple Silicon 主机上,`protocol/.cargo/config.toml` 里钉住的 target 不适用,需按 [DEVELOPMENT.md](../DEVELOPMENT.md) 用 `--target <宿主三元组> --config 'unstable.build-std=[]'` 覆盖。本机实测:
|
||||
|
||||
```
|
||||
13 passed
|
||||
23 passed
|
||||
```
|
||||
|
||||
## 拓扑
|
||||
|
||||
```text
|
||||
┌──────────────────────────────┐
|
||||
│ 裁判终端(PC,仅显示) │
|
||||
│ 队伍一 + 队伍二 + 双方血量 │
|
||||
│ RMIC::2026 桌面端(仅显示) │
|
||||
│ 队伍一 + 队伍二 + 双方血量 │
|
||||
└───────────────┬──────────────┘
|
||||
│ 同一个局域网,广播可用
|
||||
┌────────────────────┼────────────────────┐
|
||||
│ │ │
|
||||
┌───────┴───────┐ ┌───────┴───────┐ ┌───────┴───────┐
|
||||
│ 图传板 A │ │ 图传板 B │ │ 装甲板 ×4 │
|
||||
│ (队伍一) │ │ (队伍二) │ │ (预留,未实现) │
|
||||
│ (队伍一) │ │ (队伍二) │ │ (已实现) │
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
@@ -42,7 +44,7 @@ cd protocol && cargo test
|
||||
|
||||
## 线路格式
|
||||
|
||||
每个数据报 = **27 字节头** + 至多 **1400 字节**载荷:
|
||||
每个数据报 = 27 字节头 + 至多 1400 字节载荷:
|
||||
|
||||
```text
|
||||
0 1 2 3
|
||||
@@ -72,12 +74,12 @@ cd protocol && cargo test
|
||||
| 2 `Subscribe` | 客户端 → 板子 | "我是这个角色,请给我画面" |
|
||||
| 3 `Hello` | 板子 → 客户端 | "我在线,我是谁" |
|
||||
| 4 `Heartbeat` | 板子 → 客户端 | 同上,心跳形式 |
|
||||
| 5 `ArmorHealth` | 装甲板 → 客户端 | 血量(**预留,当前无实现**) |
|
||||
| 5 `ArmorHealth` | 装甲板 → 客户端 | 血量(已实现) |
|
||||
|
||||
### 三个设计决定
|
||||
### 四个设计决定
|
||||
|
||||
**27 字节不凑整。** 头只占每个 1427 字节数据报的 1.9%,而为对齐在固件和客户端两侧
|
||||
各写一段手写偏移常量,是引入静默错位的更划算的代价。
|
||||
各写一段手写偏移常量,更容易引入静默错位。
|
||||
|
||||
**`sender_id` 是多路的前提。** 裁判终端同时收两块板子,靠它在同一端口上区分来源。
|
||||
|
||||
@@ -120,6 +122,7 @@ cd protocol && cargo test
|
||||
烧录",而不是让人去猜。
|
||||
|
||||
这不削弱边界:视频、订阅、装甲板上报仍然走严格解析。
|
||||
|
||||
## 为什么视频走 UDP 而不是 TCP
|
||||
|
||||
实测(VGA 640x480,传感器产出 22 fps):
|
||||
@@ -160,7 +163,7 @@ UDP 不保证跨数据报的顺序与到达,所以试图"补洞"的接收端
|
||||
它(`a_duplicate_cannot_complete_a_frame_with_a_hole`、
|
||||
`a_gap_that_is_never_filled_never_yields_a_frame`)。
|
||||
|
||||
**不过要说清楚:在实测链路上一次重复投递都没出现过。** 一到两个订阅者、20 秒 2000+
|
||||
**在实测链路上一次重复投递都没出现过。** 一到两个订阅者、20 秒 2000+
|
||||
个分片,重复数为 0(固定端口与临时端口两种订阅方式都试过)。所以这层防护是为了正确
|
||||
性,不是为了修一个正在发生的故障。
|
||||
|
||||
@@ -188,9 +191,8 @@ UDP 不保证跨数据报的顺序与到达,所以试图"补洞"的接收端
|
||||
|
||||
### 发送端的复用
|
||||
|
||||
`Fragment::encode_into()` 追加写入而不分配:发送端对每帧的每个分片复用同一个缓冲,
|
||||
在 22fps 下这是每秒约 250 次分配与不节省别的差别——在这块同时要抢内部 RAM 的芯片
|
||||
上很实在。
|
||||
`Fragment::encode_into()` 追加写入而不分配:发送端对每帧的每个分片复用同一个缓冲。
|
||||
22 fps 下这是每秒约 250 次分配,省掉它们在这块同时要抢内部 RAM 的芯片上很实在。
|
||||
|
||||
`fragment_frame()` 从 JPEG 长度推出分片数,因此调用方不可能产出与自身矛盾的集合。
|
||||
|
||||
@@ -215,7 +217,7 @@ UDP 不保证跨数据报的顺序与到达,所以试图"补洞"的接收端
|
||||
丢包都**记在应用账上**而不是网络账上——后者本来更容易排查。
|
||||
- VGA 下每帧约 17 个分片。
|
||||
- `DEFAULT_PORT` = 5600,两端共用同一个常量。
|
||||
- `ARMOR_PORT` = 5601,装甲板预留,当前无实现。
|
||||
- `ARMOR_PORT` = 5601,装甲板血量上报。
|
||||
|
||||
## 身份
|
||||
|
||||
@@ -234,10 +236,8 @@ UDP 不保证跨数据报的顺序与到达,所以试图"补洞"的接收端
|
||||
例子也有——它的 `role` 字节曾多填 12 个零字节,固件按偏移严格读取因而拒收,表现为
|
||||
"板子在线但 0 clients subscribed"。改协议时记得同步它。
|
||||
|
||||
## 装甲板(预留)
|
||||
## 装甲板
|
||||
|
||||
`ArmorHealth` 与 `ARMOR_PORT` 已就位,`MsgType` 也留了 5 号。现在没有实现也没有
|
||||
数据源,裁判界面显示占位符而不是 0——**0 看起来像真值,现场看到会以为对方已经没
|
||||
血了**。
|
||||
|
||||
接上以后板子向 `ARMOR_PORT` 发这个结构,客户端监听即可,界面与其它代码都不用改。
|
||||
`ArmorHealth` 占 `MsgType` 的 5 号。装甲板主板向 `ARMOR_PORT` 广播,`desktop/core/src/armor.rs`
|
||||
里的 `ArmorHealthStore` 负责接收。收不到上报时界面显示占位符而不是 0——**0 看起来像真值,
|
||||
现场看到会以为对方已经没血了**。
|
||||
|
||||
Reference in New Issue
Block a user