docs: package EM observation dashboard
This commit is contained in:
@@ -213,6 +213,7 @@ dotnet run --project ClumsyPilot/tests/EMPlannerVerificationHost/EMPlannerVerifi
|
|||||||
```text
|
```text
|
||||||
plugins/
|
plugins/
|
||||||
├── ClumsyPilot.dll
|
├── ClumsyPilot.dll
|
||||||
|
├── TrajectoryPlanningVisualization.dll
|
||||||
├── osqp.dll
|
├── osqp.dll
|
||||||
└── licenses/
|
└── licenses/
|
||||||
├── OSQP-LICENSE.txt
|
├── OSQP-LICENSE.txt
|
||||||
@@ -220,7 +221,11 @@ plugins/
|
|||||||
└── OSQP-VERSION.txt
|
└── OSQP-VERSION.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
发布器会检查 64 位 PowerShell、原生 DLL 的 x64 PE 类型和固定 SHA-256。OSQP 加载器从托管程序集目录以绝对路径加载同级 `osqp.dll`;它不依赖 `PATH` 或当前工作目录。部署和执行职责的更多说明见 [TrajectoryExecution](../TrajectoryExecution/README.md)。
|
发布器只从显式 `ManagedDll` 的同级目录解析 `TrajectoryPlanningVisualization.dll`,先复制完整包到 staging,
|
||||||
|
再原子替换 `plugins` 目录;它不会搜索 `PATH` 或当前工作目录。发布器会检查 64 位 PowerShell、原生 DLL 的 x64 PE
|
||||||
|
类型和固定 SHA-256,并保留既有恢复行为。OSQP 加载器从托管程序集目录以绝对路径加载同级 `osqp.dll`;它不依赖
|
||||||
|
`PATH` 或当前工作目录。部署和执行职责的更多说明见 [TrajectoryExecution](../TrajectoryExecution/README.md),网页
|
||||||
|
观察的开关、token URL、图表语义和停止清理见 [EM trajectory observation MovementTest](../tarjplanner_movementtest/README.md)。
|
||||||
|
|
||||||
## 常见错误(Common Errors)
|
## 常见错误(Common Errors)
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,30 @@ rejected before EM planning.
|
|||||||
and must never be forwarded directly to a vehicle motion interface. This MovementTest performs no coordinate conversion
|
and must never be forwarded directly to a vehicle motion interface. This MovementTest performs no coordinate conversion
|
||||||
for driving and has no driving capability; any future execution mode requires a separate safety-reviewed design.
|
for driving and has no driving capability; any future execution mode requires a separate safety-reviewed design.
|
||||||
|
|
||||||
|
## 网页看板与可选 Painter
|
||||||
|
|
||||||
|
将 `EnableWebVisualization=true` 可启用本机网页看板;它只绑定 `127.0.0.1`,启动日志会给出完整的、带随机
|
||||||
|
会话令牌的 URL。端口为 `0` 时由系统选择可用回环端口;浏览器必须使用该完整 URL,不能删掉 token。默认
|
||||||
|
`AutoOpenWebVisualization=true` 会尝试打开默认浏览器;无桌面会话或打开失败只记录 URL,服务和观察循环继续运行。
|
||||||
|
网页默认以 `10 Hz` 发布不可变动态快照,网页关闭、断开或慢客户端只会丢弃网页帧,绝不会阻塞、序列化等待或改变
|
||||||
|
规划周期。
|
||||||
|
|
||||||
|
`EnableNativePainterVisualization=true` 才会为本会话创建 `TrajectoryObserver.World`、`LS`、`ST` Painter;默认关闭。
|
||||||
|
网页与 Painter 可以同时开启,也可全部关闭:全部关闭时仍保留 `OBSERVE_ONLY` 规划、控制台和 UI 状态。网页的启动、
|
||||||
|
快照或服务出现异常时会只记录一次中文诊断并熔断本次网页输出,不自动循环重启,也不会停止规划观察。
|
||||||
|
|
||||||
|
网页采用中文说明配合科研绘图约定:白底、细灰网格和细曲线;当前轨迹为蓝色实线,上一轮为灰色虚线,换向与交接点
|
||||||
|
为橙色,红色仅表示实际越界或失败。路径总览把已完成方向段画为灰色细实线、活动段画为蓝色细实线、未来段画为浅灰
|
||||||
|
虚线,并以深蓝覆盖当前规划视界。页面的 `ReferenceS (m)` 是将轨迹投影到**完整活动方向段**后的共享参考站;
|
||||||
|
`PathS (m)` 是每轮 ST 求解使用、从该轮局部起点累计的实际路径弧长,二者不可互相替代或跨轮直接相减。
|
||||||
|
|
||||||
|
运动学页中 `j[i]` 仅表示真实区间 `[tᵢ, tᵢ₊₁)`,所以 jerk 只有 `N-1` 个样本;末点之后没有虚构的 `j=0`。
|
||||||
|
状态页将滚动续航、接近停车边界和精确停车边界分别标为 `RollingContinuation`、
|
||||||
|
`ApproachStopBoundary`、`ExactStopAtBoundary`:前两者允许非零末端速度,只有真实边界才是精确停车锚点。换向高亮
|
||||||
|
仅会在投影位置满足容差、已连续停车保持 `GearSwitchStopHoldSeconds`,并取得
|
||||||
|
`DirectionConfirmationSamples` 个满足 `DirectionConfirmationSpeedMetersPerSecond` 阈值的下一方向带符号速度样本后,
|
||||||
|
严格从 `N -> N+1` 前进。
|
||||||
|
|
||||||
## Operator launch and stop checklist
|
## Operator launch and stop checklist
|
||||||
|
|
||||||
The vehicle UI entry is `EM轨迹规划观察闭环测试`. It is an observation session only; it has no chassis,
|
The vehicle UI entry is `EM轨迹规划观察闭环测试`. It is an observation session only; it has no chassis,
|
||||||
@@ -97,6 +121,8 @@ command is diagnostic information only and must not be copied into a vehicle-con
|
|||||||
|
|
||||||
To stop, use the vehicle UI's normal MovementTest stop action. Confirm the status says
|
To stop, use the vehicle UI's normal MovementTest stop action. Confirm the status says
|
||||||
`Observation stop requested; all observer layers were cleared.` The cancellation request stops observer work and clears
|
`Observation stop requested; all observer layers were cleared.` The cancellation request stops observer work and clears
|
||||||
all three layers. A current-session runtime fault also clears all three layers so stale active diagnostics are not left
|
an existing Painter, stops the web publisher/HTTP/SSE service, and releases its port. A current-session runtime fault
|
||||||
on screen; an intentional bootstrap failure preserves its diagnostic world view. Stopping, running, or starting this
|
also clears an existing Painter and stops the web session so stale diagnostics are not left on screen; an intentional
|
||||||
test must not issue chassis, motor, steering, brake, or gear output.
|
bootstrap failure still reports through UI/console even when both visualization modes are off. Closing a browser tab does
|
||||||
|
not stop the session; `TestStop()` owns final web and Painter cleanup. Stopping, running, or starting this test must not
|
||||||
|
issue chassis, motor, steering, brake, or gear output.
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ if (Test-SamePath $outputDirectoryPath $workspaceRoot) {
|
|||||||
if (-not [System.IO.File]::Exists($managedDllPath)) {
|
if (-not [System.IO.File]::Exists($managedDllPath)) {
|
||||||
throw "Managed DLL does not exist: $managedDllPath"
|
throw "Managed DLL does not exist: $managedDllPath"
|
||||||
}
|
}
|
||||||
|
$visualizationDll = Join-Path ([System.IO.Path]::GetDirectoryName($managedDllPath)) 'TrajectoryPlanningVisualization.dll'
|
||||||
|
if (-not [System.IO.File]::Exists($visualizationDll)) {
|
||||||
|
throw "Visualization DLL does not exist beside managed DLL: $visualizationDll"
|
||||||
|
}
|
||||||
if (-not [System.Environment]::Is64BitProcess) {
|
if (-not [System.Environment]::Is64BitProcess) {
|
||||||
throw 'Refusing to publish from a non-x64 PowerShell host.'
|
throw 'Refusing to publish from a non-x64 PowerShell host.'
|
||||||
}
|
}
|
||||||
@@ -89,6 +93,7 @@ $movedExistingPlugins = $false
|
|||||||
try {
|
try {
|
||||||
[System.IO.Directory]::CreateDirectory((Join-Path $stagingDirectory 'licenses')) | Out-Null
|
[System.IO.Directory]::CreateDirectory((Join-Path $stagingDirectory 'licenses')) | Out-Null
|
||||||
[System.IO.File]::Copy($managedDllPath, (Join-Path $stagingDirectory 'ClumsyPilot.dll'), $false)
|
[System.IO.File]::Copy($managedDllPath, (Join-Path $stagingDirectory 'ClumsyPilot.dll'), $false)
|
||||||
|
[System.IO.File]::Copy($visualizationDll, (Join-Path $stagingDirectory 'TrajectoryPlanningVisualization.dll'), $false)
|
||||||
[System.IO.File]::Copy($nativeDll, (Join-Path $stagingDirectory 'osqp.dll'), $false)
|
[System.IO.File]::Copy($nativeDll, (Join-Path $stagingDirectory 'osqp.dll'), $false)
|
||||||
[System.IO.File]::Copy($license, (Join-Path $stagingDirectory 'licenses\OSQP-LICENSE.txt'), $false)
|
[System.IO.File]::Copy($license, (Join-Path $stagingDirectory 'licenses\OSQP-LICENSE.txt'), $false)
|
||||||
[System.IO.File]::Copy($notice, (Join-Path $stagingDirectory 'licenses\OSQP-NOTICE.txt'), $false)
|
[System.IO.File]::Copy($notice, (Join-Path $stagingDirectory 'licenses\OSQP-NOTICE.txt'), $false)
|
||||||
|
|||||||
@@ -83,14 +83,20 @@ internal static class PluginPackagingChecks
|
|||||||
relativeFiles.Add(Path.GetRelativePath(packageRoot, files[index]).Replace('\\', '/'));
|
relativeFiles.Add(Path.GetRelativePath(packageRoot, files[index]).Replace('\\', '/'));
|
||||||
relativeFiles.Sort(StringComparer.Ordinal);
|
relativeFiles.Sort(StringComparer.Ordinal);
|
||||||
|
|
||||||
Verification.Equal("plugins/ClumsyPilot.dll|plugins/licenses/OSQP-LICENSE.txt|plugins/licenses/OSQP-NOTICE.txt|" +
|
Verification.Equal("plugins/ClumsyPilot.dll|plugins/TrajectoryPlanningVisualization.dll|" +
|
||||||
"plugins/licenses/OSQP-VERSION.txt|plugins/osqp.dll", string.Join("|", relativeFiles),
|
"plugins/licenses/OSQP-LICENSE.txt|plugins/licenses/OSQP-NOTICE.txt|plugins/licenses/OSQP-VERSION.txt|" +
|
||||||
"plugin tree contains exactly the managed DLL, native DLL, and OSQP license files");
|
"plugins/osqp.dll", string.Join("|", relativeFiles),
|
||||||
|
"plugin tree contains exactly the managed DLLs, native DLL, and OSQP license files");
|
||||||
|
|
||||||
string managedPlugin = Path.Combine(pluginsDirectory, "ClumsyPilot.dll");
|
string managedPlugin = Path.Combine(pluginsDirectory, "ClumsyPilot.dll");
|
||||||
AssemblyName managedAssembly = AssemblyName.GetAssemblyName(managedPlugin);
|
AssemblyName managedAssembly = AssemblyName.GetAssemblyName(managedPlugin);
|
||||||
Verification.True(!string.IsNullOrWhiteSpace(managedAssembly.Name), "packaged ClumsyPilot.dll is managed");
|
Verification.True(!string.IsNullOrWhiteSpace(managedAssembly.Name), "packaged ClumsyPilot.dll is managed");
|
||||||
|
|
||||||
|
string visualizationPlugin = Path.Combine(pluginsDirectory, "TrajectoryPlanningVisualization.dll");
|
||||||
|
AssemblyName visualizationAssembly = AssemblyName.GetAssemblyName(visualizationPlugin);
|
||||||
|
Verification.Equal("TrajectoryPlanningVisualization", visualizationAssembly.Name,
|
||||||
|
"packaged visualization DLL has the expected managed assembly name");
|
||||||
|
|
||||||
string nativePlugin = Path.Combine(pluginsDirectory, "osqp.dll");
|
string nativePlugin = Path.Combine(pluginsDirectory, "osqp.dll");
|
||||||
Verification.Equal((ushort)0x8664, ReadPeMachine(nativePlugin), "packaged OSQP binary is x64");
|
Verification.Equal((ushort)0x8664, ReadPeMachine(nativePlugin), "packaged OSQP binary is x64");
|
||||||
Verification.Equal(ReadExpectedOsqpHash(repositoryRoot), GetSha256(nativePlugin),
|
Verification.Equal(ReadExpectedOsqpHash(repositoryRoot), GetSha256(nativePlugin),
|
||||||
|
|||||||
Reference in New Issue
Block a user