From 61dfa794d20cca47b0cce9cdb0f12dad900fc427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E8=96=84=E4=BA=91?= Date: Tue, 4 Aug 2026 00:22:36 +0800 Subject: [PATCH] docs: describe OSQP plugin deployment --- .../ParkrobTrajplanner/EMPlanner/README.md | 87 ++++++++++++++++++- .../EMPlannerVerificationHost/Program.cs | 6 +- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md b/ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md index ec59bf9..1c38ed5 100644 --- a/ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md +++ b/ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md @@ -12,7 +12,8 @@ PlanningGridMap -> Hybrid A* CoarsePath -> Local G2 PathSmoothing -> EM Planner `PlanningGridMap`、车辆几何和请求快照。它不读取硬件、UI、时钟或当前工作目录。 每次计算只处理一个 `DirectionSegmentView`,因此不会跨越换向边界。 -此门禁尚未实现 OSQP、LS 横向优化、ST 纵向优化、滚动协调、轨迹发布或动态障碍物。 +此门禁已提供 solver-neutral `IQpSolver` 契约和固定 OSQP 后端;尚未实现 LS 横向优化、 +ST 纵向优化、滚动协调、轨迹发布或动态障碍物。 ## 坐标与符号 @@ -82,3 +83,87 @@ PASS segmentation PASS frenet PASS corridor ``` + +## OSQP 后端部署与诊断 + +横向与纵向规划器只能依赖 `IQpSolver`、`QuadraticProgram`、`QpSolverSettings` 和 +`QpSolveResult`;它们不得依赖 OSQP 的 P/Invoke 类型。当前后端固定为 OSQP `v1.0.0`, +Windows x64、double precision、int32 索引、未打包 settings 和内置 QDLDL algebra。源包布局为: + +```text +ClumsyPilot/ThirdParty/OSQP/ +├── build-win-x64.ps1 +├── LICENSE +├── NOTICE +├── VERSION +├── SHA256SUMS +└── win-x64/osqp.dll +``` + +`VERSION` 记录且构建脚本强制使用以下开关: + +```text +OSQP_ALGEBRA_BACKEND=builtin +OSQP_BUILD_SHARED_LIB=ON +OSQP_BUILD_STATIC_LIB=OFF +OSQP_BUILD_DEMO_EXE=OFF +OSQP_BUILD_UNITTESTS=OFF +OSQP_USE_FLOAT=OFF +OSQP_USE_LONG=OFF +OSQP_PACK_SETTINGS=OFF +OSQP_ENABLE_PRINTING=OFF +OSQP_CODEGEN=OFF +OSQP_ENABLE_DERIVATIVES=OFF +``` + +最终插件发布布局(由后续插件打包阶段负责复制)必须为: + +```text +plugins/ +├── ClumsyPilot.dll +├── osqp.dll +└── licenses/ + ├── OSQP-LICENSE.txt + └── OSQP-NOTICE.txt +``` + +`OsqpNativeLoader` 只从 `typeof(OsqpNativeLoader).Assembly.Location` 所在目录以绝对路径 +预加载同级 `osqp.dll`,不读取当前工作目录,也不要求用户修改 `PATH`。它拒绝非 x64 +进程、缺失或无法加载的 DLL、缺少导出及非 `1.0.0` 版本,并以结构化 +`SolverUnavailable`/`NativeError` 结果返回;不会让宿主进程因加载失败而崩溃。所有 C API +委托均采用 Cdecl,原生 verbose 强制关闭。 + +每次 `OsqpNativeSolver.Solve` 独立拥有 P/Q/A/l/u 和可选 warm-start 的固定数组、CSC +包装、settings 和 OSQP workspace。它在 `finally` 中按反向顺序释放:先 `osqp_cleanup` +workspace,再释放 settings/CSC 块,最后释放托管数组 pin;加载后的模块句柄保留至进程生命周期结束。 + +原生状态映射固定如下: + +| OSQP status value | `QpSolveStatus` | +| ---: | --- | +| 1 | `Solved` | +| 2 | `SolvedInaccurate` | +| 3, 4 | `PrimalInfeasible` | +| 5, 6 | `DualInfeasible` | +| 7 | `MaximumIterations` | +| 8 | `TimeLimit` | +| 9, 10, 11 或未知值 | `NativeError` | + +`SolvedInaccurate` 只在后续规划器完成更严格的独立残差和领域复核后才可发布。调用前取消映射 +为 `Cancelled`;加载失败映射为 `SolverUnavailable`;OSQP setup、warm-start 或 solve API +返回错误时映射为 `NativeError`。 + +在仓库根目录运行 OSQP 回归门: + +```powershell +dotnet run --project ClumsyPilot/tests/EMPlannerVerificationHost/EMPlannerVerificationHost.csproj -- optimization +dotnet run --project ClumsyPilot/tests/EMPlannerVerificationHost/EMPlannerVerificationHost.csproj -- osqp +``` + +`osqp` 会在临时的干净插件目录中验证缺失 DLL、损坏 DLL、绝对路径加载、并发首次加载,以及 +有界最优、等式最优、不可行和极短时限 QP。成功时包含: + +```text +PASS osqp-solve +PASS osqp-loader +``` diff --git a/ClumsyPilot/tests/EMPlannerVerificationHost/Program.cs b/ClumsyPilot/tests/EMPlannerVerificationHost/Program.cs index fd07a15..1915e73 100644 --- a/ClumsyPilot/tests/EMPlannerVerificationHost/Program.cs +++ b/ClumsyPilot/tests/EMPlannerVerificationHost/Program.cs @@ -7,10 +7,10 @@ internal static class Program private static int Main(string[] args) { if (args.Length != 1 || (args[0] != "foundation" && args[0] != "segmentation" && args[0] != "frenet" && - args[0] != "corridor" && args[0] != "optimization" && args[0] != "osqp-loader" && args[0] != "osqp-probe" && + args[0] != "corridor" && args[0] != "optimization" && args[0] != "osqp" && args[0] != "osqp-loader" && args[0] != "osqp-probe" && args[0] != "all-foundation")) { - Console.Error.WriteLine("Usage: EMPlannerVerificationHost foundation|segmentation|frenet|corridor|optimization|osqp-loader|all-foundation"); + Console.Error.WriteLine("Usage: EMPlannerVerificationHost foundation|segmentation|frenet|corridor|optimization|osqp|osqp-loader|all-foundation"); return 2; } @@ -41,7 +41,7 @@ internal static class Program MultiWheelC.TrajectoryPlanning.EMPlanner.OptimizationChecks.Run(); Console.WriteLine("PASS optimization"); } - if (args[0] == "osqp-loader") + if (args[0] == "osqp" || args[0] == "osqp-loader") { MultiWheelC.TrajectoryPlanning.EMPlanner.OsqpChecks.Run(); Console.WriteLine("PASS osqp-loader");