Files
FT546-WCS/docs/superpowers/specs/2026-07-30-wcs-dispatch-traffic-demo-design.md

259 lines
9.0 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.
# WCS 中心调度与交通管制 Demo 设计
## 1. 背景与目标
本设计依据 `01-P0-A现有链路稳固实施计划.md`,在 `FT546-WCS` 优化工作树根目录新增独立的 `javaTest` Maven 项目,用纯 Java 内存模型模拟 WCS 中心调度与交通管制。
Demo 的目标是:
1. 建立一个可运行的调度中心,模拟每周期任务准入、车辆分配、路径规划、交通管制、任务下发和完成。
2. 用真实 JUnit 5 测试覆盖关键调度规则,确保测试数量大于 0。
3. 固化当前 LEGACY 链路的重要语义,为后续从 `BaseSRgvThread` 提取可测试边界提供参考。
4. 输出可读的控制台事件,使开发人员能观察每个周期的决策原因和状态变化。
## 2. 范围与约束
### 2.1 范围内
- 独立 Maven 项目 `javaTest`。
- Java 8 源码兼容。
- JUnit 5 自动测试。
- 内存车辆快照、业务任务、调度队列、地图和事件记录。
- 每周期一次任务准入。
- 确定性车辆选择。
- 网格最短路径、路径占用和通道占用。
- 避让任务生成。
- 模拟协议下发与队列状态流转。
- 命令行 Demo 场景。
### 2.2 范围外
- 不修改生产 `BaseSRgvThread`、`PlcSrgvRead` 或数据库表。
- 不连接 SQL Server、PLC、WMS 或 Spring 容器。
- 不发送真实 PLC 指令。
- 不建立生产中央路权服务,不写交通运行表。
- 不启用 SHADOW 或 ACTIVE 模式。
- 不使用 `default02` 至 `default08` 保存新增交通状态。
- 不猜测 PLC 寄存器偏移或载货字段布局。
Demo 中的“调度中心”只协调内存任务、车辆与路径,不改变 P0-A 的 LEGACY 生产控制边界。
## 3. 方案选择
采用独立 Maven 项目,而不是加入现有 Reactor 或直接放入 `ruoyi-admin/src/test`。
理由:
- 可独立运行,不污染生产 Reactor 和依赖关系。
- 不需要 Spring、MyBatis、HslCommunication 或数据库。
- 能强制使用 JUnit 5 和现代 Surefire,避免现有工程“构建成功但测试数为 0”的假阳性。
- 后续可把验证成熟的纯领域服务迁移到生产模块。
## 4. 目录结构
```text
javaTest/
├── pom.xml
├── README.md
└── src/
├── main/java/com/ft546/wcs/demo/
│ ├── DemoApplication.java
│ ├── center/
│ ├── model/
│ ├── repository/
│ ├── traffic/
│ └── simulation/
└── test/java/com/ft546/wcs/demo/
```
包边界如下:
- `model`:不可变输入快照和明确的状态枚举。
- `center`:调度周期、任务准入和车辆选择。
- `traffic`:路径规划、资源占用与避让决策。
- `repository`:内存任务、队列和历史。
- `simulation`:场景构造、周期推进和事件输出。
## 5. 核心模型
### 5.1 车辆快照
`VehicleSnapshot` 至少包含:
- `vehicleId`
- `floor`
- `currentSite`
- `workMode`
- `status`
- `battery`
- `connected`
- `allowSend`
- `cargo`
快照不可变。车辆只有同时满足在线、自动模式 `workMode=5`、空闲 `status=1`、允许下发且电量大于 30 时才具备普通任务资格。
### 5.2 业务任务
`DispatchTask` 包含:
- `taskId`
- `type`
- `sourceSite`
- `targetSite`
- `floor`
- `priority`
- `state`
Demo 支持入库、出库和移库的统一调度输入,但不模拟真实 WMS 回调。
### 5.3 调度队列
`DispatchQueueEntry` 使用明确字段表达:
- `taskId`
- `vehicleId`
- `queueType`
- `startSite`
- `endSite`
- `priority`
- `issued`
- `executionStatus`
- `path`
状态语义与旧链路保持一致:
- 新建:`issued=0`、`executionStatus=1`
- 下发成功:`issued=1`、`executionStatus=3`
- 完成:`executionStatus=4`,随后归档并从活动队列删除
避让任务使用 `queueType=AVOIDANCE` 和优先级 9,不把新增交通状态塞入旧扩展字段。
## 6. 调度中心
`LegacyDispatchCenter.runCycle()` 是每个模拟周期的唯一入口,固定顺序为:
1. 冻结当轮车辆快照,并按 `vehicleId` 排序。
2. 调用一次 `QueueAdmissionService.createPendingQueues()`。
3. 对未分配业务任务调用 `VehicleAssignmentService.select()`。
4. 对每辆车处理已有队列。
5. 调用 `TrafficController.plan()` 获得路径、等待或避让决策。
6. 通过 `SimulatedProtocolAdapter` 模拟指令下发。
7. 根据车辆位置推进队列完成和历史归档。
无论车辆数是多少,每周期业务准入只能调用一次。
## 7. 确定性车辆选择
车辆选择采用稳定比较顺序:
1. 不符合资格的车辆排除,并记录排除原因。
2. 同楼层优先。
3. 绝对楼层差更小者优先。
4. 保留旧链路的 Y 距离优先、X 距离次优语义。
5. 全部相同时,`vehicleId` 字典序更小者优先。
站点编码必须能解析为坐标。编码无效时返回 `REJECT_INVALID_SITE`,不得按坐标 0 静默参与比较。
`VehicleAssignmentDecision` 必须包含被选车辆和可读的选择理由;没有可用车辆时返回明确的 HOLD 决策。
## 8. 交通管制
### 8.1 地图与路径
`GridMap` 保存可通行点及站点坐标。`GridPathPlanner` 使用确定性最短路径算法,只允许通过可通行节点。
每次规划前,`TrafficController` 从当前内存状态构建占用视图:
- 锁定其他车辆队列中从其当前位置开始的剩余路径。
- 锁定离线车辆当前位置。
- 锁定场景中声明不可用的提升机或障碍点。
占用视图只存在于当前模拟周期,不写数据库。
### 8.2 通道与路径冲突
如果目标通道存在同层阻挡车辆:
- 阻挡车辆没有活动队列时,为其生成高优先级避让任务。
- 当前业务任务返回 `HOLD_CHANNEL_BLOCKED`。
- 避让任务完成并删除后,下一周期重新规划。
如果路径被其他车辆占用但存在替代路线,则规划绕行;没有替代路线时返回 `HOLD_NO_PATH`。
同一阻挡车辆在已有避让队列时不得重复创建避让任务。
## 9. 协议模拟与状态流转
`SimulatedProtocolAdapter` 只记录命令,不进行 I/O。它支持成功和可注入失败两种结果:
- 成功时,队列更新为 `issued=1`、`executionStatus=3`。
- 失败时,队列保持未下发状态,并记录 `HOLD_PROTOCOL_FAILURE` 及失败原因。
- 同一队列已成功下发后不得重复发送。
模拟器把车辆移动到路径下一站。到达目标站后:
- 普通任务归档业务历史并删除活动队列。
- 避让任务只归档避让事件并删除活动队列。
- 删除队列后,其路径占用在下一周期自然释放。
## 10. 错误处理
Demo 使用决策结果表达预期异常,不使用空值表示失败:
- `HOLD_NO_ELIGIBLE_VEHICLE`
- `REJECT_INVALID_SITE`
- `HOLD_NO_PATH`
- `HOLD_CHANNEL_BLOCKED`
- `HOLD_PROTOCOL_FAILURE`
构造时拒绝重复任务号、重复车辆号和缺失地图站点。不可恢复的模型错误抛出 `IllegalArgumentException`;调度等待条件作为正常决策返回。
## 11. 模拟场景
`DemoApplication` 至少运行以下场景:
1. 三辆车、一个业务任务:证明每周期只准入一次,并稳定选出车辆。
2. 同层与跨层车辆竞争:证明同层、楼层差、Y/X 距离和车辆编号裁决。
3. 其他车辆剩余路径占用:证明绕行或等待。
4. 同通道阻挡:生成优先级 9 的避让任务,当前车等待。
5. 避让完成:删除避让队列,下一周期原任务重新规划并下发。
6. 无可达路径:返回 `HOLD_NO_PATH`,不抛异常。
7. 协议失败后重试:第一次保持未下发,下一周期成功进入执行中。
8. 到达目标:队列完成、归档并释放路径。
控制台按周期输出任务、车辆、选车原因、路径、HOLD 原因、队列状态和历史结果。
## 12. 自动测试
JUnit 5 测试至少覆盖:
- `LegacyDispatchCenterTest`:三车每周期只准入一次、稳定处理顺序。
- `VehicleAssignmentServiceTest`:资格过滤、同层优先、楼层差、Y/X 距离、稳定裁决和无效站点。
- `TrafficControllerTest`:路径锁、离线点、绕行、无路、通道阻挡、避让去重和释放。
- `QueueLifecycleTest`:新建、下发、失败重试、完成归档和幂等。
- `DemoScenarioTest`:端到端运行关键场景并验证真实事件结果。
验证命令:
```bash
cd javaTest
mvn test
mvn exec:java
```
验收时必须从 Surefire 报告确认测试数量大于 0、失败数为 0、错误数为 0;不能只依据 Maven 退出码。
## 13. 验收标准
满足以下条件才认为 Demo 完成:
1. 工作树根目录存在独立 `javaTest` Maven 项目。
2. 源码编译目标为 Java 8。
3. 调度中心真实执行每周期一次准入和逐车处理。
4. 确定性选车规则及理由可测试。
5. 交通管制能处理路径锁、通道阻挡、避让任务和占用释放。
6. 队列状态按 LEGACY 语义流转。
7. `DemoApplication` 可运行并打印完整模拟结果。
8. JUnit 5 测试数量大于 0,全部通过。
9. 项目不访问真实数据库、PLC 或 WMS,不修改生产控制代码。