# Hybrid A* 粗路径规划实施计划

> For agentic workers: implement task-by-task with checkbox tracking.

**目标：** 完成可独立调用的规划地图入口与 Hybrid A* 粗路径输出。所有核心功能和自动化测试通过后，最后编写 MovementTest。

**架构：** Map 的唯一公共调用类是 PlanningMapFactory；CoarsePath 的唯一公共调用类是 HybridAStarPlanner。Map 输出只读 PlanningGridMap，Planner 只接收该输入。

**技术栈：** C# 10、.NET Standard 2.0、现有 Clumsy 引用、PowerShell 反射测试、Clumsy MovementTest。

## 全局约束

- 外部地图与障碍物使用现有世界坐标 mm；规划内部使用 m、rad、1/m。
- 环境占据图只保存外部障碍物；车体尺寸与安全余量只属于碰撞检查。
- 支持中心放置的轴对齐矩形、圆形和可选 TwoLegDetect 投影；障碍物不膨胀。
- 第一版终点使用可配置位置/航向容差；不含 Reeds-Shepp、平滑、SQP、时间轨迹与控制。
- 每个公共接口必须有成功、边界、失败测试；MovementTest 是最后一项任务。

---

## 最终目录与职责

~~~text
ClumsyPilot/ParkrobTrajplanner/
├── Initial_plan/
│   ├── AMR_轨迹规划技术路线_Agent版.md
│   └── AMR_HybridAStar_粗路径实施计划.md
├── Utils/                                      # MultiWheelC.TrajectoryPlanning.Utils
│   ├── AngleMath.cs                            # 角度归一化、角差、航向索引
│   ├── UnitConverter.cs                        # mm/m、deg/rad、半径/曲率
│   ├── CoordinateTransform.cs                  # 世界系与车体系二维变换
│   ├── NumericGuard.cs                         # 数值合法性校验
│   └── GridIndex.cs                            # 行列索引值对象
├── Map/                                        # MultiWheelC.TrajectoryPlanning.Mapping
│   ├── Core/
│   │   ├── EnvironmentGridMap.cs               # 仅外部障碍物的 mm 栅格
│   │   ├── MapBuildRequest.cs                  # 环境图构造参数
│   │   ├── EnvironmentMapBuildResult.cs        # 环境图构造结果
│   │   └── EnvironmentMapBuilder.cs            # 内部构造器
│   ├── Obstacles/
│   │   ├── IMapObstacle.cs                     # 障碍物几何契约
│   │   ├── AxisAlignedRectangleObstacle.cs     # 中心、宽、高矩形
│   │   ├── CircleObstacle.cs                   # 中心、半径圆形
│   │   └── MapObstacleRasterizer.cs            # 唯一占据写入器
│   ├── Sources/
│   │   ├── ManualObstacleSource.cs             # 人工障碍物集合
│   │   └── TwoLegObstacleProjector.cs          # TwoLegDetect 投影
│   ├── Planning/
│   │   ├── PlanningGridMap.cs                  # 只读 m 单位规划地图
│   │   ├── ObstacleDistanceField.cs            # 最近障碍距离
│   │   └── PlanningMapAdapter.cs               # mm 地图适配
│   ├── PlanningMapRequest.cs                   # Map 统一输入
│   ├── PlanningMapBuildResult.cs                # Map 统一输出
│   ├── PlanningMapFactory.cs                   # Map 唯一公共调用类
│   └── Test/MovementTest.MapTest.cs             # 最后阶段的地图测试入口
├── CoarsePath/                                 # MultiWheelC.TrajectoryPlanning.CoarsePath
│   ├── Contracts/
│   │   ├── Pose2D.cs                           # m/rad 位姿
│   │   ├── VehicleParameters.cs                # 尺寸、曲率、安全余量
│   │   ├── PlanningRequest.cs                  # Planner 输入
│   │   ├── HybridAStarConfiguration.cs         # 可调参数
│   │   ├── PlanningResult.cs                   # Planner 输出
│   │   ├── PlanningStatus.cs                   # 成功/失败状态
│   │   ├── PlanningDiagnostics.cs              # 诊断统计
│   │   ├── CoarsePathPoint.cs                  # 稠密空间路径点
│   │   └── PathSegment.cs                      # 前进/倒车分段
│   ├── Vehicle/
│   │   ├── VehicleKinematics.cs                # 最大曲率
│   │   ├── HeadingFootprintTemplate.cs         # 单航向车体模板
│   │   ├── HeadingFootprintTemplateCache.cs    # 模板预计算
│   │   └── FootprintCollisionChecker.cs        # 碰撞检查
│   ├── Search/
│   │   ├── MotionPrimitive.cs                  # 恒曲率原语
│   │   ├── MotionPrimitiveGenerator.cs         # 原语积分
│   │   ├── HybridAStarNode.cs                  # 搜索节点
│   │   ├── HybridAStarNodeKey.cs               # Closed Set 键
│   │   ├── GoalToleranceChecker.cs             # 容差终点
│   │   ├── GridDijkstraHeuristic.cs            # 2D 启发
│   │   └── HybridAStarSearch.cs                # 搜索管理
│   ├── Output/
│   │   ├── PathBacktracker.cs                  # 恢复内部积分点
│   │   ├── CoarsePathAssembler.cs              # 弧长、换向、分段
│   │   └── CoarsePathValidator.cs              # 最终复核
│   ├── HybridAStarPlanner.cs                   # CoarsePath 唯一公共调用类
│   └── Test/
│       ├── CoarsePathScenarioFactory.cs        # 可复现场景
│       └── MovementTest.CoarsePathTest.cs      # 最后阶段的规划测试入口
└── README.md                                   # 两个门面类的调用说明

