GrabBag/App/DroneScrewbolt/Doc/ModbusTCP_Protocol.md

142 lines
8.2 KiB
Markdown
Raw Normal View History

2026-06-26 17:55:15 +08:00
# 无人机螺杆检测 — ModbusTCP 协议(板二 ↔ 外部 PLC / 上位机)
| 版本 | 日期 | 说明 |
|------|------------|------|
| V1.0 | 2026-05-22 | 初版 |
## 一、协议概览
无人机螺杆双板系统的两板之间使用 **ZeroMQ**(控制 REQ-REP / 结果 PUB-SUB与车间侧的 PLC、上位机通信使用 **ModbusTCP**
ModbusTCP 通讯主要发生在 **板二DroneScrewCtrl****外部控制器** 之间:
```
┌──────────┐ Modbus TCP ┌──────────┐ ZMQ ┌──────────┐
│ PLC/HMI │ ────────────> │ Ctrl │ ────────> │ Server │
│ 上位机 │ <──────────── │ (板二) │ <──────── │ (板一) │
└──────────┘ 状态/结果 └──────────┘ 结果上传 └──────────┘
```
- **TCP 端口**`502`Modbus 默认)
- **Slave ID**`1`
- **字节序**:寄存器内大端(按 Modbus 标准),跨寄存器多字数据低字在前(与项目其它 App 保持一致,可通过配置 `byteOrder` 切换)
- **触发模型**:上位机写入控制寄存器触发 → Ctrl 转发到 Server → Server 检测结果反馈到 Ctrl → Ctrl 写入到上位机可读取的输入/保持寄存器
## 二、地址映射
寄存器分为 4 个区段:
| 区段 | 类型 | 地址范围 | 用途 |
|---------------|-------------------|-------------------|---------------------------------|
| 控制命令 | Holding (FC06/16) | `40001 ~ 40020` | 由上位机写入,触发动作 |
| 实时状态 | Input (FC04) | `30001 ~ 30030` | 由 Ctrl 写出,上位机读取系统状态 |
| 检测结果 | Holding (FC03/04) | `40101 ~ 40200` | 当前一帧检测结果 |
| 参数配置 | Holding (FC03/06) | `40301 ~ 40360` | 算法 / 相机参数透传 |
> Modbus 寄存器使用 1 基地址展示PDU 实际为 0 基)。
### 2.1 控制命令(上位机写)
| 寄存器 | 名称 | 取值 |
|--------|-------------------|-----------------------------------------------------------------------------------------------|
| 40001 | `CMD` | `1`=启动持续检测 / `2`=停止持续 / `3`=单次检测 / `10`=请求下一条结果 / `99`=心跳 |
| 40002 | `CMD_ID` | 命令序列号(防止重复触发) |
| 40003 | `TARGET` | `0`=自动 / `1..N`=指定相机 |
| 40004 | `PARAM_BLOCK` | 1=触发同步参数下发;写入后 Ctrl 读取 40301~40360 一次性更新 |
| 40005 | `RESERVED` | 保留 |
### 2.2 实时状态(上位机读 / Ctrl 写)
| 寄存器 | 名称 | 取值 |
|--------|---------------------|-----------------------------------------------------------------------------------------------|
| 30001 | `WORK_STATUS` | `0`=Idle / `1`=Connecting / `2`=Streaming / `3`=Detecting / `9`=Error |
| 30002 | `SERVER_CONNECTED` | `0`=未连接 / `1`=已连接 |
| 30003 | `CAMERA_CONNECTED` | `0`=Server 端相机断开 / `1`=已连接 |
| 30004 | `ERROR_CODE` | 最近错误码0=无错误) |
| 30005 | `LAST_CMD_ACK` | 最近一次完成的 CMD_ID |
| 30006~30009 | `RTSP_FRAME_FPS`,`STREAM_BPS_KB`,`LATENCY_MS`,`CPU_LOAD` | 监控用 |
| 30010~30015 | `VERSION_*` | 软件 / 算法版本 |
### 2.3 检测结果(写入 1 帧后再写下一帧)
寄存器 40101 ~ 40200 共 100 个寄存器,按以下结构组织:
| 偏移 | 名称 | 说明 |
|---------|-------------------|------|
| +0 | `FRAME_ID_HI` | 帧号高 16 位 |
| +1 | `FRAME_ID_LO` | 帧号低 16 位 |
| +2~+5 | `TIMESTAMP[4]` | 微秒时间戳64 位) |
| +6 | `IMG_WIDTH` | 图像宽 |
| +7 | `IMG_HEIGHT` | 图像高 |
| +8 | `BOX_COUNT` | 检测目标数量 (`N`,最多 18) |
| +9 | `RESULT_INDEX` | 写 `0..N-1` 表示当前发送的第几个目标(配合 40001=`10` 翻页) |
| +10 | `SUCCESS` | `1`=成功 / `0`=失败 |
| +11~+15 | 保留 | — |
| +16~+20 | `BOX[0]` | `cls,score×100,x,y,w,h` 5 个字score×100 为整数百分比) |
| +21~+25 | `BOX[1]` | … |
| … | … | 最多 18 个 box占用 16~105 偏移),余量保留 |
### 2.4 参数配置(写入后通过 ZMQ 透传到 Server
| 寄存器 | 名称 | 说明 |
|--------|-----------------------|------|
| 40301 | `SCORE_TH ×1000` | 置信度阈值(千分位定点) |
| 40302 | `NMS_TH ×1000` | NMS 阈值 |
| 40303 | `INPUT_WIDTH` | 模型输入宽 |
| 40304 | `INPUT_HEIGHT` | 模型输入高 |
| 40305 | `MODEL_TYPE` | 0=YOLO, 1=自定义 |
| 40310 | `EXPOSURE_TIME_US_HI` | 曝光时间高 16 位μs |
| 40311 | `EXPOSURE_TIME_US_LO` | 曝光时间低 16 位 |
| 40312 | `GAIN ×100` | 增益(百分位定点) |
| 40320 | `RTSP_REQUEST` | 0=保持当前 RTSP 配置 / 1=请求重新发布 RTSP URL |
| 40330~40359 | `MODEL_PATH[]` | 模型路径 ASCII每寄存器 2 字符,截止 0x00 |
## 三、典型时序
### 3.1 启动一次单帧检测
```
PLC Ctrl Server (ZMQ)
│ │ │
│── 40001 := 3 ─────────▶ │ │
│ 40002 := SEQ │── ZMQ REQ {"cmd":"single"} ─▶│
│ │◀─── REP {"ok":true}──────────│
│ │ │
│ │◀─── PUB topic="result", json │
│ │ 写 40101..40200 │
│◀── 30005 := SEQ ─────────│ │
│ 30001 := Detecting │ │
│── FC03(40101..40200) ──▶ │ (读结果) │
```
### 3.2 启动持续检测
`40001=1 → Ctrl 转发 start → Server 持续 PUB → Ctrl 每帧覆盖写入 40101~40200并将 FRAME_ID 写到 30005 之后让 PLC 轮询`
### 3.3 多目标翻页
如果一次检测有 `BOX_COUNT > 18`PLC 反复写 `40001=10` 触发下一页结果Ctrl 在内部维护索引)。
## 四、错误码ERROR_CODE
| 码值 | 含义 |
|--------|------|
| 0 | 正常 |
| 1001 | Server 离线 |
| 1002 | RTSP 拉流断开 |
| 1003 | ZMQ 控制超时 |
| 2001 | 相机端连接失败Server |
| 2002 | 相机取流超时 |
| 3001 | 算法异常 |
| 9999 | 未知错误 |
## 五、实现入口
板二的 ModbusTCP 服务通过现有 `Module/ModbusTCPServer` 提供:
- 启动:`MainWindow``InitApp` 中调用 `IVrModbusTCPServer::CreateObject``Init(502, slaveId=1)`
- 寄存器更新:`DroneScrewCtrlPresenter::onResultReceived` 收到 ZMQ 结果后,调用 `WriteRegisters(40101, ...)`
- 命令解析:在 `OnModbusWriteCallback(startAddr, data, count)` 中识别 40001~40020 区段并触发对应 ZMQ 命令
> 真实接入时根据上位机厂商习惯调整字节序(`byteOrder` 配置项),结构上无需改变。