diff --git a/ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/README.md b/ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/README.md index 47c184e..73c680f 100644 --- a/ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/README.md +++ b/ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/README.md @@ -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. diff --git a/ClumsyPilot/tests/EMPlannerVerificationHost/TrajectoryObservationChecks.cs b/ClumsyPilot/tests/EMPlannerVerificationHost/TrajectoryObservationChecks.cs index 7d1d33c..5de09a1 100644 --- a/ClumsyPilot/tests/EMPlannerVerificationHost/TrajectoryObservationChecks.cs +++ b/ClumsyPilot/tests/EMPlannerVerificationHost/TrajectoryObservationChecks.cs @@ -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(), 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) {