ClumsyPilot/tests/
├── verify_planning_utils.ps1
├── verify_planning_map_factory.ps1
├── verify_planning_map_adapter.ps1
├── verify_coarse_path_search.ps1
└── verify_coarse_path_integration.ps1
~~~

## 唯一调用方式

~~~csharp
var mapResult = new PlanningMapFactory().Create(new PlanningMapRequest
{
    ResolutionMm = 50f,
    ManualObstacles = manualObstacles,
    TwoLegInput = optionalTwoLegInput,
    AllowExplicitEmptyMap = true,
});

if (!mapResult.Succeeded)
    return PlanningResult.FromMapFailure(mapResult);

return new HybridAStarPlanner().Plan(new PlanningRequest
{
    Map = mapResult.Map,
    Start = startPose,
    Goal = goalPose,
    Vehicle = vehicle,
    Configuration = configuration,
});
~~~

调用方不得直接创建 EnvironmentMapBuilder、MapObstacleRasterizer、PlanningMapAdapter、碰撞检查器、原语生成器或搜索节点。

---

### Task 1：建立 Utils 与工具测试

**文件：**
- Create：Utils 下的 AngleMath.cs、UnitConverter.cs、CoordinateTransform.cs、NumericGuard.cs、GridIndex.cs
- Test：ClumsyPilot/tests/verify_planning_utils.ps1

**输出：** NormalizeRadians、ShortestSignedAngleDifference、MillimetersToMeters、DegreesToRadians、TransformLocalToWorld 和 GridIndex。

- [ ] 写失败测试：

~~~powershell
Assert-Equal 1.25 ([UnitConverter]::MillimetersToMeters([single]1250))
Assert-Near 0.0 ([AngleMath]::NormalizeRadians(6.283185307179586)) 1e-12
~~~

- [ ] 运行 verify_planning_utils.ps1；预期 FAIL，类型不存在。
- [ ] 实现 UnitConverter：

~~~csharp
public static double MillimetersToMeters(float millimeters) => millimeters / 1000d;
public static double DegreesToRadians(float degrees) => degrees * Math.PI / 180d;
~~~

