From 55236a04bf630d3aaed423464ec2bf3ff3aa771a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E8=96=84=E4=BA=91?= Date: Tue, 28 Jul 2026 12:27:40 +0800 Subject: [PATCH] docs: design coarse path test diagnostics --- ...-28-coarse-path-test-diagnostics-design.md | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-28-coarse-path-test-diagnostics-design.md diff --git a/docs/superpowers/specs/2026-07-28-coarse-path-test-diagnostics-design.md b/docs/superpowers/specs/2026-07-28-coarse-path-test-diagnostics-design.md new file mode 100644 index 0000000..05cb683 --- /dev/null +++ b/docs/superpowers/specs/2026-07-28-coarse-path-test-diagnostics-design.md @@ -0,0 +1,160 @@ +# 粗路径手动测试诊断与耗时设计 + +## 目标 + +完善 `[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,014,Open 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 中可见,不再被误认为测试入口暗中禁用完整算法。