Files
simba-rmic-2026/README.md
T
sloray ee22a82ecd
构建客户端 / 检查(类型 + 单元测试) (push) Canceled after 0s
构建客户端 / Linux x64(deb + AppImage) (push) Canceled after 0s
构建客户端 / Windows x64(NSIS 安装包) (push) Canceled after 0s
构建客户端 / macOS 通用(.app + .dmg) (push) Canceled after 0s
docs: README 不写死构建号,改由 version.json 提供
2026-10-19 10:47:42 +08:00

358 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RMIC::2026 视野链路系统
黑龙江大学 602 实验室 · Simba Robotics 的机器人对抗赛视野链路。ESP32-S3 采集 OV5640 输出的硬件 JPEG,经 UDP 推给局域网内的桌面端;桌面端 RMIC::2026 提供队伍端与裁判端两套界面,接收 ESP32-C3 装甲板的血量广播,并负责固件维护。
当前版本 **v0.2.1**(线路协议 1,构建号见 `version.json`)。仓库已从 `ESP32S3_vt` 改名为 `simba-rmic-2026`,旧地址会重定向到新地址:
```text
git@git.simba-robotics.com:PRAM/simba-rmic-2026.git
```
## 组成与数据流
```text
ESP32-S3 图传板 A ─┐ ┌─ 队伍端(绑定本队板卡)
├─ 同一局域网 / UDP ─┼─ 裁判端(双路画面 + 装甲板表)
ESP32-S3 图传板 B ─┤ └─ 队伍端
ESP32-C3 装甲板 ───┘
```
视频使用 UDP **5600**,装甲板血量使用 UDP **5601**。板卡与客户端要在可互相通信、允许广播的网络里;关闭 AP 客户端隔离,并允许客户端程序通过防火墙。
| 部分 | 作用 | 技术栈 |
| --- | --- | --- |
| 根目录固件 | 图传板:相机采集、JPEG 分片、UDP 发送、发现与订阅、Wi-Fi 重连 | Rust `std` + ESP-IDF |
| `protocol/` | 视频与血量的线路格式、帧重组 | 纯 Rust,主机可测 |
| `desktop/` | RMIC::2026:队伍端 / 裁判端、录制、固件维护 | Tauri v2 + React + Rust |
| `armor/` | 装甲板:四路受击检测、WS2812 灯带、血量上报 | Rust + ESP-IDF(ESP32-C3) |
| `components/` | 本地相机驱动与 C/Rust 接口封装 | C + Rust FFI |
## 当前状态
图传板跑 VGA 640×480 彩色,完整接收约 **30 fps**,发射功率 **15 dBm**,三块 PSRAM 采集缓冲。发送端只保留当前一张完整 JPEG,拥塞时按有限预算重试,过期就转向新帧;原生视频通道和 WebView 都会拒绝滞留超过 100 ms 的旧帧。具体策略和五分钟实测见 [REALTIME.md](REALTIME.md)。
桌面端已经换成 Tauri v2 + React,不再是 Slint 客户端。队伍端有装甲条、瞄准器、命中反馈和密码闸门,裁判端有双路画面、可改队名、装甲板发现表、槽位分配和录制回放;两侧共用同一份快照。固件维护页支持选择编译后打出的 `.zip` 固件包,在坏块板上搜索可写槽位并回读校验,不需要重新编译。
装甲板是独立的 ESP32-C3 工程:主板负责四路压电片和四路灯带,整车 100 血,每次受击扣 3 点,每 200 ms 广播四条血量。
版本号和改动日志都从 git 历史算出。板子每 2 秒广播的 `Hello` 里带着语义化版本、构建号和编译进去的线路协议号;客户端会把它显示在绑定列表和裁判端每一格下面,协议不匹配时直接说明原因,而不是只表现为没有画面。
## 项目结构
| 路径 | 用途 |
| --- | --- |
| `src/` | ESP32-S3 图传固件,根目录 Cargo 项目 |
| `components/` | 本地相机驱动及 C/Rust 接口封装 |
| `protocol/` | 共享 UDP 协议与帧重组,支持主机测试 |
| `armor/` | 独立 ESP32-C3 装甲板 workspace |
| `desktop/` | Tauri + React 客户端及独立网络核心 `core/` |
| `scripts/` | 构建、烧录、打包与探测脚本 |
| `reference/armor/` | 早期 C 版装甲板工程 |
| `docs/` | 固件维护、自动烧录评估与界面重构设计稿 |
各子项目的构建目标不同。下面的编译、烧录流程针对根目录的 ESP32-S3 图传固件。
## 硬件要求
| 项目 | 当前配置 |
| --- | --- |
| 开发板 | Freenove ESP32-S3-WROOM CAM |
| 模组 | ESP32-S3-WROOM-1-N16R8,16 MB Flash + 8 MB Octal PSRAM |
| 摄像头 | OV5640;驱动包含 OV2640 / OV3660 支持,接线需核对 |
| 网络 | 2.4 GHz Wi-Fi |
| 连接 | 支持数据传输的 USB 线、可识别的串口及稳定供电 |
默认采集 VGA(640 × 480)、彩色 JPEG quality 12,按传感器节拍发送。相机引脚、Flash 分区和 PSRAM 配置见 [HARDWARE.md](HARDWARE.md)。换板型前必须核对接线,避免占用 Flash / PSRAM 引脚。
## 固件开发环境
本项目使用 Rust `std` 和 ESP-IDF。ESP32-S3 属于 Xtensa 架构,需要通过 `espup` 安装 Espressif Rust 工具链;普通 `rustup target add` 不能替代这一步。根目录固定使用名为 `esp-1.97.0.0` 的工具链,避免浮动版本影响构建。
### 1. 安装基础依赖与 Rust 工具
先安装 [Rust / rustup](https://rustup.rs/)、[Git](https://git-scm.com/downloads)、[Python 3](https://www.python.org/downloads/)(建议 3.11)、[CMake](https://cmake.org/download/) 与 [Ninja](https://ninja-build.org/),确保命令在 `PATH` 中。
- Windows:使用 PowerShell 7.5 或更新版本,安装 Visual Studio Build Tools 的“使用 C++ 的桌面开发”和 Windows SDK,使用 MSVC Rust 主机工具链。仓库和工具链尽量使用较短、无空格和中文的路径。
- Linux(Debian / Ubuntu):安装 `build-essential pkg-config libudev-dev libssl-dev python3 python3-venv cmake ninja-build git curl`。
- macOS:安装 Xcode Command Line Tools(`xcode-select --install`),以及 Python、CMake 和 Ninja。
以下命令显式使用 `+stable`,即使在仓库内执行,也不会要求事先已有 `esp`:
```text
rustup toolchain install stable
cargo +stable install espup --locked
cargo +stable install ldproxy --locked
cargo +stable install espflash --version 4.4.0 --locked
espup install --name esp-1.97.0.0 --toolchain-version 1.97.0.0 --targets esp32s3 --std
```
也可以从各工具的官方 releases 下载预编译程序。`espup --std` 安装本项目所需的 Rust / LLVM 工具,ESP-IDF 的 C 工具链由后续构建准备。
Linux / macOS 每次新开终端后执行:
```bash
. "$HOME/export-esp.sh"
```
Windows 安装后重新打开 PowerShell,让环境变量生效;若当前终端仍找不到 LLVM,可执行 `. "$HOME/export-esp.ps1"`。检查结果:
```text
rustup toolchain list
rustc +esp-1.97.0.0 --version
cargo +esp-1.97.0.0 --version
espflash --version
```
官方入门资料:[The Rust on ESP Book](https://docs.espressif.com/projects/rust/book/getting-started/toolchain.html)、[espup](https://github.com/esp-rs/espup)、[espflash](https://github.com/esp-rs/espflash/tree/v4.4.0/espflash)。
### 2. 准备 ESP-IDF
默认使用 ESP-IDF v5.5.5。首次构建时,`esp-idf-sys` 下载 SDK、对应 C 工具链及 Python 依赖,默认缓存到用户目录的 `.espressif/`;需要网络、磁盘空间及缓存目录写入权限。
已有匹配版本 SDK 时可在终端设置 `IDF_PATH`,不要提交个人绝对路径:
```powershell
# Windows:替换为实际 SDK 源码目录。
$env:IDF_PATH = 'C:\Espressif\frameworks\esp-idf-v5.5.5'
```
```bash
# Linux / macOS:替换为实际 SDK 源码目录。
export IDF_PATH="$HOME/esp/esp-idf-v5.5.5"
```
使用自动下载时,清除指向其他 SDK 的旧 `IDF_PATH`。缓存位置等高级设置见 [esp-idf-sys 构建选项](https://github.com/esp-rs/esp-idf-sys/blob/master/BUILD-OPTIONS.md)。
## 配置 Wi-Fi 与摄像头
在根目录复制 `.env.example` 为 `.env`,再用编辑器填写;已有 `.env` 时不要覆盖。
```powershell
# Windows PowerShell
Copy-Item .env.example .env
```
```bash
# Linux / macOS
cp .env.example .env
```
```dotenv
WIFI_SSID='你的2.4G网络名称'
WIFI_PASS='你的Wi-Fi密码'
# 可选,省略时使用固件默认值。
#CAM_RES=vga
#CAM_QUALITY=12
#CAM_QUALITY_MAX=0
#CAM_MAX_FPS=0
#CAM_CLOCK_PROFILE=default
#CAM_FB_COUNT=3
#CAM_GRAYSCALE=0
#CAM_EXPOSURE_EV=0
#CAM_AE_LEVEL=-1
#CAM_SHUTTER_LINES=0
#CAM_EXPOSURE_MAX_LINES=0
#CAM_GAIN_CEILING=0
#CAM_HTS=0
#UDP_PACKET_GAP_US=0
#UDP_RETRY_BUDGET_US=8000
#CAM_THERMAL_LIMIT_C=75
#CAM_VSYNC_INVERT=1
#WIFI_AUTH=wpa2
#WIFI_TX_POWER_DBM=15
#WIFI_TEST_DROP_AFTER_S=0
```
| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `WIFI_SSID` | 无,必填 | 2.4 GHz 网络名称,最多 32 字节 |
| `WIFI_PASS` | 空字符串 | Wi-Fi 密码;开放网络可留空 |
| `CAM_RES` | `vga` | `qqvga` / `qvga` / `cif` / `hvga` / `vga` / `svga` / `xga` / `sxga` / `uxga` |
| `CAM_QUALITY` | `12` | 0–63,越小通常画质越好、JPEG 越大;当前交付使用 18 |
| `CAM_QUALITY_MAX` | `0` | `0` 固定画质;设为 `CAM_QUALITY`–63 时按发送回压在两者之间调节压缩,保留彩色和分辨率。拥塞时每 5 秒增大最多 3 档,连续稳定 15 秒才恢复 1 档 |
| `CAM_MAX_FPS` | `0` | 取帧与发送的最高节拍,1–60;`0` 不限帧。仅限制消费节拍,不修改传感器时钟 |
| `CAM_CLOCK_PROFILE` | `default` | `default` 保留驱动时钟;`vga30` 使用 OV5640 VGA 约 30.09 fps PLL 配置,保持 HTS/VTS 和读出窗口,SYSCLK 61 MHz / PCLK 15.25 MHz。切换后需重新核对曝光行数 |
| `CAM_FB_COUNT` | `3` | PSRAM 帧缓冲数,允许 2 或 3。当前交付选三缓冲,保留发送突发时的采集余量;双缓冲曾在短测降低部分回显延迟,但用户长程运行反馈峰值丢帧明显,保留为试验选项 |
| `CAM_GRAYSCALE` | `0` | `1` 使用传感器灰度效果,保留硬件 JPEG;`0` 彩色 |
| `CAM_EXPOSURE_EV` | `0` | OV5640 自动曝光目标偏置:`-1` / `-2` 约对应 −1.1 / −1.9 EV;不是标定后的绝对 EV,也不保证快门缩短 |
| `CAM_AE_LEVEL` | 未设置 | 可选 OV5640 驱动 AE 档位,−5–5;仅与 `CAM_EXPOSURE_EV=0` 同用。`-1` 将目标从 55 小幅降至 45,目标比值约 −0.29 EV,保留自动曝光/增益;未设置时按 EV 参数处理。实际快门和亮度变化取决于场景 |
| `CAM_SHUTTER_LINES` | `0` | OV5640 固定快门,单位为传感器曝光行;`0` 自动曝光,非零保持自动增益。默认 VGA / HTS 2060 下 220 行估算约 10 ms;数值不能超过当前 VTS |
| `CAM_EXPOSURE_MAX_LINES` | `0` | OV5640 自动曝光上限,`0` 保留驱动默认。非零保持 AEC/AGC 联动并禁用夜景延帧,不能与固定快门同时使用。默认 VGA 下 440 行约 20 ms;`vga30` 下 592 行约 20 ms。实际曝光由场景和抗频闪步长决定 |
| `CAM_GAIN_CEILING` | `0` | OV5640 自动增益上限,`0` 保留驱动默认;1–63,单位为倍,实际上限略低于整数档。短曝光遇到室内弱光时可提高,但暗部噪点和 JPEG 负载可能增加 |
| `CAM_HTS` | `0` | OV5640 水平总长度试验参数,`0` 使用驱动默认。缩短消隐会影响彩色稳定性,本机 1500 / 1800 出现绿紫闪烁,已撤回;几何检查通过不代表可用 |
| `UDP_PACKET_GAP_US` | `0` | 成功提交视频数据报之间的最小间隔;0–5000 μs,须为调度 tick 的整数倍(当前为 1000 μs)。配合有界帧等待,避免集中突发写入队列 |
| `UDP_RETRY_BUDGET_US` | `8000` | 每帧、所有分片及订阅者共用的让出调度重试预算,0–25000 μs,须为 tick 整数倍;`0` 为非阻塞失败即弃。总发送检查期限为 25 ms,采集帧龄期限为 100 ms;分片间隔也计入期限,不会额外延长 |
| `CAM_THERMAL_LIMIT_C` | `75` | 芯片内部温度达到该值时减半帧率(向上取整),下降 5°C 后恢复;40–95,`0` 禁用。原先不限帧时降至 8 fps |
| `CAM_VSYNC_INVERT` | `1` | 驱动反相 VSYNC;硬件已反相时填 `0` |
| `WIFI_AUTH` | 自动选择 | `none` / `wep` / `wpa` / `wpa2` / `wpawpa2` / `wpa3` / `wpa2wpa3` / `wapi`;只在扫描看不到 AP(如隐藏 SSID)时才需要 |
| `WIFI_TX_POWER_DBM` | SDK 默认上限 | 可选整数 2–20 dBm;当前交付请求 15 dBm,本板驱动回读 15.00 dBm;启动及重连时应用,拥塞和温控逻辑不降低此上限 |
| `WIFI_TEST_DROP_AFTER_S` | `0` | 仅诊断构建:运行指定秒数后主动断网一次并保持 5 秒,用来验证运行时恢复。正式构建保持 `0` |
`.env` 使用简单的 `KEY=value`;值含空格、`#` 或 `$` 时用单引号包围,不使用变量展开或命令替换。脚本会加载 `.env`,直接 `cargo build` 不会自动读取它。上述参数在编译时写入固件,修改后需要重新编译和烧录。`.env` 已被 Git 忽略;固件也包含凭据,分享前应重新配置。
运行时断线恢复不重置摄像头、曝光或增益。首次尝试立即发起,失败后按 1、2、4、8、16、30 秒退避;关联与 DHCP 分别有 15 秒期限。恢复 IP 后丢弃旧采集帧、重建 socket 并重新广播,由客户端自动续订。启动时首次联网仍使用扫描与认证模式探测流程。实现依据 [ESP-IDF 断线事件处理说明](https://docs.espressif.com/projects/esp-idf/en/v5.5.5/esp32s3/api-guides/wifi.html#wifi-event-sta-disconnected)。
## 编译固件
在仓库根目录执行:
```powershell
# Windows PowerShell
$env:CARGO_TARGET_DIR = 'C:\s3vt'
.\scripts\build.ps1
```
```bash
# Linux / macOS
./scripts/build.sh
```
脚本执行 `cargo build --release --locked`,目标为 `xtensa-esp32s3-espidf`。首次编译包含 Rust 标准库、ESP-IDF 和相机组件,耗时较长。构建完成后可用 `-Package` / `--package` 再打一个 `.zip` 固件包,供桌面端维护页使用。
Windows 的 ESP-IDF 构建输出路径需不超过 88 字符,因此示例使用短目录 `C:\s3vt`(需可写,且不与其他项目共用)。`subst` 不能绕过该检查。下表的 `<TARGET_DIR>` 在 Windows 示例中为 `C:/s3vt`,Linux / macOS 默认是仓库的 `target`。每次新开 Windows 终端都要设置相同的 `CARGO_TARGET_DIR`。
| 产物 | 位置 |
| --- | --- |
| 固件 ELF | `<TARGET_DIR>/xtensa-esp32s3-espidf/release/esp32`(没有 `.exe` 后缀) |
| Bootloader | `<TARGET_DIR>/xtensa-esp32s3-espidf/release/bootloader.bin` |
| 分区表 BIN | `<TARGET_DIR>/xtensa-esp32s3-espidf/release/partition-table.bin` |
| 分区表源文件 | 根目录 `partitions.csv` |
ELF 供 `espflash` 烧录与符号解析,不能当作 BIN 直接写入 Flash。Bootloader、分区表与 App 应来自同一次构建。
## 烧录与串口验证
### 1. 查找串口
```text
espflash list-ports
```
Windows 常见 `COM5`;Linux 为 `/dev/ttyACM0` 或 `/dev/ttyUSB0`;macOS 为 `/dev/cu.usbmodem...`。关闭其他串口监视器,Linux 需具备串口访问权限。
### 2. 烧录 ELF
本项目使用自定义分区表,显式传入 `partitions.csv` 和本次构建的 Bootloader。将示例端口替换为实际端口:
```powershell
$targetDir = if ($env:CARGO_TARGET_DIR) { $env:CARGO_TARGET_DIR } else { 'target' }
espflash flash --chip esp32s3 --port COM5 --flash-size 16mb --flash-mode dio --flash-freq 40mhz --partition-table partitions.csv --bootloader "$targetDir/xtensa-esp32s3-espidf/release/bootloader.bin" --monitor "$targetDir/xtensa-esp32s3-espidf/release/esp32"
```
```bash
target_dir="${CARGO_TARGET_DIR:-target}"
espflash flash --chip esp32s3 --port /dev/ttyACM0 --flash-size 16mb --flash-mode dio --flash-freq 40mhz --partition-table partitions.csv --bootloader "$target_dir/xtensa-esp32s3-espidf/release/bootloader.bin" --monitor "$target_dir/xtensa-esp32s3-espidf/release/esp32"
```
连接失败时按住 BOOT,点按 RESET / EN,松开 BOOT 后重试。正常启动应看到相机识别、Wi-Fi 获取 IP 和 `ESP32 camera is live` 日志。没有客户端时,`0 clients subscribed` 属于正常状态。
仅查看日志:
```text
espflash monitor --port COM5
```
### 3. 导出 BIN
`espflash save-image --merge` 可导出从 `0x0` 写入的合并镜像。完整命令、独立镜像偏移与测试方法见 [DEVELOPMENT.md](DEVELOPMENT.md)。
保留的 `scripts/flash.sh` 针对特定坏 Flash 模组,依赖 macOS 环境,会修改分区并重编译。普通板卡使用上述标准流程;坏板限制见 [HARDWARE.md](HARDWARE.md#损坏-flash-模组的兼容处理)。
## 桌面端 RMIC::2026
安装依赖并启动开发模式:
```text
cd desktop
pnpm install
pnpm app
```
`pnpm app` 等价于 `tauri dev`:起 Vite、编 Rust、开窗口。只构建前端用 `pnpm build`,打包用 `pnpm tauri build`。Windows x64 需要 Node.js 22.12+、pnpm、Rust stable MSVC、Visual Studio Build Tools 的 C++ 组件和 WebView2 Runtime;安装包用 NSIS,产物在 `src-tauri/target/x86_64-pc-windows-msvc/release/`。
没有板子也能跑演示模式:
```text
cd desktop
CAM_DEMO=1 pnpm app
```
演示模式合成协议数据报,从真实的接收与重组路径进入界面,不是给界面塞假数据。界面配置、密码、绑定、录制、裁判端槽位、防作弊和固件维护的细节见 [desktop/README.md](desktop/README.md)。固件维护页的实现、`.zip` 包格式与实机验证范围见 [docs/firmware-maintenance.md](docs/firmware-maintenance.md)。
## 装甲板
装甲板是独立的 ESP32-C3 / RISC-V 工程,不能使用 S3 的 ELF。`ARMOR_TEAM=0/1` 在编译期决定红 / 蓝队伍。接线、规则与构建烧录见 [armor/README.md](armor/README.md)。
```bash
scripts/build_armor.sh # 编译
scripts/flash_armor.sh # 烧录并看 20 秒日志
python3 scripts/armor_probe.py 15 # 不打开界面时核对血量广播
```
## 常见问题
| 现象 | 检查方法 |
| --- | --- |
| 提示缺少 `esp-1.97.0.0` | 按上述命令安装指定名称的工具链,重新打开终端后检查版本 |
| `espup` 查询 GitHub 版本返回 403 | 对上述固定版本安装命令追加 `--skip-version-parse`,或稍后重试 |
| 找不到 `ldproxy` / `libclang` | 安装链接工具;Unix 加载 `export-esp.sh`,Windows 重开终端 |
| ESP-IDF 路径或版本错误 | 清除旧 `IDF_PATH` 或指向 v5.5.5 SDK |
| Windows 路径过长 | 缩短仓库和工具链路径,见开发说明 |
| Wi-Fi 连不上 | 核对 2.4 GHz、凭据和认证方式,再重新编译烧录 |
| 相机无输出 / 初始化失败 | 核对板型接线、供电与 Octal PSRAM |
| `NO-EOI`、几帧后停止 | 确认 `CONFIG_CAMERA_PSRAM_DMA=n` |
| 在线但没有画面 | 检查客户端订阅、UDP 5600、防火墙及 AP 隔离 |
| 界面提示协议不匹配 | 板子与客户端的线路协议号不同;按提示重新烧录同版本的固件 |
| 开启 VPN / 虚拟网卡后设备在线但无画面 | 使用支持按已发现设备 IP 定向续订的客户端;仅发送 `255.255.255.255` 广播可能走错网卡 |
| 改 C 组件后无变化 | 清理 `esp-idf-sys` 构建缓存后重编,见开发说明 |
| 主机项目被编为 Xtensa | 显式指定宿主 target,见各子项目说明 |
用 `python scripts/udp_probe.py 10` 可独立检查视频协议;装甲板用 `python scripts/armor_probe.py 15`。这些脚本需要板卡在线,构建通过不代表已完成硬件验证。
测量帧率和丢帧可运行以下命令,将 IP 换成板卡实际地址。对照测试时先退出桌面客户端,避免额外订阅者增加无线负载:
```text
python scripts/perf_probe.py 192.168.1.139 --seconds 30 --json perf.json
```
脚本定向续订,支持保留 VPN / TUN 的环境。输出包含完整帧率、帧损失率、接收间隔和组装耗时;这些时间不等于摄像头到屏幕的端到端延迟。
运动图传保持 `CAM_GRAYSCALE=0`,优先使用自动曝光上限和自动增益协同控制拖影。室内强制 −1 EV / 固定短快门在本机过暗,已撤回;提高增益上限也会增加噪点。需要限流时设 `CAM_MAX_FPS=15`,追求帧率时用 `0`;可启用有界 JPEG 压缩调节应对发送回压,分片间隔按网络实测选择。灰度效果仍保留硬件 JPEG,不是改为 RGB565 或降低 JPEG 采样位数。75°C 是主动减载阈值,温度来自 ESP 芯片内部,不能代表摄像头或环境温度,也不是芯片损坏温度规格。五分钟彩色对照与此前中止的灰度长测见 [STABILITY.md](STABILITY.md)。
## 版本号与改动日志
版本号和 `CHANGELOG.md` 不手写,从 git 历史算:
```sh
node scripts/version.mjs --write # 计算并写回 version.json / CHANGELOG / 客户端版本
node scripts/version.mjs --check # 只校验(CI 与发布前用)
```
- 版本号由提交类型决定:`BREAKING CHANGE:` → major,`feat` → minor,`fix` / `perf` → patch。
- 构建号 = `git rev-list --count HEAD`,单调、不撞车。
- 同一次计算还产出 `version.json`(固件 `build.rs` 读它)、`CHANGELOG.json`、`desktop/src/lib/version.ts`。
固件与客户端的版本是联动的:板子每 2 秒广播的 `Hello` 里带着语义化版本、构建号与它编译进去的线路协议号;客户端读出来显示在设置与裁判端每一格下面,协议对不上时直接说明原因(“板子是协议 2,客户端是协议 1,画面会被丢弃,请重新烧录”),而不是只表现为没有画面。
细节见 [desktop/README.md](desktop/README.md#版本与改动日志算出来的不是写出来的) 与 [protocol/README.md](protocol/README.md#通告里的版本信息)。
## 文档索引
- [CHANGELOG.md](CHANGELOG.md):改动记录,由脚本从 git 历史生成。
- [HARDWARE.md](HARDWARE.md):接线、内存、Flash 与驱动限制。
- [DEVELOPMENT.md](DEVELOPMENT.md):镜像导出、测试、协议与性能测量。
- [PERFORMANCE.md](PERFORMANCE.md):保留 TUN 的图传排查、参数取舍与实际测试结果。
- [STABILITY.md](STABILITY.md):限帧、灰度与温度减载,长时间运行测试。
- [REALTIME.md](REALTIME.md):阻塞时取最新帧、超期丢弃和客户端积压处理。
- [POWER.md](POWER.md):15 dBm 回退、功率与距离的关系,以及发送拥塞证据。
- [LATENCY.md](LATENCY.md):约 30 fps 配置、Wi-Fi 重连及实际画面链路延迟对照。
- [FLASH-CLIENT-ARCH.md](FLASH-CLIENT-ARCH.md):烧录 / 维护客户端的架构提议稿。
- [protocol/README.md](protocol/README.md):UDP 线路格式及帧重组。
- [armor/README.md](armor/README.md):装甲板固件与规则。
- [desktop/README.md](desktop/README.md):RMIC::2026 的配置、录制与排查。
- [docs/firmware-maintenance.md](docs/firmware-maintenance.md):已实现的固件维护页、官方 bundle 格式、坏块规避流程与实机验证记录。
- [docs/firmware-provisioning-evaluation.md](docs/firmware-provisioning-evaluation.md):自动烧录、坏区规避与 SSID 配置 patch 的工具评估、MVE 与测试矩阵。
- [docs/desktop-ui-redesign.md](docs/desktop-ui-redesign.md):RMIC::2026 界面、比赛控制与直播包装的重构设计稿。
- [docs/CHANGELOG-legacy.md](docs/CHANGELOG-legacy.md):建立自动版本机制之前的人工改动记录。