- [ ] 构建并重跑脚本；预期 PASS。
- [ ] 提交：git add Utils 与 verify_planning_utils.ps1；git commit -m "feat: add planning utilities"。

### Task 2：定义 CoarsePath 契约与可调容差

**文件：**
- Create：CoarsePath/Contracts 下的 Pose2D、VehicleParameters、PlanningRequest、HybridAStarConfiguration、PlanningResult、PlanningStatus、PlanningDiagnostics、CoarsePathPoint、PathSegment。
- Test：verify_planning_utils.ps1

**输出：** 默认原语 0.50 m、积分 0.05 m、航向 5°、位置容差 0.15 m、航向容差 5°。

- [ ] 写失败测试，断言上述配置默认值和 Success、InvalidMap、StartInCollision、GoalInCollision、NoFeasiblePath 状态。
- [ ] 运行脚本；预期 FAIL，配置类型不存在。
- [ ] 实现不可变请求/结果契约；结果不得包含速度、加速度或时间。
- [ ] 构建并重跑脚本；预期 PASS。
- [ ] 提交：git add CoarsePath/Contracts 与 verify_planning_utils.ps1；git commit -m "feat: add coarse path contracts"。

### Task 3：实现外部障碍环境地图

**文件：**
- Create：Map/Core/EnvironmentGridMap.cs
- Create：Map/Obstacles 下的 IMapObstacle、AxisAlignedRectangleObstacle、CircleObstacle、MapObstacleRasterizer。
- Create：Map/Sources/ManualObstacleSource.cs
- Test：verify_planning_map_factory.ps1

**输出：** 矩形按中心/宽/高，圆按中心/半径栅格化；环境地图没有车辆足迹接口。

- [ ] 写失败测试，分别验证矩形中心、圆心、边界外占据和不存在 MarkVehicleFootprint。
- [ ] 运行脚本；预期 FAIL，地图和障碍物类型不存在。
- [ ] 实现轴对齐矩形与圆-格矩形相交栅格化。
- [ ] 构建并重跑脚本；预期 PASS。
- [ ] 提交：git add Map/Core Map/Obstacles Map/Sources/ManualObstacleSource.cs 和测试；git commit -m "feat: add external obstacle map"。

### Task 4：实现 TwoLeg 图层和 PlanningMapFactory

**文件：**
- Create：Map/Sources/TwoLegObstacleProjector.cs
- Create：Map/Core 下的 MapBuildRequest、EnvironmentMapBuildResult、EnvironmentMapBuilder。
- Create：Map 下的 PlanningMapRequest、PlanningMapBuildResult、PlanningMapFactory。
- Test：verify_planning_map_factory.ps1

**输出：** new PlanningMapFactory().Create(request) 是 Map 唯一公共入口；TwoLeg 失败不能删除人工地图。

- [ ] 写失败测试，验证人工地图成功时 TwoLegApplied 为 false 仍然成功。
- [ ] 运行脚本；预期 FAIL，PlanningMapFactory 不存在。
- [ ] 实现工厂：合并人工障碍与可选投影；TwoLegObstacleProjector 只产出 CircleObstacle。
- [ ] 构建并重跑脚本；预期 PASS。
- [ ] 提交：git add Map 与 verify_planning_map_factory.ps1；git commit -m "feat: add planning map factory"。

### Task 5：适配 PlanningGridMap 并生成距离场

**文件：**
- Create：Map/Planning 下的 PlanningGridMap、ObstacleDistanceField、PlanningMapAdapter。
- Modify：Map/PlanningMapFactory.cs
- Test：verify_planning_map_adapter.ps1

**输出：** 深拷贝占据格，mm 转 m，越界占据，生成最近障碍距离场。

