docs: describe OSQP plugin deployment

This commit is contained in:
梁薄云
2026-08-04 00:22:36 +08:00
parent a957fda6c5
commit 61dfa794d2
2 changed files with 89 additions and 4 deletions
@@ -12,7 +12,8 @@ PlanningGridMap -> Hybrid A* CoarsePath -> Local G2 PathSmoothing -> EM Planner
`PlanningGridMap`、车辆几何和请求快照。它不读取硬件、UI、时钟或当前工作目录。 `PlanningGridMap`、车辆几何和请求快照。它不读取硬件、UI、时钟或当前工作目录。
每次计算只处理一个 `DirectionSegmentView`,因此不会跨越换向边界。 每次计算只处理一个 `DirectionSegmentView`,因此不会跨越换向边界。
此门禁尚未实现 OSQP、LS 横向优化、ST 纵向优化、滚动协调、轨迹发布或动态障碍物。 此门禁已提供 solver-neutral `IQpSolver` 契约和固定 OSQP 后端;尚未实现 LS 横向优化、
ST 纵向优化、滚动协调、轨迹发布或动态障碍物。
## 坐标与符号 ## 坐标与符号
@@ -82,3 +83,87 @@ PASS segmentation
PASS frenet PASS frenet
PASS corridor 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
```
@@ -7,10 +7,10 @@ internal static class Program
private static int Main(string[] args) private static int Main(string[] args)
{ {
if (args.Length != 1 || (args[0] != "foundation" && args[0] != "segmentation" && args[0] != "frenet" && 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")) 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; return 2;
} }
@@ -41,7 +41,7 @@ internal static class Program
MultiWheelC.TrajectoryPlanning.EMPlanner.OptimizationChecks.Run(); MultiWheelC.TrajectoryPlanning.EMPlanner.OptimizationChecks.Run();
Console.WriteLine("PASS optimization"); Console.WriteLine("PASS optimization");
} }
if (args[0] == "osqp-loader") if (args[0] == "osqp" || args[0] == "osqp-loader")
{ {
MultiWheelC.TrajectoryPlanning.EMPlanner.OsqpChecks.Run(); MultiWheelC.TrajectoryPlanning.EMPlanner.OsqpChecks.Run();
Console.WriteLine("PASS osqp-loader"); Console.WriteLine("PASS osqp-loader");