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

8.5 KiB
Raw Blame History

粗路径手动测试诊断与耗时设计

目标

完善 [MovementTest(name = "粗路径规划")] 的手动测试体验,使调用者能够为每次测试指定正数秒总预算,并在失败时看到真实、可区分的终止原因、搜索统计、总耗时和路径搜索耗时。

本改动不放宽碰撞安全、终点判定或成功路径发布条件,也不把普通规划失败改成异常。普通失败继续通过 PlanningResult 返回;输入读取失败和未预期程序错误才按异常信息展示。

已确认的现状

手动测试使用正式的 CoarsePathPlanningServiceHybridAStarPlannerHybridAStarSearch,没有测试专用搜索器,也没有关闭倒车;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 后只覆盖本次请求的:

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。例如:

总预算 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;搜索开始后的成功、失败、取消、超时、节点上限、回溯失败或最终复核失败均保留截至返回时的路径搜索耗时。所有结果满足:

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.ps1verify_coarse_path_integration.ps1 先增加失败断言,再实现:

  • 超时、节点上限、无解和内部错误返回不同的非空原因。
  • InternalError 原因包含异常类型或消息。
  • 搜索前失败的 PathSearchElapsed 为零。
  • 一个真实成功规划的路径搜索耗时非负且不超过总耗时。
  • 搜索阶段失败保留已消耗的路径搜索耗时。
  • 5 秒会超时而更长手动预算可成功的近距离换向案例得到回归覆盖;测试应使用足够稳定的预算余量,避免仅依赖精确墙钟阈值形成脆弱测试。

最终回归

最终运行 Debug 构建,以及现有地图、碰撞、搜索、集成和 UI 脚本。既有固定成功场景、取消、总超时、节点上限、无解、地图缓存和最终碰撞复核语义不得改变。

验收标准

  • 手动“粗路径规划”每次要求输入有限正数秒总预算,并应用到该次请求。
  • 失败 Toast 能直接区分超时、节点上限、无解、碰撞和内部错误,并包含可操作原因。
  • 状态图层同时显示两种耗时、搜索统计和演示车辆参数。
  • 可行但超过默认 5 秒的复现场景可以通过更长的用户输入预算成功。
  • 所有新旧自动化验证通过。
  • 算法第一版能力限制在 README 中可见,不再被误认为测试入口暗中禁用完整算法。