- [ ] 写失败测试，断言 ResolutionMeters=0.05、障碍坐标转换、越界和障碍格距离为 0。
- [ ] 运行脚本；预期 FAIL，适配类型不存在。
- [ ] 实现 PlanningMapAdapter.Adapt(EnvironmentGridMap) 和多源距离场；显式空旷图使用正无穷距离。
- [ ] 构建并重跑脚本；预期 PASS。
- [ ] 提交：git add Map/Planning Map/PlanningMapFactory.cs 和测试；git commit -m "feat: adapt planning map"。

### Task 6：实现车辆足迹与碰撞检查

**文件：**
- Create：CoarsePath/Vehicle 下的 VehicleKinematics、HeadingFootprintTemplate、HeadingFootprintTemplateCache、FootprintCollisionChecker。
- Test：verify_coarse_path_search.ps1

**输出：** IsCollisionFree(Pose2D, PlanningGridMap, VehicleParameters, out clearanceMeters)。

- [ ] 写失败测试，覆盖占据碰撞、45° 安全、越界碰撞和不同航向。
- [ ] 运行脚本；预期 FAIL，碰撞类型不存在。
- [ ] 实现扩大车体模板；距离场仅在大于外接圆时放行，否则查询航向模板。
- [ ] 构建并重跑脚本；预期 PASS。
- [ ] 提交：git add CoarsePath/Vehicle 和测试；git commit -m "feat: add footprint collision checking"。

### Task 7：生成恒曲率运动原语

**文件：**
- Create：CoarsePath/Search/MotionPrimitive.cs、MotionPrimitiveGenerator.cs
- Test：verify_coarse_path_search.ps1

**输出：** 五级曲率、前进/倒车、最多 0.50 m、每步不超过 0.05 m、保留内部点。

- [ ] 写失败测试，覆盖直行 10 点、曲线航向变化、倒车和曲率跳变拒绝。
- [ ] 运行脚本；预期 FAIL，原语生成器不存在。
- [ ] 实现积分：

~~~csharp
x += directionSign * Math.Cos(theta) * stepMeters;
y += directionSign * Math.Sin(theta) * stepMeters;
theta = AngleMath.NormalizeRadians(theta + directionSign * curvature * stepMeters);
~~~

- [ ] 构建并重跑脚本；预期 PASS，所有内部点经过碰撞检查。
- [ ] 提交：git add 两个原语文件和测试；git commit -m "feat: add motion primitives"。

### Task 8：实现目标容差、启发和 Hybrid A* 搜索

**文件：**
- Create：CoarsePath/Search 下的 HybridAStarNode、HybridAStarNodeKey、GoalToleranceChecker、GridDijkstraHeuristic、HybridAStarSearch。
- Test：verify_coarse_path_search.ps1

**输出：** Closed Set 键为位置格、航向格、方向、曲率索引；终点读取可调容差。

- [ ] 写失败测试，无障碍前进、单障碍绕行、一次倒车、容差成功、无解和节点上限。
- [ ] 运行脚本；预期 FAIL，搜索类型不存在。
- [ ] 实现搜索循环：

~~~csharp
while (openList.Count > 0 && diagnostics.ExpandedNodeCount < configuration.MaxExpandedNodes)
{
    var current = PopBestValidNode();
    if (_goalChecker.IsReached(current.Pose, request.Goal, configuration, current.Direction))
        return SearchResult.Succeeded(current.NodeIndex);
    ExpandValidPrimitives(current);
}
~~~

- [ ] 构建并重跑脚本；预期 PASS。
- [ ] 提交：git add CoarsePath/Search 和测试；git commit -m "feat: add hybrid astar search"。

### Task 9：回溯、输出和 HybridAStarPlanner 门面

**文件：**
- Create：CoarsePath/Output 下的 PathBacktracker、CoarsePathAssembler、CoarsePathValidator。
- Create：CoarsePath/HybridAStarPlanner.cs
- Test：verify_coarse_path_integration.ps1

