test: verify EM observation movement test

This commit is contained in:
梁薄云
2026-08-04 16:57:16 +08:00
parent ea043ea0a6
commit 417f8ca9ea
2 changed files with 54 additions and 0 deletions
@@ -48,3 +48,26 @@ rejected before EM planning.
`EmTrajectoryPoint.VelocityX` and `VelocityY` are world-frame components. They are not chassis-frame velocity commands
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.
## Operator launch and stop checklist
The vehicle UI entry is `EM杞ㄨ抗瑙勫垝瑙傚療闂幆娴嬭瘯`. It is an observation session only; it has no chassis,
motor, steering, brake, or gear output.
Before starting:
1. Ensure the vehicle is in a safe, supervised state; this test reads live localization and signed chassis speed but
never controls the vehicle.
2. Confirm localization and the chassis read interface are available. The session reports a startup failure if either
cannot be read.
3. Set a finite goal X/Y/yaw (or be ready to enter them when prompted), then enter zero to twenty manual obstacles.
Each obstacle must remain inside the configured start/goal rectangle plus map padding.
To start, select the entry in the vehicle UI and start the MovementTest. Confirm the status begins with
`OBSERVE_ONLY: no chassis command is sent.`, then review the bootstrap status and the
`TrajectoryObserver.World`, `TrajectoryObserver.LS`, and `TrajectoryObserver.ST` layers. A logged trajectory control
command is diagnostic information only and must not be copied into a vehicle-control interface.
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
all three layers. Stopping, running, or starting this test must not issue chassis, motor, steering, brake, or gear output.
@@ -25,6 +25,7 @@ internal static class TrajectoryObservationChecks
VerifiesLsPresentationUsesPathSOnHorizontalAxis();
VerifiesRollingRequestUsesOnePublishedTrajectorySnapshot();
FreezesBootstrapVehicleForRollingRequests();
VerifiesEmptyMapBootstrapProducesPublishableReference();
}
private static void VerifiesObservationSourceHasNoActuatorCalls()
@@ -259,6 +260,36 @@ internal static class TrajectoryObservationChecks
expectedMaximumCurvature, expectedMinimumRadius, "replaced bootstrap job vehicle");
}
private static void VerifiesEmptyMapBootstrapProducesPublishableReference()
{
var settings = new TrajectoryObservationSettings();
CoarsePathPlanningJob job = TrajectoryObservationSetupFactory.CreateBootstrapJob(
new Pose2D(0.5d, 0.5d, 0d), new Pose2D(3.5d, 0.5d, 0d), settings,
Array.Empty<TrajectoryObservationObstacle>(), 0L);
TrajectoryObservationBootstrapResult bootstrap = new TrajectoryObservationBootstrapper()
.Bootstrap(job, CancellationToken.None);
Verification.True(bootstrap.Succeeded, "observer empty-map bootstrap succeeds");
Verification.True(bootstrap.CoarseResult.MapResult.Succeeded,
"observer empty-map bootstrap builds a successful map");
Verification.True(bootstrap.Map != null, "observer empty-map bootstrap returns a map");
Verification.Equal(PlanningStatus.Success, bootstrap.CoarseResult.PlanningResult.Status,
"observer empty-map coarse planning succeeds");
Verification.True(bootstrap.SmoothedPath != null && IsPublishableSmoothingStatus(bootstrap.SmoothedPath.Status),
"observer empty-map bootstrap returns a publishable smoothing result");
Verification.True(bootstrap.Segments.Count > 0,
"observer empty-map bootstrap returns at least one direction segment");
}
private static bool IsPublishableSmoothingStatus(PathSmoothingStatus status)
{
return status == PathSmoothingStatus.Complete ||
status == PathSmoothingStatus.PartialImprovement ||
status == PathSmoothingStatus.NotNeeded ||
status == PathSmoothingStatus.Unchanged;
}
private static void AssertVehicleSnapshot(VehicleParameters actual, double expectedLength, double expectedWidth,
double expectedMargin, double? expectedMaximumCurvature, double? expectedMinimumRadius, string name)
{