Files
ParkingRobot/docs/superpowers/specs/2026-07-28-coarse-path-test-diagnostics-design.md
T

161 lines
8.5 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.
# 粗路径手动测试诊断与耗时设计
## 目标
完善 `[MovementTest(name = "粗路径规划")]` 的手动测试体验,使调用者能够为每次测试指定正数秒总预算,并在失败时看到真实、可区分的终止原因、搜索统计、总耗时和路径搜索耗时。
本改动不放宽碰撞安全、终点判定或成功路径发布条件,也不把普通规划失败改成异常。普通失败继续通过 `PlanningResult` 返回;输入读取失败和未预期程序错误才按异常信息展示。
## 已确认的现状
手动测试使用正式的 `CoarsePathPlanningService``HybridAStarPlanner``HybridAStarSearch`,没有测试专用搜索器,也没有关闭倒车;`HybridAStarConfiguration.AllowReverse` 默认仍为 `true`
影响实际成功率和问题定位的限制如下:
- 手动入口未覆盖 `SearchTimeout`,因此沿用 5 秒总预算。
- 已复现一个空图可行案例:起点 `(1000 mm, 2000 mm, 0 deg)`、终点 `(1500 mm, 2500 mm, 90 deg)` 在 5 秒返回 `SearchTimeout`,将预算改为 30 秒后约 10.2 秒成功。
- 手动测试固定使用长 `0.80 m`、宽 `0.60 m`、安全余量 `0.05 m`、最小转弯半径 `1.20 m` 的演示车辆参数,不读取现场 AMR 几何参数。
- `HybridAStarPlanner` 将所有搜索阶段失败改写成同一句“Hybrid A* 搜索未找到可发布路径”,丢失了超时、节点上限、无解和内部错误的具体区别。
- 状态图层只在 `TerminationReason` 非空时绘制原因,而 Toast 不包含原因。
- 第一版算法只支持汽车式恒曲率前进、倒车和原语边界换向;明确不支持 Reeds-Shepp 精确连接、横移、蟹行和原地旋转。这是整个粗规划核心的版本边界,不是手动测试单独阉割。
## 范围
### 包含
- 手动测试增加单次总超时输入。
- 搜索结果保留原始终止原因。
- 面向调用者组合状态、原因、资源上限和节点统计。
- 状态图层与 Toast 展示原因、总耗时和路径搜索耗时。
- README 说明测试车辆参数和第一版运动能力限制。
- 自动化覆盖输入校验、失败分类、耗时边界和 UI 文本。
### 不包含
- Reeds-Shepp 或 Dubins 解析终点连接。
- 横移、蟹行或原地旋转原语。
- 路径平滑、速度规划或控制。
- 将固定演示车辆参数替换为尚未定义来源的现场 AMR 参数。
- 改变地图边界策略、碰撞规则、终点容差或 Open List 排序。
## 设计
### 手动超时输入
`CoarsePathPlanningTest.Test()` 在读取终点航向后读取“粗路径规划总超时(秒,必须大于 0)”。输入按当前文化和不变文化解析为有限 `double`,必须严格大于零,并且转换为 `TimeSpan` 后不溢出。
场景工厂仍负责创建完整业务请求;测试入口在取得 `CoarsePathPlanningJob` 后只覆盖本次请求的:
```csharp
job.Configuration.SearchTimeout = TimeSpan.FromSeconds(timeoutSeconds);
```
固定回归场景继续使用各自既有预算。手动输入不修改全局默认配置,也不影响下次测试。
输入 `0`、负数、NaN、Infinity、非数字或超出 `TimeSpan` 可表示范围时,本次规划不启动,并通过既有输入失败提示显示具体字段。
### 搜索原始终止原因
`HybridAStarSearchResult` 增加只读 `TerminationReason`。搜索的每个失败出口填写与发生位置一致的原因:
- `SearchTimeout`:共享总预算已经耗尽。
- `SearchNodeLimitExceeded`:扩展节点数达到配置上限。
- `NoFeasiblePath`:二维启发式不可达、起始状态无法进入 Open List,或 Open List 耗尽。
- `Cancelled`:收到取消请求。
- 输入、地图、车辆或配置状态:指出对应校验阶段。
- `InternalError`:保留异常类型和消息,不在 UI 展示完整堆栈。
`HybridAStarPlanner` 不再用同一句泛化说明覆盖搜索原因。它将原始原因与可操作统计组合为最终 `PlanningDiagnostics.TerminationReason`。例如:
```text
总预算 8.000 秒已耗尽;扩展 5,366,生成 21,014Open List 峰值 15,102。
```
节点上限原因包含配置的 `MaximumExpandedNodes`;无解原因包含扩展、生成和 Open List 峰值。起点、终点、碰撞和最终复核的现有明确原因保持不变。
### 异常语义
普通规划失败不抛异常,因为超时、无解、碰撞和资源上限是可预期业务结果。调用者继续通过 `PlanningStatus` 做稳定分支,并读取 `TerminationReason`
搜索或规划器捕获未预期异常时返回 `InternalError`,原因包含异常类型和非空消息。完整堆栈不进入 Toast,避免界面噪声;自动化测试验证异常不会再次被完全静默吞掉。
### 耗时
保留既有 `PlanningDiagnostics.Elapsed`,定义为从 `CoarsePathPlanningService.Plan` 入口开始的总耗时,包括建图、缓存查询、栅格化、距离场和路径规划。
新增只读 `PlanningDiagnostics.PathSearchElapsed`,边界为:
- 开始:规划请求、地图、车辆、配置、起点、终点和初始碰撞预检均已通过,即将进入 `HybridAStarSearch.Search`
- 包含:二维 Dijkstra 启发式、Hybrid A* 扩展、回溯、路径装配、方向分段和最终复核。
- 结束:`HybridAStarPlanner` 准备构造最终 `PlanningResult`
- 不包含:地图来源读取、地图缓存、栅格化、距离场构建和搜索前预检。
搜索开始前失败时为 `TimeSpan.Zero`;搜索开始后的成功、失败、取消、超时、节点上限、回溯失败或最终复核失败均保留截至返回时的路径搜索耗时。所有结果满足:
```text
TimeSpan.Zero <= PathSearchElapsed <= Elapsed
```
构造函数的新参数位于现有参数之后并具有 `TimeSpan.Zero` 默认值,保持现有调用兼容。
### MovementTest 展示
状态图层显示:
- 地图状态、缓存命中和快照。
- 规划状态。
- 总耗时与路径搜索耗时。
- 扩展节点数、生成节点数和 Open List 峰值。
- 非空失败原因。
- 当前测试采用的车辆长、宽、安全余量和最小转弯半径。
Toast 保持单行摘要,但成功和失败都显示两种耗时;失败时必须附加 `TerminationReason`。这样即使用户没有看到地图左下角的状态图层,也不会只收到一个无原因的失败状态。
### 文档
`CoarsePath/README.md` 增加以下说明:
- 手动入口要求输入有限正数秒总预算。
- 总耗时与路径搜索耗时的不同边界。
- 手动入口采用固定演示车辆参数,不代表现场 AMR。
- 当前算法支持汽车式恒曲率前进、倒车和换向,但不支持 Reeds-Shepp 精确连接、横移、蟹行或原地旋转。
## 测试策略
所有行为修改遵循 Red-Green-Refactor。
### 输入与 UI 源码检查
`verify_coarse_path_ui.ps1` 先增加失败断言,再实现:
- 手动入口读取并应用超时秒数。
- 超时输入使用正数有限值校验。
- 状态图层和 Toast 都读取 `PathSearchElapsed`
- Toast 读取 `TerminationReason`
- 状态图层显示节点统计和车辆参数。
- README 包含新的耗时边界、手动预算和能力限制说明。
### 搜索与集成行为
`verify_coarse_path_search.ps1``verify_coarse_path_integration.ps1` 先增加失败断言,再实现:
- 超时、节点上限、无解和内部错误返回不同的非空原因。
- `InternalError` 原因包含异常类型或消息。
- 搜索前失败的 `PathSearchElapsed` 为零。
- 一个真实成功规划的路径搜索耗时非负且不超过总耗时。
- 搜索阶段失败保留已消耗的路径搜索耗时。
- 5 秒会超时而更长手动预算可成功的近距离换向案例得到回归覆盖;测试应使用足够稳定的预算余量,避免仅依赖精确墙钟阈值形成脆弱测试。
### 最终回归
最终运行 Debug 构建,以及现有地图、碰撞、搜索、集成和 UI 脚本。既有固定成功场景、取消、总超时、节点上限、无解、地图缓存和最终碰撞复核语义不得改变。
## 验收标准
- 手动“粗路径规划”每次要求输入有限正数秒总预算,并应用到该次请求。
- 失败 Toast 能直接区分超时、节点上限、无解、碰撞和内部错误,并包含可操作原因。
- 状态图层同时显示两种耗时、搜索统计和演示车辆参数。
- 可行但超过默认 5 秒的复现场景可以通过更长的用户输入预算成功。
- 所有新旧自动化验证通过。
- 算法第一版能力限制在 README 中可见,不再被误认为测试入口暗中禁用完整算法。