GrabBag/App/ParkingSpaceGuide/Doc/详细设计.md

445 lines
19 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.

# 停机引导系统详细设计
## 1. 目标
项目:`App/ParkingSpaceGuide`
设备:
- 雷达:`Device/RsLidarDevice`
- 2D 相机:`Device/MvsDevice`
- LED 屏:`Device/LedDisplayDevice`,ModbusTCP
- 组播:`Nets/UDPClient`
功能点:
1. 标定
- 地面标定、停止线标定均调用算法接口
- 应用保存算法返回结果,失败时显示原因
2. 雷达
- 正常工作主检测设备;
- 低频找飞机,发现飞机后 10fps 检测。
3. 2D 相机
- 用于飞机目标检测,以及飞机停稳后的轮挡区域人员检测
4. 输出
- 检测结果更新 UI 结果列表、LED 显示、组播 JSON。
5. 日志
- 页面操作日志即时显示,不入库。
- 引导会话、状态采样和操作事件写入本机 MariaDB;库连不上时引导继续。
## 2. 输出结果
| 输出项 | 字段 | 单位 | 说明 |
| --- | --- | --- | --- |
| 选择机型 | `expectedModelType` | - | 操作员点击开始前选择的期望机型。 |
| 机型 | `modelType` | - | 算法识别结果;未识别成功时为“未知”。 |
| 机型匹配 | `modelMatched` | - | 选择名称包含 A320 且识别为 A320,或包含 B737 且识别为 B737 时为 `true`。 |
| 细分机型校验能力 | `modelVerificationSupported` | - | 三分类模型完成识别时为 `true`。 |
| 轮挡区域人员 | `personInChockRegion` | - | 裁剪后的轮挡 ROI 内是否检测到人员。 |
| 轮挡确认 | `chocksConfirmed` | - | 连续有效检测达到配置次数。 |
| 到停止线距离 | `distanceToStop` | mm | 未到线为正,到线为 0,越线为负。 |
| 机身偏转角 | `bodyYawAngle` | degree | 算法输出。 |
| 横向偏移 | `lateralOffset` | mm | 算法输出。 |
| 停机位 | `parkId` | - | 业务配置参数,不属于标定。 |
| 目标编号 | `targetId` | - | 业务配置或上位系统分配。 |
| 异常状态 | `hasException` | bool | 是否有异常;对应组播协议中的异常情况。 |
| 引导状态 | `guideState` | - | WAIT、TRACKING、SLOW、STOP、OK、TOOFAR、ERROR 等。 |
| 置信度 | `confidence` | - | 算法输出。 |
## 3. 坐标定义
- X 轴:横向,向右为正。
- Y 轴:垂向,向下为正。
- Z 轴:纵向,飞机运行方向为负方向。
- 引导中心线:由停止线标定结果定义,不固定为 `X=0`。
- 停止线:由停止线标定结果定义。
应用不计算坐标关系,只保存标定结果并传给算法接口。
## 4. 模块职责
| 模块 | 职责 |
| --- | --- |
| `ParkingSpaceGuidePresenter` | 设备初始化、调用算法接口、分发结果到 UI/LED/组播。 |
| `DetectPresenter` | 算法接口调用入口。 |
| `ConfigManager` | 加载、保存、页面修改配置。 |
| `RsLidarDevice` | 采集雷达点云。 |
| `MvsDevice` | 搜索并采集 2D 平面相机图像。 |
| `LedDisplayDevice` | 输出 LED 显示结果。 |
| `UDPClient` | 组播发送 JSON 检测结果。 |
| `GuideRecordStore` | 将引导会话、状态采样和操作事件写入 MariaDB。 |
数据流:
```text
RsLidarDevice -> 算法检测接口 -> 检测结果
MvsDevice -> 算法机型识别接口 -> modelType
检测结果 -> UI / LED / 组播 / HTTP / 日志
操作与会话 -> GuideRecordStore -> MariaDB
```
## 5. 标定模式
原则:
- 标定算法由算法模块提供。
- 应用只负责采集数据、调用接口、显示结果、保存结果。
- `parkId` 是业务配置,不参与标定。
- 接口失败时只显示失败原因,不覆盖旧结果。
### 5.1 标定流程
```mermaid
%%{init: {"flowchart": {"curve": "linear"}} }%%
flowchart TD
A([进入标定]) --> B{设备状态}
B -- 异常 --> C[显示原因]
B -- 正常 --> E[加载地面标定参数]
E --> F[采集雷达点云]
F --> G[调用 CalibrateGround]
G --> H{地面标定结果}
H -- 成功 --> I[保存地面标定结果]
H -- 失败 --> J[显示失败原因]
```
### 5.2 地面标定
输入:
- 地面标定参数,至少包含采集帧数,默认建议 `N >= 10`。
- 多帧雷达点云。
输出:
- `groundCalibrationResult`
- `calibrationTime`
### 5.3 停机几何配置
当前版本直接配置调平坐标系中的停机点、引导线远点、引导范围、引导线过滤范围及机鼻到前轮距离,不保留旧中心线/停机线兼容结构。
## 6. 正常工作模式
### 6.1 工作流程
```mermaid
%%{init: {"flowchart": {"curve": "linear"}} }%%
flowchart TD
A([启动]) --> B{设备和标定检查}
B -- 异常 --> C[输出 ERROR]
B -- 缺标定 --> D[提示补做标定]
B -- 正常 --> E[进入待机]
E --> F[操作员可从配置机型表选择或不选机型]
F --> G[点击开始]
G --> G1{自检雷达/相机/存储/网络}
G1 -- 失败 --> C
G1 -- 通过 --> H[发布系统已激活并锁定参数控件]
H --> I[按帧采集雷达点云]
I --> J[调用 planeLocalization 和引导状态计算]
J --> K{检测结果}
K -- 失败 --> L[显示原因并输出错误状态]
L --> I
K -- 成功 --> M{进入 25m 且尚未完成机型验证}
M -- 是 --> N[提交异步采图、ROI 裁剪和飞机检测任务]
M -- 否 --> O[使用点云引导结果]
N --> O
N -. 任务完成 .-> P[合并机型结果并更新 UI / LED / UDP / HTTP]
O --> P
P --> Q{飞机到位并稳定停止}
Q -- 否 --> I
Q -- 是 --> R[保持 STOP,满 okHoldMs 后显示 OK,并周期检测轮挡 ROI 人员]
R --> T{连续检测达到稳定次数}
T -- 否 --> I
T -- 是 --> U[发布 21 / CHOCK ON,写入人员轮挡时间]
U --> S[停止检测并进入休眠]
S --> E
```
### 6.2 雷达
- 主检测设备。
- 点击开始即可进入检测;机型可选,未选择时以实际识别结果继续流程。
- 点击开始后由点云实测距离决定 WAIT、START、CAPTURE 和后续引导状态,不使用虚拟距离。
- 已有有效测量时,若当前帧的距离变化或横向偏移变化任一项超过对应配置阈值,则判为误检并忽略,状态机继续使用上一有效测量。
- 输出距离、偏移、偏角、异常状态、引导状态等结果。
### 6.3 2D 相机
- 使用 AAPGS 目标检测模型识别飞机和人员。
- 是否触发由算法检测接口返回,默认在距离不大于 25m 时最多验证两次。
- 飞机检测区域由 `roiX`、`roiY`、`roiWidth`、`roiHeight` 配置为归一化 ROI;相机原图先按 ROI 裁剪,`RecognizeModel2D` 只接收裁剪图像。
- 常规雷达、机型识别和人员检测结果均显示相机全图;机型模型只接收飞机 ROI,人员模型只接收轮挡 ROI,人员检测框转换回原图坐标后叠加到全图。
- 飞机采图、ROI 裁剪和模型推理在独立任务中执行,不占用雷达点云检测线程。任务未完成时的新机型识别触发只跳过本次提交,当前雷达帧仍正常完成定位和状态更新;任务完成后由检测循环合并结果。
- 操作员选择值保存为本次会话的 `expectedModelType`,不作为检测结果显示。
- 当前三分类模型返回 `A320`、`B737` 或“其他”。选择名称包含 `A320` 且检测为 `A320` 算匹配,包含 `B737` 且检测为 `B737` 同样算匹配。A321、C919 等其他配置机型不校验。可选机型列表由 `config.xml` 的 `AircraftModels` 配置。
- 达到最大次数仍不一致时输出 `STOP+IDFAIL`,并显示算法返回原因。
- 飞机稳定停止后保持 `STOP`,满 `okHoldMs` 后发布 `OK`;按配置周期裁剪轮挡 ROI 并仅对裁剪图检测人员;ROI 内连续检测到人员达到稳定次数后发布 `CHOCK ON`,同时记录人员确认时间。人工上/下轮挡时间单独入库,会话结束后仍可补记到最后一次会话。
### 6.4 输出
UI 结果列表字段:
- 时间
- `parkId`
- `targetId`
- `expectedModelType`
- `modelType`
- `modelMatched`
- `distanceToStop`
- `lateralOffset`
- `bodyYawAngle`
- 速度
- `guideState`
- `confidence`
更新规则:
- 当前目标按 `parkId + targetId` 更新。
- 不做每帧无限追加。
LED 按 0720 式样输出:
- 显示状态:1、2、5、6、7、8、10、15、16、17、20、21、22。
- 清屏状态:3、4、9、11、12、13、14、18、19、23、24。
- 白色行只清空 LED 动态区,不影响 UI、UDP 和 HTTP 的完整状态数据。
### 6.5 急停输入
- 板卡接口使用 `/sys/external_gpio/jwsioc_inout_gpio3` 配置方向,启动或故障重连时写入 `0` 设置为输入。
- 周期读取 `/sys/external_gpio/jwsioc_gpio3`,只接受 `0` 或 `1`。
- 急停采用常闭安全回路:正常时 I/O3 与 GND 闭合,读取 `0`;按下急停或线路断开时回路断开,读取 `1` 并锁存急停。
- 默认轮询周期为 10ms、消抖时间为 50ms。方向配置失败、电平文件不可读或内容非法时按急停输入不可用处理,停止检测并禁止重新开始。
- START 需要已点击开始且实测距离不大于 100m;CAPTURE 为 25m 至 80m;SLOW 为 15m 内且接近速度不小于 2m/s;STOP 容差为正负 0.1m;TOOFAR 为越线不小于 0.5m。
组播:
- 使用 JSON。
- 端口:`8800`。
- 雷达进入 10fps 后按检测结果输出,可配置限频。
- 检测失败或无结果也发送状态包。
### 6.6 日志与记录
日志分两层:页面操作日志只显示;引导记录写入 MariaDB,供本机查询和 View 历史回放。库连不上时跳过入库,引导、LED 和远程显示继续。
#### 页面操作日志
`DetectLogHelper` 显示在主界面 `detect_log`,不写入数据库。
| 字段 | 说明 |
| --- | --- |
| 时间 | 本机本地时间,格式 `hh:mm:ss` |
| 消息 | `NotifyStatus` 及页面操作提示原文 |
| 重复计数 | 连续相同消息合并为 `(xN)` |
来源包括:初始化、开始/停止、自检、急停、维护模式、轮挡、参数页开关、工作状态变化。点击开始时清空本次页面日志。
#### MariaDB 引导记录
默认库名 `parking_guide`。配置节点 `Database`:`enabled`、`host`、`port`、`user`、`name`、`retainDays`(默认 30 天)、`sampleIntervalMs`(默认 200 ms)。启动时按 `retainDays` 清理过期会话、明细和事件。
过程还原用 `guide_session` 和 `guide_detail`。`guide_event` 记录操作事件。三张表用 `sessionUuid` 关联;删除会话时级联删除该次引导的明细和事件。无会话事件(如开机自检)`sessionUuid` 为空,过期时按时间单独清理。表间关系、外键和查询示例以《停机引导对接协议》第 11 节为准。`guide_detail` 字段与协议 `ParkingSpaceGuideResult` 一一对应;`status`、`selfCheck` 拆成 `status_`、`selfCheck_` 前缀列。`sessionUuid` 只作关联,还原时不放入结果包。回放按 `timestamp` 升序读列,拼回与组播/HTTP 相同的结果对象。`guideStateCode` 变化时立即写一条,其余按 `sampleIntervalMs`(默认 200 ms)采样。`timestamp` 为 Unix 毫秒;轮挡时间为设备本地 `yyyy-MM-dd HH:mm:ss`,未记录为空。
**`guide_session` 引导会话**
一次点击开始到停止(或急停/自检失败结束)对应一条会话。结束时回写检测机型、最终状态和错误信息。
| 字段 | 说明 |
| --- | --- |
| sessionUuid | 会话标识,仅库内/回放使用 |
| parkId | 停机位 |
| targetId | 目标编号 |
| expectedModelType | 操作员选择机型 |
| modelType | 检测机型,会话结束时回写 |
| modelMatched | 选择机型与检测机型是否匹配 |
| startTime | 开始时间 |
| endTime | 结束时间;进行中为空 |
| guideStateCode | 结束时的引导状态序号 |
| hasException | 结束时是否异常 |
| errorCode | 结束时错误码,与协议相同 |
| message | 结束时说明 |
| personChockTime | 人员轮挡确认时间 |
| chockOnTime | 人工上轮挡时间 |
| chockOffTime | 人工下轮挡时间 |
**`guide_detail` 引导明细**
一次会话的过程数据。字段与协议一一对应。
| 字段 | 说明 |
| --- | --- |
| sessionUuid | 所属会话,仅库内关联,还原时不放入结果包 |
| protocol | 固定 `ParkingSpaceGuideResult` |
| version | 协议版本,当前 `1.1` |
| success | 本条是否有效结果且 errorCode=0 |
| hasResult | 本条是否包含有效引导结果 |
| targetId | 目标编号 |
| parkId | 停机位 |
| expectedModelType | 操作员选择机型 |
| modelType | 检测机型 |
| modelMatched | 选择机型与检测机型是否匹配 |
| personChockTime | 人员轮挡确认时间 |
| chockOnTime | 人工上轮挡时间 |
| chockOffTime | 人工下轮挡时间 |
| status_workMode | 工作模式 |
| status_activated | 是否已激活 |
| status_camera_name | 平面相机名称 |
| status_camera_connected | 平面相机是否在线 |
| status_lidar_name | 雷达名称 |
| status_lidar_connected | 雷达是否在线 |
| status_emergencyStop_name | 急停名称 |
| status_emergencyStop_enabled | 是否启用急停 |
| status_emergencyStop_available | 急停输入是否可用 |
| status_emergencyStop_active | 急停是否正在触发 |
| status_emergencyStop_latched | 急停是否已锁存 |
| selfCheck_running | 是否正在自检 |
| selfCheck_ok | 自检是否通过 |
| selfCheck_lidarOk | 雷达自检 |
| selfCheck_cameraOk | 相机自检 |
| selfCheck_storageOk | 存储自检 |
| selfCheck_networkOk | 网络自检 |
| selfCheck_errorCode | 自检错误码 |
| selfCheck_message | 自检说明 |
| guideStateCode | 引导状态序号 |
| distanceToStop | 到停止线距离,毫米 |
| bodyYawAngle | 机身偏转角,度 |
| lateralOffset | 横向偏移,毫米 |
| aircraftSpeed | 接近速度,米/秒 |
| hasException | 本条是否异常 |
| guideText | 引导文字 |
| message | 说明或异常原因 |
| errorCode | 错误码,与协议相同 |
| timestamp | 本条时间,Unix 毫秒 |
**`guide_event` 操作事件**
操作员动作和关键系统事件,用 `sessionUuid` 关联到 `guide_session`。无会话时 `sessionUuid` 为空(如开机自检)。
| 字段 | 说明 |
| --- | --- |
| sessionUuid | 所属会话,与 `guide_session.sessionUuid` 相同;无会话时为空 |
| timestamp | 事件时间,Unix 毫秒 |
| eventType | 事件类型,见下表 |
| message | 说明文字 |
| payload | 附加 JSON;自检事件为 `selfCheck` 对象,其余通常为空 |
| eventType | 写入时机 | payload |
| --- | --- | --- |
| boot_self_check | 应用初始化完成时的开机自检 | 自检结果 |
| self_check | 点击开始后的启动自检 | 自检结果 |
| session_begin | 自检通过,引导会话开始 | 空 |
| session_end | 停止、急停或流程结束 | 空 |
| person_chock | 轮挡区域人员首次确认 | 空 |
| chock_on | 人工上轮挡 | 空 |
| chock_off | 人工下轮挡 | 空 |
| maintenance | 进入或退出维护模式 | 空 |
View 通过 `list_sessions` / `get_session_samples` 读取会话和明细做历史回放。回放按明细协议列拼回 `ParkingSpaceGuideResult`,不含点云和图像。
## 7. 配置
```xml
<Business parkId="P01"
targetId="T001"/>
<AlgorithmParams>
<PlaneParkingParam parkingPointX="0" parkingPointY="0" parkingPointZ="0"
guideLinePointX="0" guideLinePointY="20000" guideLinePointZ="0"/>
<PlaneGroundCalibrationParam planeHeight="-1">...</PlaneGroundCalibrationParam>
<PlaneTreeGrowParam yDeviationMax="300" zDeviationMax="300"/>
<GuideDecisionParam lateralTolerance="100" angleTolerance="5"/>
<ParkingProcessParam dockingStartDistance="100000"
captureStartDistance="80000"
approachStartDistance="25000"
slowDistance="15000"
stopDistanceTolerance="100"
overshootDistance="500"
maxApproachSpeed="2000"
distanceChangeThreshold="10000"
lateralOffsetChangeThreshold="3000"/>
<ModelRecognitionParam modelVerifyDistance="25000"
roiX="0" roiY="0"
roiWidth="1" roiHeight="1"
confidenceThreshold="0.6"
maxRecognitionAttempts="2"/>
<PersonDetectionParam enabled="true"
roiX="0" roiY="0"
roiWidth="1" roiHeight="1"
confidenceThreshold="0.5"
stableFrames="3"
detectionIntervalMs="500"/>
</AlgorithmParams>
<WorkMode airplaneProbeIntervalMs="1000"
trackingFps="10"
uiUpdateIntervalMs="200"
udpOutputIntervalMs="100"/>
<UdpBroadcast enabled="false"
address="239.255.0.1"
port="8800"/>
<Database enabled="true" host="127.0.0.1" port="3306"
name="parking_guide" retainDays="30" sampleIntervalMs="200"/>
```
配置页面需要支持修改:
- `parkId`
- `targetId`
- 组播参数
- LED 参数
- 雷达参数
- 相机参数
- 标定参数
- 工作模式参数
- 数据库保留天数和采样间隔
## 8. 算法接口
应用调用单帧定位算法,并在其输出上实现多帧停机流程状态机。
| 接口 | 输入 | 输出 |
| --- | --- | --- |
| `CalibrateGround` | 雷达点云、地面标定参数 | 成功标志、地面标定结果、失败原因 |
| `DetectAirplanePresence` | 雷达点云、配置参数 | 是否有飞机、阻挡/遮挡状态、失败原因 |
| `wd_planeLocalization` | 二维扫描线、地面调平、停机几何、聚类生长参数 | 距离、横向偏差、航向角、机鼻位置、错误码 |
| `DetectParkingSpaceGuide` | 雷达点云、帧时间、算法参数、上一帧状态 | 检测结果、完整引导状态、下一帧状态、是否需要机型识别 |
| `RecognizeModel2D` | 按飞机 ROI 裁剪后的 2D 图像、检测上下文 | 机型、置信度、失败原因 |
## 9. 异常处理
| 异常 | 处理 |
| --- | --- |
| 雷达断开 | 停止检测,LED/组播输出错误状态。 |
| 相机断开 | 雷达检测继续,机型识别不可用。 |
| 急停按下或线路断开 | 锁存紧急停止,停止当前检测;恢复闭合后仍需重新点击开始。 |
| 急停 sysfs 不可用 | 按失效保护处理,停止检测并禁止启动。 |
| LED 断开 | 检测和组播继续,UI 提示。 |
| 组播初始化失败 | 检测和 LED 继续,UI/日志提示。 |
| 地面标定缺失 | 禁止进入正常检测。 |
| 停止线标定缺失 | 禁止输出距离和 STOP/TOOFAR。 |
| 算法接口失败 | 显示失败原因,输出错误状态。 |
| 启动自检失败 | 发布 22 ERROR,错误码 2201–2204(多项 2200),不启动引导。 |
| MariaDB 不可用 | 记录库跳过,引导、LED 和远程显示继续。 |
## 10. 验收
标定:
- 地面标定结果可保存和加载。
- 停止线标定结果可保存和加载。
- 标定失败显示原因,不覆盖旧结果。
正常工作:
- 初始化完成后保持待机,不自动开始算法检测。
- 操作员点击开始后按配置周期处理雷达点云;未选择机型时以实际识别结果完成流程。
- UI、LED、组播同步更新。
- 机型识别按算法触发。
- 25m 内按配置次数进行机型一致性验证,达到最大次数仍失败时进入 IDFAIL。
- START、CAPTURE、CENTER、SLOW、STOP、TOOFAR、IDFAIL、ERROR 等状态及 LED 清屏规则输出正确。
- 页面操作日志显示时间与消息;开始引导后会话、采样和操作事件写入 MariaDB。
- 库连不上时引导仍可继续,页面日志不受影响。