# 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,不修改生产控制代码。