GrabBag/App/DroneScrewbolt/Doc/project_design.md
2026-07-11 15:28:36 +08:00

382 lines
20 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.

# DroneScrewbolt 项目设计文档
## 1. 项目定位
DroneScrewbolt 采用远端服务端和地面端控制应用分离的结构。
- DroneScrewServer部署在远端板卡直接连接双目相机负责采集、推流、算法检测和 ZMQ 协议服务。
- WDRemoteReceiver地面端通信库封装设备发现、控制命令、检测结果订阅和原始图像订阅。
- DroneScrewCtrlApp地面端用户应用负责连接远端服务、切换工作模式、展示图像和检测结果并提供参数配置入口。
服务端是算法和设备控制中心,地面端不直接操作相机和算法,只通过 WDRemoteReceiver 调用服务端能力。
## 2. 工作模式
### 2.0 模式参数总表
| 模式 | 控制命令 | detectMode | 相机降采样 | 采集/处理帧率 | 图像输出 | 压缩参数 | 视频链路 | result 输出 | 地面端显示 | 测试入口 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 距离检测(RTMP/RTSP) | `start_stream` / `stop_stream` | 不使用 | 关闭 binning使用 `DecimationHorizontal/Vertical=4x4` 相机端抽样下采样4096x3000 输出 1024x750曝光直接使用配置曝光 | `30fps` | 单路实时视频,默认 `1024x750` | H.264`Rtsp.bitrateKbps` 默认 `4096Kbps`GOP 固定为 `fps/2`,约 `0.5s` | DroneScrewServer 内部推 `rtmp://127.0.0.1:1935/live/dronescrew`,地面端拉 `rtsp://<server-ip>:8554/live/dronescrew` | `DetectDistance` 持续发布 boxes/distances协议距离单位为 mm | DroneScrewCtrlApp 拉 RTSP测距结果 overlay 和列表按 m 显示 | `Test\WDRemoteReceiverTest` 的 LiveStream |
| 精准检测(双图 raw) | `set_detect_mode=binocular``start` / `stop` | `binocular` | `1x1`/关闭 binning | `2fps` | 左图 + 右图,全分辨率 raw | zlib 无损压缩,失败时 raw 兜底 | 关闭 RTSP/RTMP | `Detect` 精准检测结果持续发布 | 用于联调/测试双目 raw 链路;正式 DroneScrewCtrlApp 默认不进入该传输方式 | `Test\WDRemoteReceiverTest` 选择 binocular 后 Start |
| 精准检测(单图 raw) | `set_detect_mode=mono``start` / `stop` | `mono` | `1x1`/关闭 binning | `2fps` | 左图右图为空4096x3000 输入压缩后约 1024x750 | 固定有损压缩Mono8 先按 `1/4` 缩放,再 MJPEG `quality=25`;不动态算带宽、不跳帧 | 关闭 RTSP/RTMP | `Detect` 精准检测结果持续发布result 坐标系固定为算法输入原图尺寸 | DroneScrewCtrlApp 使用压缩后左图显示raw/result 按 frameId 对齐后按原图坐标比例叠框,图像中只标框和序号,列表显示每个目标 | `Test\WDRemoteReceiverTest` 选择 mono 后 Start |
| 程序 | 定位 | 应覆盖的模式 |
| --- | --- | --- |
| `Test\WDRemoteReceiverTest` | 通信库和模式链路测试工具 | 距离检测、精准检测双图 raw、精准检测单图 raw |
| `DroneScrewCtrlApp` | 正式地面端用户程序 | 距离检测(RTSP + result) 和精准检测单图 raw(MJPEG + result) |
### 2.1 距离检测模式
距离检测模式用于实时观察和距离检测。
服务端行为:
- 双目相机关闭 binning固定使用 `DecimationHorizontal/Vertical=4x4` 相机端抽样下采样采集。
- `Decimation` 是相机输出阶段的像素抽样降采样,不是压缩,也不是求平均/求和合并它会改变相机输出分辨率4096x3000 在 4x4 decimation 后输出 1024x750。
- MVS SDK 自带 `Features.xml` 中未提供 `BinningMode``Average``Sum` 这类 binning 合并模式选择;已确认的 `DecimationHorizontal/Vertical` 描述为 image sub-sampling因此距离模式固定使用 decimation 来保持与精准检测相同的曝光语义。
- 距离检测和精准检测使用同一个配置曝光值;运行中通过 `set_exposure` 修改曝光时也直接按当前配置曝光下发,不再按 binning 倍率做 `/16` 换算。
- 当前设计帧率为 30fps。
- 现场双目相机分别连接两个独立 USB 控制器1024x750 Mono8 30fps 单路原始数据约 23MB/s约 184Mbps两路分摊到独立 USB2.0 控制器后按 30fps 设计。该约束不适用于两台相机共用同一个 USB2.0 root hub 的接法。
- 算法走 DetectDistance 距离检测 pipeline。
- 启动实时视频链路:服务端内部 RTMP 推到本机 mediamtx地面端通过 RTSP 拉取配置指定的单路相机画面。
- 同时通过 ZMQ result 通道发布距离检测结果。
地面端行为:
- 通过 RTSP 拉流显示实时画面。
- 同时订阅 ZMQ result接收距离检测结果。
- result 中的 boxes/distances 用于显示检测框和距离信息;协议内距离仍以 mm 保存,地面端距离检测 UI 按 m 显示。
- 该模式不依赖 ZMQ raw 图像通道显示画面。
设计要求:
- 距离检测模式必须同时具备 RTSP 拉流和 result 订阅。
- 地面端进入距离检测模式时不能停止 result 订阅。
- 服务端 start_stream 不能只被理解为“单纯推流”它代表“decimation 距离检测 + 实时推流”。
### 2.2 精准螺栓检测模式
精准螺栓检测模式用于高分辨率螺栓检测。
服务端行为:
- 双目相机关闭 binning使用原始分辨率采集。
- 当前设计帧率为 2fps。
- 算法走 Detect 精准检测 pipeline。
- 停止实时视频链路。
- 通过 ZMQ raw 图像通道发布图像。
- 通过 ZMQ result 通道发布检测框和距离结果。
地面端行为:
- 不拉 RTSP。
- 订阅 ZMQ raw 图像,用 raw 左目图作为显示画面。
- 订阅 ZMQ result用检测结果叠加检测框并展示列表。正式地面端按最新帧刷新结果列表精准检测显示每个目标距离检测显示最新测距结果。
- raw 图像和 result 必须按 frameId 对齐后再叠加;单图 raw 显示图为压缩后尺寸,但 result 坐标系保持算法输入原图尺寸,由地面端按比例缩放绘制。
- 地面端绘制时必须把已经匹配的 raw/result 成对送入绘制队列,不能在绘制线程再读取“最新结果”;框坐标只按 result 的 imageWidth/imageHeight 到当前 QImage 像素尺寸缩放QGraphicsView 的 fitInView 只负责最终显示缩放。
- 默认可使用 detectMode=mono只传左目 raw 图以降低网络带宽;算法内部仍使用服务端双目输入。
设计要求:
- detectMode 只影响 raw 图像传输内容,不代表算法变为单目。
- 精准检测模式启动后应持续检测,不应只处理一帧或两帧后停止。
### 2.3 检测图像保存
服务端进入检测状态后必须把进入算法的左右图像对异步保存到本地磁盘。保存线程独立于检测线程检测线程只负责深拷贝图像并放入保存队列PNG 编码和写盘由保存线程完成。
目录规则:
- 根目录固定为 `/home/cat`
- 二级目录为启动当天日期,格式 `yyyyMMdd`
- 三级目录为当前检测模式:距离检测为 `distance`,精准单图 raw 为 `precision_mono`,精准双图 raw 为 `precision_binocular`
- 文件名按本轮检测序号从 1 开始递增:`leftImage_N.png``rightImage_N.png`
示例:
- `/home/cat/20260629/distance/leftImage_1.png`
- `/home/cat/20260629/distance/rightImage_1.png`
保存失败或队列满时只记录日志,不允许阻塞检测线程或导致检测流程退出。
## 3. 通信通道
| 通道 | 默认端口 | 模式 | 用途 |
| --- | ---: | --- | --- |
| UDP discovery | 5554 | 广播/应答 | 地面端搜索 DroneScrewServer |
| ZMQ control | 15555 | REQ/REP | start/stop/open/get_info/参数设置 |
| ZMQ result | 15556 | PUB/SUB | 检测结果 boxes/distances |
| ZMQ raw | 15557 | PUB/SUB | 精准检测模式下的 raw 图像 |
| RTMP publish | 1935 | FFmpeg/FLV | DroneScrewServer 推到本机 mediamtx 的内部入口 |
| RTSP pull | 8554 | RTSP/TCP | 地面端和 VLC 从 mediamtx 拉取距离检测实时画面 |
### 3.1 实时推流设计
实时推流只属于距离检测模式,也就是 `start_stream` 对应的 LiveStream 状态。它不是单独的视频功能,而是和 4x4 decimation 采集、DetectDistance 距离检测、result 发布一起启动。
服务端推流链路:
1. `start_stream` 到达 DroneScrewServer。
2. 服务端停止精准检测相关状态配置相机为距离检测模式binning=1x1、decimation=4x4默认 30fps。
3. 服务端启动单路实时画面编码,输入为 Mono8缩放到配置尺寸转换为 NV12。
4. `CVrFFMediaPusher` 使用 Rockchip MPP 编码 H.264,码率由 `Rtsp.bitrateKbps` 配置,默认 4096KbpsGOP 按当前 fps 的一半设置30fps 时约 0.5s,减少新客户端等待关键帧的时间。
5. 服务端内部推流地址固定为 `rtmp://127.0.0.1:1935/live/dronescrew`
6. mediamtx 接收 RTMP publish并对外提供 RTSP 拉流。
7. 对外拉流地址通过 discovery/get_info/start_stream 返回给地面端,格式为 `rtsp://<板子IP>:8554/live/dronescrew`
端口边界:
- `1935` 是服务端内部 RTMP publish 端口,只给 DroneScrewServer 推到本机 mediamtx 使用。
- `8554` 是客户端 RTSP pull 端口DroneScrewCtrlApp、VLC、ffplay 都必须拉这个端口。
- 配置文件 `<Rtsp port="...">` 表示对外 RTSP pull 端口,不表示内部 RTMP publish 端口。
- 如果旧配置误写成 `1935`,服务端应警告并自动改用 `8554` 作为对外拉流端口。
mediamtx 职责:
- 监听 `rtmpAddress: :1935`,接收服务端内部 RTMP 推流。
- 监听 `rtspAddress: :8554`,给地面端提供 RTSP 拉流。
- 路径使用 `/live/dronescrew`,不需要为该路径预先创建固定配置,按 publisher 动态建立。
地面端拉流链路:
1. DroneScrewCtrlApp 通过 WDRemoteReceiver 发送 `start_stream`
2. WDRemoteReceiver 启动 result 订阅,关闭 raw 订阅。
3. `start_stream` 成功后DroneScrewCtrlApp 读取服务端返回或 get_info 返回的 `rtsp` 字段。
4. 拉流地址以服务端返回为准;如果服务端未返回地址,则用配置中的 `serverIp + rtspPort + rtspPath` 生成兜底地址。
5. 地面端必须把旧地址 `rtmp://...:1935/...` 规范化为 `rtsp://...:8554/...`
6. 如果服务端返回 `0.0.0.0``127.0.0.1``localhost`,地面端必须替换为发现到的服务端 IP。
7. start_stream 成功返回后,认为服务端 RTSP 链路已经建立DroneScrewCtrlApp 固定多次打开本地 RTSP puller默认最多 5 次、间隔 500ms每次 open/read 超时按 5s 处理。成功标准不是 puller `Start()` 返回,而是收到并解码出第一帧 RTSP 图像;探测参数为 `probesize=262144``analyzeduration=500000us``fflags=nobuffer``max_delay=0``reorder_queue_size=0`
8. 本地 RTSP puller 多次启动或首帧等待全部失败时,只提示“服务端已开流但本地拉流未启动”,不能自动发送 `stop_stream`;服务端 LiveStream 状态必须保持运行,便于用户用 VLC/ffplay 或网络工具继续定位 8554 拉流问题。
低延迟约束:
- 服务端 RTMP/FLV muxer 使用 flush packets、零 interleave delay并且单视频流直接 `av_write_frame`,避免 muxer 为多流交织排序引入等待。
- 服务端每个 IDR 内嵌 SPS/PPSGOP 约 0.5s,降低 VLC/DroneScrewCtrlApp 中途接入时等待关键帧的时间。
- 地面端点击“开始实时显示”后必须立即弹出“正在拉流,请稍候...”提示框,同时禁用开始/检测按钮;`StartLiveStream()` 返回后关闭提示框,并按结果切换 UI 状态。
- 地面端收到第一帧 RTSP 后显示“RTSP 已出图”,用于区分“服务端已开流”和“画面已经解码显示”两个阶段。
现场日志判定:
- `FFMediaPusher: init done (...)` 表示编码器和封装器初始化成功。
- `[RTMP] pusher init ok ... push=rtmp://127.0.0.1:1935/live/dronescrew pull=rtsp://<板子IP>:8554/live/dronescrew` 表示内部推流地址和外部拉流地址已经拆清。
- `FFMediaPusher: connected to mediamtx, header written` 表示服务端已经连上 mediamtxRTMP 头已写入。
- `[LIVE] started ... url=rtsp://<板子IP>:8554/live/dronescrew` 表示 LiveStream 状态已启动。
- `start_stream` 返回 `ok=true``rawImagePublish=false` 是正确状态,距离检测模式显示走 RTSP不走 raw。
- start_stream 成功返回后如果地面端多次打开 RTSP 或等待首帧仍失败,应按真实错误处理,不自动发送 `stop_stream` 关闭服务端 LiveStream优先检查拉流 URL、mediamtx 和 8554 端口。
- 同尺寸推流时服务端直接拷贝 Mono8 到 NV12 Y 平面,不调用 RGA只有输入输出尺寸不一致时才尝试 RGA 缩放,失败后回退 CPU 缩放继续推流。
VLC 或地面端提示“输入无法被打开”时,优先检查:
1. 拉流 URL 是否为 `rtsp://<板子IP>:8554/live/dronescrew`,不能是 `rtsp://<板子IP>:1935/...`
2. mediamtx 服务是否运行,且 `rtspAddress: :8554``rtmpAddress: :1935` 是否被监听。
3. 服务端是否打印 `connected to mediamtx, header written`
4. 服务端是否已有相机帧进入 `pushRtspFrame`,日志中的 `rtsp_push` 是否增长、`rtsp_fail` 是否增长。
5. 网络侧是否允许地面端访问板卡 8554 端口。
## 4. 控制命令
核心命令:
- open按 machineCode 打开指定服务端并返回服务信息。
- get_info读取服务端运行状态、相机参数、算法参数和端口信息。
- start_stream进入距离检测模式开启 decimation 4x4 下采样、RTSP 推流和 result 发布。
- stop_stream退出距离检测模式停止推流和距离检测。
- start进入精准螺栓检测模式关闭 binning 和 decimation开启 raw/result 发布。
- stop退出精准螺栓检测模式。
- single执行单次精准检测。
- set_detect_mode设置精准检测模式下 raw 图像传输方式,支持 mono/binocular。
- set_exposure / set_gain下发相机曝光和增益。
- set_algo_params下发算法参数。
- swap_cameras交换左右相机角色。
## 5. 结果数据
检测结果由服务端通过 topic=result 发布,地面端由 WDRemoteReceiver 解析为 WDRemoteDetectionFrame。
主要字段:
- frameId帧号。
- timestampUs时间戳。
- imageWidth / imageHeight检测坐标对应的图像尺寸。
- success算法是否成功。
- errorCode错误码或算法拒绝原因。
- message详细消息。
- boxes检测框列表。
- distances距离结果列表协议单位为 mm距离检测 UI 显示时换算为 m精准螺杆/螺栓相关尺寸和坐标保持原图坐标语义。
距离检测模式和精准检测模式都应发布 result。区别在于图像显示来源不同距离检测模式显示 RTSP精准检测模式显示 raw。
## 6. 原始图像数据
raw 图像使用 topic=raw 发布,主要服务于精准检测模式。
当前协议:
- payload = WDRemoteBinocularRawImageHeader + leftData + rightData。
- magic 为 BIWI。
- 支持 raw、png、mjpeg、zlib 压缩标识。
- 精准检测双图 raw 使用 zlib 无损压缩左右图同时发送zlib 失败时回退 raw。
- 精准检测单图 raw 使用固定有损压缩比例Mono8 左图先按 `1/4` 缩放,再用 MJPEG `quality=25` 编码;不按运行时 payload 动态计算带宽,不因为带宽丢 raw 帧。
- 单图 raw 的 result 仍使用算法原始图像坐标,服务端发布 result 前把 `imageWidth/imageHeight` 固定为算法输入左图尺寸,地面端按显示图尺寸做比例叠框。
- MJPEG 编码失败时可回退 zlib/raw保证图像链路不断。
- detectMode=mono 时 right 字段为空,仅传 left。
## 7. 组件职责边界
### DroneScrewServer
负责:
- 相机连接、左右角色、曝光/增益、binning/decimation、采集频率。
- 两种 pipeline 切换DetectDistance 和 Detect。
- 实时视频链路RTMP publish 到本机 mediamtx并向地面端发布 RTSP pull URL。
- ZMQ control/result/raw 服务。
- UDP discovery。
- 算法参数加载和更新。
不负责:
- 地面端 UI 状态。
- 用户交互流程。
### WDRemoteReceiver
负责:
- 搜索和连接服务端。
- 封装控制命令。
- 订阅 result。
- 订阅 raw。
- 解析服务端 JSON 和 raw payload。
- 通过回调把数据交给业务层。
不负责:
- UI 显示。
- 算法业务判断。
- 画框叠加。
### DroneScrewCtrlApp
负责:
- 用户操作入口。
- 服务端连接状态展示。
- 距离检测模式RTSP 画面 + result 距离结果展示。
- 精准检测模式raw 图像 + result 检测框展示。
- 曝光、增益、算法参数配置。
- 单次检测测试。
不负责:
- 直接操作相机。
- 直接调用算法。
- 解析底层 ZMQ 协议细节。
## 8. 推荐状态流
### 8.1 地面端启动
1. 创建 WDRemoteReceiver。
2. 注册 event/result/raw 回调。
3. UDP 搜索服务端。
4. 通过 machineCode open。
5. get_info 更新 UI 参数。
### 8.2 进入距离检测模式
1. 地面端停止精准检测模式相关 raw 订阅。
2. 地面端保持或启动 result 订阅。
3. 地面端发送 start_stream。
4. 服务端开启 decimation 4x4 下采样采集。
5. 服务端启动 RTSP 推流。
6. 服务端持续执行 DetectDistance。
7. 地面端拉 RTSP 显示画面。
8. 地面端接收 result 显示距离检测结果。
### 8.3 进入精准螺栓检测模式
1. 地面端停止 RTSP 拉流。
2. 地面端发送 stop_stream。
3. 地面端设置 detectMode默认 mono。
4. 地面端启动 result/raw 订阅。
5. 地面端发送 start。
6. 服务端关闭 binning 和 decimation停止 RTSP 推流。
7. 服务端持续执行 Detect。
8. 服务端发布 raw/result。
9. 地面端用 raw 图像叠加 result 检测框。
### 8.4 停止
距离检测模式停止:
- 地面端发送 stop_stream。
- 服务端停止 RTSP 推流和距离检测。
精准检测模式停止:
- 地面端发送 stop。
- 服务端停止精准检测线程。
- 地面端停止 raw/result 订阅。
全部停止:
- 地面端释放 RTSP puller。
- 发送 stop。
- 发送 stop_stream。
## 9. 实现约束
- 两种模式互斥,不能同时启动 RTSP 距离检测和 raw 精准检测。
- 服务端算法始终使用双目输入。
- detectMode=mono 只减少地面端 raw 图像传输量。
- 距离检测模式必须订阅 result否则只能看到画面看不到距离检测结果。
- 精准检测模式依赖 raw 图像显示,不依赖 RTSP。
- 服务端开始检测后应持续处理最新有效帧;相机不同步时应使用最新缓存帧继续推进,不能因为 ready 标志被清空而停住。
## 10. 状态机约束
### 10.1 服务端状态
服务端只允许三种外部可见状态:
| 状态 | RTSP | raw PUB | result PUB | 算法 pipeline | 相机降采样 |
| --- | --- | --- | --- | --- | --- |
| Idle | 关闭 | 关闭 | 无业务结果 | 无 | 精准默认配置binning=1x1, decimation=1x1 |
| LiveStream | 开启 | 关闭 | 持续发布 | DetectDistance | binning=1x1, decimation=4x4 |
| Detection | 关闭 | 开启 | 持续发布 | Detect | binning=1x1, decimation=1x1 |
合法转换:
- Idle -> LiveStream收到 start_stream。
- Idle -> Detection收到 start。
- LiveStream -> Idle收到 stop_stream。
- Detection -> Idle收到 stop。
- LiveStream -> Detection必须先 stop_stream 成功,再 start 成功。
- Detection -> LiveStream必须先 stop 成功,再 start_stream 成功。
非法或无效转换:
- LiveStream 状态下收到 start应返回模式冲突或由调用方先 stop_stream。
- Detection 状态下收到 start_stream应返回模式冲突或由调用方先 stop。
- LiveStream 状态下收到 stop 不应关闭距离检测结果链路。
- Detection 状态下收到 stop_stream 不应关闭精准检测线程。
### 10.2 WDRemoteReceiver 本地状态
WDRemoteReceiver 使用 `Idle / LiveStream / Detection` 记录最后一次已确认的远端模式:
| 本地状态 | result 订阅 | raw 订阅 | 地面端图像来源 |
| --- | --- | --- | --- |
| Idle | 关闭 | 关闭 | 无 |
| LiveStream | 开启 | 关闭 | RTSP puller |
| Detection | 开启 | 开启 | ZMQ raw |
状态推进规则:
- 只有控制命令返回成功后才更新本地状态。
- 停旧模式失败时保留旧状态,不能提前置为 Idle。
- 旧模式已确认停止,但新模式启动或订阅失败时,必须清理已打开订阅并进入 Idle。
- StopWork 只在停止当前活跃模式成功时关闭订阅并进入 Idle停止非当前模式不能破坏当前模式的订阅。
- Disconnect 必须关闭 result/raw 订阅并进入 Idle。