docs(javaTest): design bounded conflict-aware routing

This commit is contained in:
zgw
2026-08-06 16:47:01 +08:00
parent e5f1c34ab9
commit 97de1f9f26

View File

@@ -0,0 +1,346 @@
# javaTest 有界绕行与冲突感知路径规划设计
**日期:** 2026-08-06
**状态:** 已完成方案讨论,等待书面确认
**适用范围:** `javaTest` 历史任务中心调度仿真与调度路径审计页面
## 1. 背景
当前 `javaTest` 使用 `GridPathPlanner` 在完整地图上执行 BFS,得到边数最少且结果确定的路径。
历史 `path_info` 只用于结果对照,不参与重新规划。240 条历史任务的初步结果为 137 条路径序列
发生变化,但该数字不能直接证明路径优化有效:
- 130 条历史路径的首尾与解析后的物理业务端点不一致;
- 2 条历史路径含未知或非邻接段;
- 剩余 108 条可公平比较的任务中,103 条完全相同,4 条路线不同但边数相同,只有 1 条更短;
- 可比较任务的平均边数仅从 10.14 降到 10.12。
因此,本设计不再用“路径是否不同”或受故障影响的实际完成时间证明优化效果,而是在最短物理
距离附近选择交通冲突更少、路线重叠更少、转弯更少的候选路线,并提供完整、可解释的决策证据。
## 2. 目标与非目标
### 2.1 目标
1. 接近路径和服务路径都允许在最短物理距离 110% 范围内绕行。
2. 只使用当前活动任务、节点占用、边预约和走廊方向判断交通风险,不使用历史热度。
3. 按固定业务优先级比较候选路线,不使用难以解释和调参的加权总分。
4. 同一交通资源连续造成 3 个调度周期 HOLD 后,从车辆当前位置重新规划剩余路线。
5. 路线切换必须保持当前占用和预约安全,不能因重规划产生资源空窗。
6. 将路线质量、交通执行和故障恢复分开统计。
7. 相同地图、输入和交通快照必须产生相同结果。
### 2.2 非目标
1. 不用实际行驶时间或最终任务完成时间给路径质量打分。
2. 不使用历史 `path_info` 约束新路线。
3. 不在本次改造中改变现有车辆资格、低电量和车辆选择业务规则。
4. 不把 PLC 失败、断线、低电量或车辆故障当成交通 HOLD。
5. 不接入生产数据库、真实 PLC、真实 WMS 或实时交通服务。
## 3. 业务术语
- **接近路径:** 重新选中的车辆当前位置到任务物理起点 A 的路线。
- **服务路径:** 任务物理起点 A 到物理终点 B 的路线。
- **基准最短距离 D:** 在永久禁行条件下,起终点间可达路线的最小坐标距离。
- **有界候选路线:** 物理距离不超过 `D * 1.10` 的无环路线。
- **交通快照:** 某次调度决策时的车辆占用节点、边预约、走廊方向和其他活动路线。
- **交通 HOLD:** 下一步因节点、边、对向或走廊方向冲突而暂时不能安全推进。
- **相同阻塞:** 任务、车辆、阻塞资源标识和交通 HOLD 原因均相同。
## 4. 总体架构
### 4.1 `RouteCandidatePlanner`
职责:根据完整 `GridMap`、起点、终点和永久禁行资源生成确定性的有界候选路线。
输入:
- `GridMap`
- 起点、终点
- 永久禁行节点或边
- `RoutePlanningPolicy`
输出:
- 基准最短距离
- 最短路线
- 不超过 110% 的候选路线
- 是否命中候选数量上限
该模块不读取车辆状态、交通预约、历史路径或任务优先级,只负责生成地图上合法的路线候选。
### 4.2 `RouteQualityEvaluator`
职责:使用同一时刻的 `TrafficRouteSnapshot` 对候选路线进行可解释的业务排序。
输入:候选路线、交通快照、当前任务和车辆。
输出:每条路线的 `RouteQuality` 以及最终 `RoutePlanDecision`。
### 4.3 `TrafficRouteSnapshot`
职责:为一次规划决策提供不可变交通证据,避免候选路线使用不同时间点的数据。
包含:
- 车辆当前占用节点及归属车辆;
- 已预约的有向边、方向和归属任务;
- 走廊方向预约及归属任务;
- 其他活动任务尚未完成的剩余路线;
- 当前任务和车辆自身已经合法持有的资源。
### 4.4 `HoldReroutePolicy`
职责:只累计交通 HOLD,并在同一阻塞连续出现 3 个调度周期时触发重规划。
### 4.5 `RouteDecisionEvidence`
职责:保存候选生成、路线评分、HOLD 触发、资源替换和最终选择的可审计证据,供 JSON 报告和
HTML 页面展示。
## 5. 物理距离与候选路线
### 5.1 边距离
当前完整地图共有 8 层、1239 条边,不存在跨层边。相邻站点边距离按地图坐标的欧氏距离计算:
```text
edgeDistance = sqrt((to.x - from.x)^2 + (to.y - from.y)^2)
pathDistance = sum(edgeDistance)
```
距离单位是地图坐标单位,不宣称为米。未来如增加跨层边,必须由地图元数据显式提供该边距离;
不得根据楼层编号虚构垂直距离。
### 5.2 候选生成算法
采用确定性的 K 最短无环路径方案:
1. 使用 Dijkstra 计算基准最短路线和距离 `D`;
2. 按距离从小到大生成无环候选路线;
3. 下一候选距离超过 `D * 1.10` 时停止;
4. 最多保留 32 条候选;
5. 距离相同时按完整站点序列排序;
6. 未知节点、永久封闭道路和静态禁行资源不进入候选;
7. 当前临时占用和预约不从地图删除,只在质量评价阶段计入风险。
候选上限 32 是性能边界,不是业务评分。达到上限时在证据中写入
`candidateLimitReached=true`,但仍从已生成候选中作出确定性选择。
### 5.3 接近路径与服务路径
现有 `VehicleAssignmentService` 继续负责车辆资格和选车,不在本设计中改变选车规则。选车完成后:
1. 为选中车辆计算“当前位置到任务起点”的有界接近路径;
2. 独立计算“任务起点到任务终点”的有界服务路径;
3. 分别保存两段路线的最短距离、候选数量和选择原因;
4. 交通预约仍对拼接后的完整执行路线申请。
这样可以优化两段路线,同时避免本次改造无意改变已经验证过的自动选车行为。
## 6. 路线质量排序
每条候选路线生成以下固定顺序的比较元组:
```text
(
oppositeDirectionConflictCount,
occupiedNodeCount,
incompatibleReservedEdgeCount,
activeRouteOverlapEdgeCount,
turnCount,
physicalDistance,
canonicalPath
)
```
排序为字典序,前一项不同时不再比较后一项。
### 6.1 指标定义
- `oppositeDirectionConflictCount`:候选有向边与其他任务已预约方向相反的数量。
- `occupiedNodeCount`:候选未来节点中被其他车辆占用或独占预约的数量;当前车辆自身起点不计。
- `incompatibleReservedEdgeCount`:候选边与现有容量或方向规则不兼容的预约数量;已计为对向冲突
的边不重复计数。
- `activeRouteOverlapEdgeCount`:候选无向边与其他活动任务剩余路线重合的数量;这是未来竞争风险,
不等同于已经发生的资源冲突。
- `turnCount`:相邻两条同层边的方向向量发生变化的次数。
- `physicalDistance`:第 5 节定义的坐标距离。
- `canonicalPath`:用完整站点序列作最终稳定决胜。
安全规则仍由交通资源裁决执行。质量评价只决定优先尝试哪条路线,不能绕过节点容量、边方向或
走廊预约。
## 7. HOLD 后重规划
### 7.1 触发条件
仅以下原因进入连续 HOLD 计数:
- 下一节点被其他车辆占用或独占预约;
- 下一条边不可申请;
- 存在对向换边风险;
- 走廊方向预约冲突。
键为:
```text
(simulationTaskId, vehicleId, blockingResourceId, holdReason)
```
连续第 1、2 次只保持 HOLD;连续第 3 次产生 `REROUTE_TRIGGER`。车辆发生移动、阻塞资源或原因
改变、HOLD 消失、车辆被重新分配时清零。
PLC 发送失败或未 ACK、低电量、车辆故障和断线不进入该计数。
### 7.2 重规划范围
- 尚未到达任务起点:重新计算“当前位置到起点”的接近路径,同时基于同一交通快照重新评价
“起点到终点”的服务路径。
- 已进入服务路径:只计算“当前位置到任务终点”的剩余服务路径。
### 7.3 防止路线抖动
满足以下条件才允许切换:
1. 新剩余路线与当前剩余路线不同;
2. 新路线不超过对应最短距离 110%;
3. 新路线的质量元组严格优于当前路线;
4. 新路线的路线级走廊预约能够安全替换;
5. 上次成功换路后车辆已经至少移动一个节点,或当前路线出现永久失效。
找不到严格更优路线时产生 `REROUTE_REJECTED` 并继续 HOLD,不关闭任务。
## 8. 预约替换与资源释放
新增原子语义的路线级走廊预约替换操作:
```text
保留车辆当前占用节点和已进入边
→ 以当前任务旧预约为可替换资源,试算新剩余路线的走廊方向
→ 在不暴露中间状态的前提下提交走廊预约替换
→ 成功后提交新 remainingPath
→ 释放旧路线不再使用的走廊预约
```
如果试算或替换失败,旧路线和现有合法资源保持不变。不得先释放旧预约再申请新路线。
节点和边不因重规划而整条路线预占,仍由现有交通控制器在车辆移动前逐段申请,并在车辆通过后
逐段释放。重规划不能释放车辆当前节点、正在通过的边或其他任务资源。该边界既保留现有安全
语义,也避免因整条路线预占扩大资源等待和死锁风险。
## 9. 失败与降级规则
- 完整地图永久不可达:任务关闭为 `NO_ROUTE`。
- 存在地图路线但所有候选都有临时冲突:选择风险最小候选,交给交通裁决决定 GRANT/HOLD。
- 候选达到 32 条上限:从已有候选选择并记录上限证据。
- HOLD 后无更优路线:保持当前路线和 HOLD。
- PLC 失败或未 ACK:沿用原有协议重试,不触发路径重规划。
- 车辆故障或断线:沿用重新选车流程;新车辆确定后重新规划接近路径和服务路径。
- 低电量:车辆不再接收新任务;不把低电量伪装成交通冲突。
## 10. 事件与审计证据
保留现有事件,并新增:
- `REROUTE_TRIGGER`:包含连续 HOLD 次数、阻塞资源和原因;
- `REROUTE`:包含旧剩余路线、新剩余路线、两者质量元组和选择原因;
- `REROUTE_REJECTED`:包含没有更优候选、超出 110% 或预约替换失败原因。
每次初始规划和重规划输出:
- `shortestPhysicalDistance`
- `selectedPhysicalDistance`
- `detourRatio`
- `candidateCount`
- `candidateLimitReached`
- 质量元组各项指标
- `decisionReason`
- `pathVersion`
- `planningStage`:`APPROACH` 或 `SERVICE`
浏览器继续显示完整地图、历史路径、新规划路径和实际轨迹,并在检查器中分别显示接近路径和
服务路径的选择证据。实际时间、完成时间和 PLC 重试放在“运行与故障恢复”区域,不进入路线评分。
## 11. 历史路线比较口径
每条历史任务先分类:
- `COMPARABLE`:历史路径首尾与物理业务端点一致,且所有连续边都存在于权威地图;
- `ENDPOINT_MISMATCH`:历史首尾与物理业务端点不一致;
- `INVALID_HISTORY_PATH`:包含未知节点或非邻接段。
只有 `COMPARABLE` 任务进入路线质量统计。统计分类为:
- 完全相同;
- 物理距离更短;
- 距离相同但冲突或转弯更少;
- 距离在 110% 内略长但冲突更少;
- 新路线质量更差。
`pathChanged` 继续保留节点序列语义以兼容现有报告,但不能再单独作为“优化成功”指标。
## 12. 验收门禁
### 12.1 路线算法门禁
1. 所有选中路线距离不超过对应最短物理距离 110%。
2. 最终路线必须是已生成候选中的字典序最优质量元组。
3. 临时冲突不能导致错误的 `NO_ROUTE`。
4. 同一输入、地图和交通快照重复运行必须得到相同路线和原因。
5. 历史端点不一致或存在无效段时不得计入优化比例。
### 12.2 HOLD 与资源门禁
1. 同一交通冲突连续 1、2 次不重规划,第 3 次触发。
2. PLC 失败、低电量、故障和断线不能误触发交通重规划。
3. 找不到严格更优路线时保持原路线。
4. 路线切换失败不能丢失旧预约。
5. 车辆移动前后节点、边和走廊资源均保持单一合法归属。
6. 节点双占、资源超容量、对向换边和死锁为 0。
### 12.3 业务闭环门禁
1. 基准 240 条历史任务全部进入终态,不遗留活动或等待任务。
2. 所有完成任务归档一次且仅一次。
3. WMS 重复投递不产生重复业务效果。
4. 失败任务必须有明确、可审计的失败原因。
## 13. 测试策略
### 13.1 单元测试
- 坐标距离和路线距离;
- 110% 边界内外候选过滤;
- 无环候选和 32 条数量上限;
- 固定质量元组排序;
- 转弯、重叠、占用和对向冲突计数;
- 相同输入的确定性;
- 历史路线三类可比性判定。
### 13.2 集成测试
- 最短路线有冲突,10% 内存在无冲突绕行,必须选择绕行;
- 无冲突绕行超过 10%,必须保留允许范围内的最优路线;
- 所有候选有临时冲突时保持可调度而非 `NO_ROUTE`;
- 连续第 3 次相同交通 HOLD 重规划;
- 阻塞资源变化后计数重新开始;
- 成功换路后移动一个节点前不再次普通重规划;
- 新预约失败时旧预约保持完整;
- PLC 重试和车辆故障不污染交通 HOLD 计数。
### 13.3 历史负载和浏览器验收
- 重新执行 240 条历史任务并输出 `COMPARABLE/ENDPOINT_MISMATCH/INVALID_HISTORY_PATH`;
- 报告接近路径和服务路径的候选、质量、绕行比例和重规划证据;
- 在完整地图中显示初始路线、HOLD 点和重规划后的剩余路线;
- 验证所有路线切换均能从事件和资源证据追溯;
- 验证归档、WMS 幂等和所有安全门禁。
## 14. 性能与兼容性
- 不新增生产依赖,保持 Java 8 编译目标。
- 候选数量固定上限为 32,避免历史批量回放搜索量失控。
- 现有 `plannedPath`、`pathChanged` 和历史证据字段保持兼容;新增字段只扩展 JSON。
- 当前 BFS 行为保留为基准测试和最短边数对照,不再承担最终冲突感知选路职责。
- 本设计只修改 `javaTest`,不直接替换生产 WCS 调度实现。