From 99b15d0d96865f5dcb90987acbb5d1a3fc88bc48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E8=96=84=E4=BA=91?= Date: Tue, 11 Aug 2026 15:53:11 +0800 Subject: [PATCH] docs: design EM planner controller handoff guide --- ...planner-controller-handoff-guide-design.md | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-11-em-planner-controller-handoff-guide-design.md diff --git a/docs/superpowers/specs/2026-08-11-em-planner-controller-handoff-guide-design.md b/docs/superpowers/specs/2026-08-11-em-planner-controller-handoff-guide-design.md new file mode 100644 index 0000000..cb0ca8a --- /dev/null +++ b/docs/superpowers/specs/2026-08-11-em-planner-controller-handoff-guide-design.md @@ -0,0 +1,186 @@ +# EM Planner 控制器交接指南设计 + +## 目标 + +在 `ClumsyPilot/ParkrobTrajplanner/Trajplanner_guide` 中提供一套无需编译、可以直接复制阅读的中文指南和 C# 示例,使闭环控制器维护者能够完整理解: + +1. 固定离线场景中的起点、终点、车辆参数和障碍物如何形成规划输入; +2. Hybrid A* 粗路径、Local G2 平滑路径和 EM 时间轨迹依次如何产生; +3. `EmPlanningService` 如何调用,调用方何时可以从 `EmPlanningResult` 索取完整轨迹; +4. `EmTrajectory` 输出包含什么、字段单位和坐标语义是什么; +5. 如何把 EM 输出转换成闭环测试消费的 `Trajectory2D`,替换当前 `TestTrajectoryFactory` 人工轨迹。 + +交付物仅为指南和示例代码,不新增可执行项目,不改变规划器或闭环控制器行为。 + +## 读者与使用边界 + +主要读者是维护 `停车机器人-合并测试/parkr_shen/MultiWheelC/Movements` 和对应 `Experiments` 闭环测试的控制器开发者。指南假设读者了解 C#,但不了解本仓库规划模块。 + +示例采用固定、离线、静态场景,目的是展示真实 API 的完整调用关系,而不是提供可以直接启动车辆的测试入口。示例不得读取实时定位、直接发送底盘命令或暗示规划成功即可无条件接管车辆。 + +## 方案与文件结构 + +采用“详细 README + 完整流程示例 + 控制器替换示例”的结构: + +```text +ClumsyPilot/ParkrobTrajplanner/Trajplanner_guide/ +├── README.md +├── EmPlannerFullPipelineDemo.cs +├── EmPlannerTrajectoryReplacementExample.cs +└── trajectory-planning-flow-demo.html +``` + +- `README.md` 是主指南,负责步骤解释、配置索引、输出契约、错误处理和集成边界。 +- `EmPlannerFullPipelineDemo.cs` 是一份连续的固定离线 C# 示例,从场景输入一直写到 `Trajectory2D`。 +- `EmPlannerTrajectoryReplacementExample.cs` 聚焦闭环测试中的轨迹索取和替换点,提供替换前后对照。 +- 现有 `trajectory-planning-flow-demo.html` 保留为辅助流程图;README 会链接它,但完整理解不依赖浏览器或 HTML。 + +示例代码无需独立编译,但所有命名、构造参数、状态判断和字段访问必须与当前仓库真实 API 对齐。为了阅读连续性,允许在示例中使用少量明确标注为“宿主提供”的辅助方法;每个辅助方法都必须说明其输入、输出和真实系统替换来源,不能以省略号隐藏规划步骤。 + +## README 内容设计 + +### 1. 首屏结论 + +README 开头直接说明两个类型边界: + +```text +EMplanner 正式输出:EmTrajectory +闭环控制器正式输入:Trajectory2D +桥接方法:EmControlTrajectoryAdapter.Create(EmTrajectory) +``` + +同时明确 `EmPlanningService` 是进程内同步服务,不是 HTTP、RPC、消息队列或后台轨迹仓库。调用方构造冻结的 `EmPlanningRequest`,调用 `Plan(request, cancellationToken)`,并从本次返回的 `EmPlanningResult` 中索取轨迹。 + +### 2. 完整数据流 + +按以下顺序逐步解释,每一步与完整示例中的编号注释一致: + +1. 定义世界坐标系固定起点和终点; +2. 定义车辆尺寸、曲率约束、安全边界和规划预算; +3. 建立带固定障碍物的 `PlanningGridMap`; +4. 建立粗路径 `PlanningRequest`; +5. 调用 `HybridAStarPlanner.Plan` 并拒绝非成功结果; +6. 建立 `PathSmoothingRequest` 并调用 Local G2 平滑; +7. 从平滑结果选择当前方向段,禁止跨换向边界混合; +8. 建立初始 `VehicleMotionState`; +9. 建立并冻结 `EmPlannerConfiguration`; +10. 建立 `EmPlanningRequest`; +11. 使用 `EmPlanningService(new OsqpNativeSolver()).Plan(request, cancellationToken)`; +12. 检查状态、失败原因、轨迹非空和点数; +13. 读取 `EmTrajectory.Metadata` 和 `EmTrajectory.Points`; +14. 使用 `EmControlTrajectoryAdapter.Create(result.Trajectory)` 转换为 `Trajectory2D`; +15. 把结果赋给 `TrajectoryTrackingMovement.Trajectory` 或包装为 `TrackMotionPlanSegment`。 + +每一步都说明“输入来自哪里、调用哪个函数、返回什么、失败后做什么、下一步消费什么”。 + +### 3. 配置索引 + +README 按模块列出配置的源码位置和作用: + +- `CoarsePath`:车辆外廓、地图分辨率、运动原语、目标容差、搜索预算; +- `PathSmoothing`:采样间距、Local G2 窗口和连续性相关参数; +- `EMPlanner/Configuration`:走廊、Frenet、横向、纵向、求解器、调度和验证参数; +- `TrajectoryTrackingMovement`:Stanley、纵向 PID、速度上限、终点容差、偏离保护和执行超时。 + +每个对集成有影响的参数表必须包含:字段名、源码文件、单位、示例值、含义、调大/调小的主要影响。README 还要区分: + +- 规划安全约束与控制器执行参数; +- 米和毫米; +- 弧度和角度; +- 世界坐标速度分量与车体纵向有符号速度; +- 滚动视界字段与完整方向段规划字段。 + +### 4. 输出契约 + +README 逐项说明: + +- `EmPlanningResult.Status`、`FailureReason`、`Trajectory`; +- `EmTrajectory.Metadata` 中的轨迹身份、生效时间、方向段、方向、终端类型和规划范围; +- `EmTrajectoryPoint` 中时间、世界坐标位置、航向、曲率、路径弧长、带符号纵向速度、世界速度分量、加速度、jerk 和 yaw rate。 + +必须明确: + +- 只有成功结果中的完整非空轨迹可以交给控制适配器; +- `VelocityX`/`VelocityY` 是世界坐标预测分量,不能直接当底盘命令; +- 前进速度为正、倒车速度为负; +- 控制适配器使用世界位姿、车辆曲率和带符号纵向速度,并按世界位置重建从零开始的控制弧长; +- 轨迹是不可变结果,调用方不应在交给控制器前原地修改点列。 + +### 5. 单方向、换向和终点 + +固定 demo 使用单方向段,保证其最终结果可以直接转换成一个 `Trajectory2D`。README 仍需完整解释多方向粗路径: + +- EM 每次规划一个活动方向段; +- 换向边界必须先精确停车; +- 不得跨方向或边界对轨迹点插值; +- 多方向任务应按段规划和执行,并由安全审查后的换向状态机确认方向,再请求下一段; +- 不得把多个正负方向段简单拼成一个供当前几何控制器连续跟踪的 `Trajectory2D`。 + +### 6. 失败和安全处理 + +README 为以下情况给出明确处理:粗路径失败、平滑失败、EM 求解失败、取消、超时、空轨迹、少于两个不同位置的控制点、单位错误、方向段不匹配。失败示例必须停止在控制输入边界,不创建或下发替代移动命令。 + +## 完整流程示例设计 + +`EmPlannerFullPipelineDemo.cs` 使用一个固定单方向停车场景。文件采用连续编号的区域和中文注释,注释必须同时回答“为什么”和“单位是什么”,而不是简单复述代码。 + +示例包含: + +- 所有必需的 `using`; +- 固定场景常量; +- 场景、地图、车辆、粗规划、平滑和 EM 配置的建立; +- 每一层结果的显式状态检查; +- `EmPlanningService` 调用; +- 至少一段遍历输出点并解释字段的代码; +- `EmControlTrajectoryAdapter` 转换; +- 返回一个包含原始 `EmTrajectory` 与控制 `Trajectory2D` 的只读示例结果对象,以便读者看清两种输出并存而非互相替代。 + +示例必须完整展开所有步骤,不得使用省略号或待办标记。如果真实 API 需要由宿主提供地图栅格写入或固定障碍物离散化,示例必须给出完整辅助函数,或明确引用仓库中已有的完整公共入口。 + +## 控制器替换示例设计 + +`EmPlannerTrajectoryReplacementExample.cs` 以对方现有测试为上下文,直接展示: + +```csharp +// 替换前:人工测试轨迹 +Trajectory2D trajectory = TestTrajectoryFactory.CreateStraight4Meters( + trajectoryStartPose, + CruiseSpeedMetersPerSecond, + AccelerationMetersPerSecondSquared, + DecelerationMetersPerSecondSquared, + PointSpacingMeters); + +// 替换后:从规划服务结果索取并适配 +EmPlanningResult result = planningService.Plan(request, cancellationToken); +if (result.Status != EmPlanningStatus.Success || result.Trajectory == null) + throw new InvalidOperationException(result.FailureReason); + +Trajectory2D trajectory = adapter.Create(result.Trajectory); +``` + +文件随后分别展示两种消费方式: + +1. `new TrajectoryTrackingMovement { Trajectory = trajectory, StateProvider = stateProvider }`; +2. `new TrackMotionPlanSegment(trajectory)`。 + +注释会指出对方测试中当前人工轨迹建立位置,并说明真正合并时需要替换的仅是“轨迹来源”,控制器参数和车辆状态源不应被示例暗中改写。 + +## 一致性与验证 + +由于交付物不要求独立编译,验证重点是静态真实性和可追踪性: + +1. 逐个核对示例中的类型、构造函数、枚举、属性和方法与仓库源代码一致; +2. 检查 README 的步骤编号与 C# 注释编号一一对应; +3. 检查配置表中的路径、字段和单位均可在源码定位; +4. 检查替换示例准确对应外部闭环测试的 `TestTrajectoryFactory` 调用和 `TrajectoryTrackingMovement.Trajectory`; +5. 扫描交付物,确保没有省略号、占位符或未解释的伪 API; +6. 检查工作区差异,确保只修改指南范围内文件及本设计/计划文档,不覆盖用户现有改动。 + +## 非目标 + +- 不修改 `EmPlanningService`、规划算法或配置默认值; +- 不修改外部 `停车机器人-合并测试` 目录; +- 不创建网络服务或新的跨进程传输协议; +- 不创建可执行 demo 项目; +- 不直接运行车辆或发送任何底盘命令; +- 不在本次工作中设计完整的多方向自动换向执行器。