**输出：** new HybridAStarPlanner().Plan(request) 返回稠密路径、换向标记、分段、诊断和状态。

- [ ] 写失败测试，验证首点弧长为 0、内部点连续、换向标记、终点容差和最终复核。
- [ ] 运行脚本；预期 FAIL，门面不存在。
- [ ] 实现编排：

~~~csharp
var search = _search.Run(request);
if (!search.Succeeded) return PlanningResult.Failed(search.Status, search.Diagnostics);
var points = _assembler.Assemble(_backtracker.Backtrack(search));
return _validator.Validate(points, request)
    ? PlanningResult.Succeeded(points, search.Diagnostics)
    : PlanningResult.Failed(PlanningStatus.FinalValidationFailed, search.Diagnostics);
~~~

- [ ] 构建并重跑脚本；预期 PASS。
- [ ] 提交：git add CoarsePath/Output CoarsePath/HybridAStarPlanner.cs 和测试；git commit -m "feat: expose coarse path planner"。

### Task 10：完成非 UI 回归与调用说明

**文件：**
- Create：ParkrobTrajplanner/README.md
- Modify：全部 verify_planning 脚本。

- [ ] 写失败测试，断言 PlanningMapFactory 和 HybridAStarPlanner 是唯一由外部测试实例化的模块门面。
- [ ] 运行全部脚本；预期在 README、状态或门面断言未齐全时 FAIL。
- [ ] 在 README 写入 Map 到 Planner 的调用代码、mm/m-rad 边界和非目标。
- [ ] 构建、运行全部规划脚本并运行 git diff --check；预期全部 PASS。
- [ ] 提交：git add README 和 tests；git commit -m "test: complete coarse path regression coverage"。

### Task 11：最后编写 MovementTest 集成模块

**文件：**
- Create：Map/Test/MovementTest.MapTest.cs
- Create：CoarsePath/Test/CoarsePathScenarioFactory.cs
- Create：CoarsePath/Test/MovementTest.CoarsePathTest.cs
- Test：Clumsy UI 手动运行两个 MovementTest，然后重跑 Task 10 自动化回归。

**输出：** MapTest 只调用 PlanningMapFactory；CoarsePathTest 只调用两个门面；两者绝不发送底盘命令。

- [ ] 写失败测试，场景工厂生成的地图请求可由 PlanningMapFactory 构建，规划请求可由 HybridAStarPlanner 成功规划。
- [ ] 运行 verify_coarse_path_integration.ps1；预期 FAIL，场景工厂不存在。
- [ ] 实现入口：

~~~csharp
[MovementTest(name = "Hybrid A* 粗路径测试")]
public sealed class CoarsePathTest : MovementTest
{
    public override void Test()
    {
        var map = new PlanningMapFactory().Create(CoarsePathScenarioFactory.CreateSingleObstacleMapRequest());
        var result = map.Succeeded
            ? new HybridAStarPlanner().Plan(CoarsePathScenarioFactory.CreatePlanningRequest(map.Map))
            : PlanningResult.FromMapFailure(map);
        DrawMapAndPath(map, result);
    }
}
~~~

- [ ] MapTest 绘制人工矩形、人工圆、TwoLeg 投影和边界；CoarsePathTest 绘制起点、目标、路径、换向点和失败状态。TestStop 只清理 Painter/任务。
- [ ] 构建、运行全部 PowerShell 脚本，并在 Clumsy UI 手动运行“规划地图测试”和“Hybrid A* 粗路径测试”；预期只显示调试结果，不发送运动命令。
- [ ] 提交：git add Map/Test CoarsePath/Test 和 tests；git commit -m "feat: add coarse path movement tests"。

## 实施前检查

- PlanningMapFactory 与 HybridAStarPlanner 是未来调用方和测试入口唯一允许直接实例化的模块类。
- MovementTest 位于最后一个任务；它之前所有 Map 与搜索逻辑必须已完成非 UI 自动化验证。

