From 4058230eb8f5c9bc062592f71e6bce4bf81219a5 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 13:28:13 +0800 Subject: [PATCH] test: verify rolling EM execution --- .../ParkrobTrajplanner/EMPlanner/README.md | 102 ++++++++++++ .../CoordinatorChecks.cs | 152 ++++++++++++++++++ .../ExecutorChecks.cs | 39 +++++ .../LateralIntegrationChecks.cs | 4 + .../EMPlannerVerificationHost/OsqpChecks.cs | 2 + .../EMPlannerVerificationHost/Program.cs | 39 +++-- 6 files changed, 322 insertions(+), 16 deletions(-) diff --git a/ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md b/ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md index 536d52b..7365100 100644 --- a/ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md +++ b/ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md @@ -343,3 +343,105 @@ PASS longitudinal-integration PASS trajectory PASS em-planning-service ``` + +## Rolling execution ownership and deployment + +The first-version boundary has three independently testable layers: + +```text +caller snapshots -> EmPlanningCoordinator -> immutable published EmTrajectory + -> TrajectoryExecutor -> TrajectoryControlCommand +``` + +- `EmPlanningService` remains a pure, synchronous, one-shot planner. It consumes only the request snapshot and never + reads a clock, current directory, UI, localization, wheel speed, or hardware object. +- The caller owns state capture, map/reference-path version selection, the replan clock, and any hardware-specific + action after it receives a generic command. `IVehicleStateProvider.Capture()` belongs to this execution boundary and + returns a `VehicleMotionState` snapshot; it is not a planner dependency. +- `EmPlanningCoordinator` owns latest-wins cycle cancellation and atomic publication. A cycle binds + `MapSnapshotId`, `ReferencePathId`, vehicle-state `SequenceId`, `PreviousTrajectoryId`, and `SegmentIndex`; a + result publishes only when that complete identity and its version are still current. The default update cadence is + `0.20 s` (with the configured `6.0 s` / `5.0 m` planning horizons). +- `TrajectoryExecutor` only samples the immutable published trajectory with caller-provided time and measured state. + It never extrapolates beyond the final point. A failed replan leaves the last complete published trajectory in + service through its exact zero-speed safety tail. + +### Handoff and gear changes + +A normal replan may use a future sample from the prior trajectory only when it is within the configured age and +position/yaw/speed tracking tolerances, remains in the same segment and direction, and does not cross a gear boundary. +Unsafe tracking, stale data, a terminal boundary, or any segment/direction mismatch causes a deterministic reset to +the caller-supplied measured state with no trajectory seed. + +At an exact `GearSwitchApproach` boundary the executor follows this sequence: + +```text +Following -> ApproachingGearSwitch -> HoldingZero +-> RequestingDirectionChange (one request) -> AwaitingDirectionConfirmation -> Following +``` + +Measured absolute speed must remain below `0.01 m/s` continuously for `0.20 s` before the single direction-change +request. Every holding, direction-confirmation, rolling-stop, and goal-completion command is zero speed and zero yaw +rate. `Goal` and `RollingSafetyStop` leave the executor completed while braking is held. + +### Trajectory telemetry and generic command + +Every `EmTrajectoryPoint` retains these fields for execution telemetry and independent validation: + +```text +X, Y, Yaw, +SignedLongitudinalVelocity, Speed, VelocityX, VelocityY, YawRate, VehicleCurvature, +TimeFromStart, +SegmentIndex, SegmentLocalS, PathS, Direction, BoundaryType, +LongitudinalAcceleration, LongitudinalJerk +``` + +`SignedLongitudinalVelocity` is authoritative: `Speed = abs(signedV)`, world `VelocityX/Y` are derived from vehicle +yaw, and `YawRate = signedV * VehicleCurvature`. Pose, world velocity, speed, and curvature stay available in +`TrajectoryExecutionState.SelectedPoint`; they are monitoring telemetry, not controller inputs. + +`TrajectoryControlAdapter` produces only the controller-neutral immutable command below: + +```text +SignedLongitudinalVelocity +YawRate +Direction +RequestDirectionChange +HoldBrake +IsTrajectoryComplete +``` + +There is intentionally no body-lateral-velocity, crab-motion, in-place-rotation, UI, or hardware field. A later +hardware adapter may map this command only after that controller's field semantics are independently confirmed. + +### Windows x64 plugin package + +The build output carries the pinned OSQP runtime and notices. Create the deployable plugin tree from a built managed +assembly with an explicit destination that is neither a drive root nor the repository root: + +```powershell +& .\ClumsyPilot\scripts\Publish-ClumsyPilotPlugin.ps1 ` + -ManagedDll .\ClumsyPilot\bin\Debug\netstandard2.0\ClumsyPilot.dll ` + -OutputDirectory C:\deploy\ParkingRobot +``` + +The transactional publisher verifies a 64-bit PowerShell host, the OSQP PE machine type, and the pinned +`ThirdParty/OSQP/SHA256SUMS` hash before staging and renaming exactly: + +```text +plugins/ClumsyPilot.dll +plugins/osqp.dll +plugins/licenses/OSQP-LICENSE.txt +plugins/licenses/OSQP-NOTICE.txt +plugins/licenses/OSQP-VERSION.txt +``` + +Run the complete first-version gate from the repository root: + +```powershell +dotnet run --project ClumsyPilot/tests/EMPlannerVerificationHost/EMPlannerVerificationHost.csproj -- em-all +``` + +Dynamic-obstacle prediction, time-space occupancy, following/yielding/overtaking behavior, dynamic rerouting, +body-lateral motion, in-place rotation, UI integration, and hardware integration are explicitly deferred and are not +implemented by this first version. diff --git a/ClumsyPilot/tests/EMPlannerVerificationHost/CoordinatorChecks.cs b/ClumsyPilot/tests/EMPlannerVerificationHost/CoordinatorChecks.cs index 5d5ca15..4c1d33e 100644 --- a/ClumsyPilot/tests/EMPlannerVerificationHost/CoordinatorChecks.cs +++ b/ClumsyPilot/tests/EMPlannerVerificationHost/CoordinatorChecks.cs @@ -19,6 +19,14 @@ internal static class CoordinatorChecks VerifiesSafePreviousTrajectoryHandoffs(); } + public static void RunRollingEndToEnd() + { + VerifiesLatestCycleWinsAndEveryIdentityFieldSuppressesStaleResults(); + VerifiesSafePreviousTrajectoryHandoffs(); + VerifiesPublishedForwardAndReverseCommands(); + VerifiesFailureLeavesPublishedZeroSpeedTailExecutable(); + } + private static void VerifiesCallerSuppliedSchedulingDecision() { var service = new ControlledPlanningService(); @@ -177,6 +185,142 @@ internal static class CoordinatorChecks "coordinator consumes only its published immutable trajectory"); } + private static void VerifiesPublishedForwardAndReverseCommands() + { + DateTimeOffset effectiveAt = DateTimeOffset.UnixEpoch.AddSeconds(800d); + var service = new ControlledPlanningService(); + var coordinator = new EmPlanningCoordinator(service); + var executor = new TrajectoryExecutor(); + + PlanningCycleInput forwardInput = CreateInput(CreateMap(30), "rolling-reference", 90L, string.Empty, 6, + "rolling-forward", effectiveAt, null, CreateMeasuredState(0d, 0d, 0d, 0.10d, effectiveAt, 90L)); + EmTrajectory forward = CreateExecutionTrajectory("rolling-forward", TravelDirection.Forward, effectiveAt, + EmBoundaryType.RollingSafetyStop, EmTerminalType.RollingSafetyStop); + PlanningCycleResult forwardResult = Publish(service, coordinator, forwardInput, forward); + Verification.True(forwardResult.Published, "first forward rolling cycle publishes"); + TrajectoryControlCommand forwardCommand = executor.UpdateCommand(effectiveAt, + forwardInput.Request.VehicleState, coordinator.PublishedTrajectory, TravelDirection.Forward, + TravelDirection.Forward, false); + AssertPublishedMotion(forwardCommand, coordinator.PublishedTrajectory.Points[0], "forward rolling command"); + + PlanningCycleInput forwardRepeat = CreateInput(CreateMap(31), "rolling-reference", 91L, "rolling-forward", 6, + "rolling-forward-repeat", effectiveAt.AddSeconds(0.20d), null, + CreateMeasuredState(0.02d, 0d, 0d, 0.10d, effectiveAt.AddSeconds(0.20d), 91L)); + EmTrajectory repeatedForward = CreateExecutionTrajectory("rolling-forward-repeat", TravelDirection.Forward, + effectiveAt.AddSeconds(0.20d), EmBoundaryType.RollingSafetyStop, EmTerminalType.RollingSafetyStop); + Publish(service, coordinator, forwardRepeat, repeatedForward); + Verification.Equal("rolling-forward-repeat", coordinator.PublishedTrajectory.Metadata.TrajectoryId, + "repeated forward replan replaces only the published trajectory"); + + PlanningCycleInput reverseInput = CreateInput(CreateMap(32), "rolling-reference", 92L, + "rolling-forward-repeat", 7, "rolling-reverse", effectiveAt.AddSeconds(0.40d), null, + CreateMeasuredState(0d, 0d, 0d, -0.10d, effectiveAt.AddSeconds(0.40d), 92L)); + EmTrajectory reverse = CreateExecutionTrajectory("rolling-reverse", TravelDirection.Reverse, + effectiveAt.AddSeconds(0.40d), EmBoundaryType.Goal, EmTerminalType.Goal); + PlanningCycleResult reverseResult = Publish(service, coordinator, reverseInput, reverse); + Verification.True(reverseResult.Published, "reverse rolling cycle publishes"); + TrajectoryControlCommand reverseCommand = executor.UpdateCommand(effectiveAt.AddSeconds(0.40d), + reverseInput.Request.VehicleState, coordinator.PublishedTrajectory, TravelDirection.Reverse, + TravelDirection.Reverse, false); + AssertPublishedMotion(reverseCommand, coordinator.PublishedTrajectory.Points[0], "reverse rolling command"); + Verification.True(reverseCommand.SignedLongitudinalVelocity < 0d, + "reverse rolling command preserves negative longitudinal velocity"); + + PlanningCycleInput unsafeTracking = CreateInput(CreateMap(32), "rolling-reference", 93L, "rolling-reverse", 7, + "unsafe-tracking", effectiveAt.AddSeconds(0.41d), CreateHandoffConfiguration(), + CreateMeasuredState(5d, 0d, 0d, -0.10d, effectiveAt.AddSeconds(0.41d), 93L)); + TrajectoryHandoffSelection reset = coordinator.SelectHandoff(unsafeTracking, TravelDirection.Reverse); + Verification.Equal(TrajectoryHandoffSource.MeasuredState, reset.Source, + "unsafe tracking resets rolling handoff to caller measurement"); + Verification.True(object.ReferenceEquals(unsafeTracking.Request.VehicleState, reset.StartState), + "unsafe tracking preserves the supplied measurement snapshot"); + } + + private static void VerifiesFailureLeavesPublishedZeroSpeedTailExecutable() + { + DateTimeOffset effectiveAt = DateTimeOffset.UnixEpoch.AddSeconds(900d); + var service = new ControlledPlanningService(); + var coordinator = new EmPlanningCoordinator(service); + var executor = new TrajectoryExecutor(); + PlanningCycleInput successfulInput = CreateInput(CreateMap(40), "tail-reference", 100L, string.Empty, 8, + "tail-published", effectiveAt, null, CreateMeasuredState(0d, 0d, 0d, 0.10d, effectiveAt, 100L)); + EmTrajectory published = CreateExecutionTrajectory("tail-published", TravelDirection.Forward, effectiveAt, + EmBoundaryType.RollingSafetyStop, EmTerminalType.RollingSafetyStop); + Publish(service, coordinator, successfulInput, published); + + for (int attempt = 1; attempt <= 2; attempt++) + { + DateTimeOffset now = effectiveAt.AddSeconds(0.20d * attempt); + PlanningCycleInput failedInput = CreateInput(CreateMap(40 + attempt), "tail-reference", 100L + attempt, + "tail-published", 8, "tail-failed-" + attempt, now, null, + CreateMeasuredState(0.02d, 0d, 0d, 0.10d, now, 100L + attempt)); + Task failedCycle = coordinator.PlanLatestAsync(failedInput, CancellationToken.None); + service.WaitUntilStarted(failedInput.Request.OutputTrajectoryId); + service.Fail(failedInput.Request.OutputTrajectoryId); + PlanningCycleResult failure = failedCycle.GetAwaiter().GetResult(); + Verification.Equal(EmPlanningStatus.Failed, failure.Result.Status, "failed replan status " + attempt); + Verification.True(!failure.Published, "failed replan cannot publish " + attempt); + Verification.True(object.ReferenceEquals(published, coordinator.PublishedTrajectory), + "failed replan retains the complete prior trajectory " + attempt); + } + + TrajectoryControlCommand beforeTail = executor.UpdateCommand(effectiveAt.AddSeconds(0.10d), + CreateMeasuredState(0.10d, 0d, 0d, 0.10d, effectiveAt.AddSeconds(0.10d), 103L), + coordinator.PublishedTrajectory, TravelDirection.Forward, TravelDirection.Forward, false); + Verification.True(beforeTail.SignedLongitudinalVelocity > 0d, + "old trajectory remains executable before its safety tail"); + + TrajectoryControlCommand atTail = executor.UpdateCommand(effectiveAt.AddSeconds(0.30d), + CreateMeasuredState(0d, 0d, 0d, 0d, effectiveAt.AddSeconds(0.30d), 104L), coordinator.PublishedTrajectory, + TravelDirection.Forward, TravelDirection.Forward, false); + TrajectoryControlCommand afterTail = executor.UpdateCommand(effectiveAt.AddSeconds(10d), + CreateMeasuredState(0d, 0d, 0d, 0d, effectiveAt.AddSeconds(10d), 105L), coordinator.PublishedTrajectory, + TravelDirection.Forward, TravelDirection.Forward, false); + AssertZeroTail(atTail, "exact rolling safety-stop terminal"); + AssertZeroTail(afterTail, "after rolling safety-stop terminal"); + } + + private static PlanningCycleResult Publish(ControlledPlanningService service, EmPlanningCoordinator coordinator, + PlanningCycleInput input, EmTrajectory trajectory) + { + Task cycle = coordinator.PlanLatestAsync(input, CancellationToken.None); + service.WaitUntilStarted(input.Request.OutputTrajectoryId); + service.Complete(input.Request.OutputTrajectoryId, trajectory); + return cycle.GetAwaiter().GetResult(); + } + + private static EmTrajectory CreateExecutionTrajectory(string trajectoryId, TravelDirection direction, + DateTimeOffset effectiveAt, EmBoundaryType terminalBoundary, EmTerminalType terminalType) + { + double signedVelocity = direction == TravelDirection.Forward ? 0.10d : -0.10d; + var metadata = new EmTrajectoryMetadata(trajectoryId, effectiveAt, effectiveAt, 110L, "rolling-reference", 100L, + string.Empty, 8, direction, terminalType); + return new EmTrajectory(metadata, new[] + { + new EmTrajectoryPoint(0d, 0d, 0d, signedVelocity, 0d, 0.20d, 8, 0d, 0d, direction, + EmBoundaryType.None, 0d, 0d), + new EmTrajectoryPoint(signedVelocity * 3d, 0d, 0d, 0d, 0.30d, 0.20d, 8, 0.03d, 0.03d, direction, + terminalBoundary, 0d, 0d), + }); + } + + private static void AssertPublishedMotion(TrajectoryControlCommand command, EmTrajectoryPoint point, string name) + { + Verification.NearlyEqual(point.SignedLongitudinalVelocity, command.SignedLongitudinalVelocity, + name + " originates from the currently published trajectory"); + Verification.NearlyEqual(point.YawRate, command.YawRate, + name + " preserves the currently published trajectory yaw rate"); + Verification.True(!command.HoldBrake && !command.IsTrajectoryComplete, + name + " is neither a brake hold nor an extrapolated completion command"); + } + + private static void AssertZeroTail(TrajectoryControlCommand command, string name) + { + Verification.NearlyEqual(0d, command.SignedLongitudinalVelocity, name + " signed velocity"); + Verification.NearlyEqual(0d, command.YawRate, name + " yaw rate"); + Verification.True(command.HoldBrake && command.IsTrajectoryComplete, name + " holds a completed trajectory"); + } + private static void AssertHandoffRejected(TrajectoryHandoffSelector selector, EmTrajectory trajectory, VehicleMotionState measuredState, int segmentIndex, TravelDirection direction, DateTimeOffset now, EmPlannerConfiguration configuration, TrajectoryHandoffRejectionReason reason, string name) @@ -320,6 +464,14 @@ internal static class CoordinatorChecks cycle.Completion.TrySetResult(result); } + public void Fail(string outputTrajectoryId) + { + PendingCycle cycle; + lock (gate) + cycle = pending[outputTrajectoryId]; + cycle.Completion.TrySetResult(new EmPlanningResult(EmPlanningStatus.Failed, null, "scripted rolling failure")); + } + private static EmPlanningResult CreateSuccess(EmPlanningRequest request) { var metadata = new EmTrajectoryMetadata(request.OutputTrajectoryId, request.RequestedAtUtc, request.EffectiveAtUtc, diff --git a/ClumsyPilot/tests/EMPlannerVerificationHost/ExecutorChecks.cs b/ClumsyPilot/tests/EMPlannerVerificationHost/ExecutorChecks.cs index 1b47221..9a54a77 100644 --- a/ClumsyPilot/tests/EMPlannerVerificationHost/ExecutorChecks.cs +++ b/ClumsyPilot/tests/EMPlannerVerificationHost/ExecutorChecks.cs @@ -15,6 +15,15 @@ internal static class ExecutorChecks VerifiesVehicleStateProviderRemainsSnapshotOnly(); } + public static void RunRollingEndToEnd() + { + VerifiesGearSwitchSequence(TravelDirection.Forward, TravelDirection.Reverse, + "end-to-end forward-to-reverse"); + VerifiesGearSwitchSequence(TravelDirection.Reverse, TravelDirection.Forward, + "end-to-end reverse-to-forward"); + VerifiesGoalCommandStopsAtAndAfterTerminal(); + } + private static void VerifiesGearSwitchSequence(TravelDirection currentDirection, TravelDirection desiredDirection, string name) { @@ -191,6 +200,36 @@ internal static class ExecutorChecks Verification.Equal(84L, provider.Capture().SequenceId, "vehicle state provider returns caller-owned snapshot"); } + private static void VerifiesGoalCommandStopsAtAndAfterTerminal() + { + DateTimeOffset effectiveAt = DateTimeOffset.UnixEpoch.AddSeconds(950d); + EmTrajectory goalTrajectory = CreateMotionTrajectory(effectiveAt, TravelDirection.Forward, 0.10d, 0.20d); + var executor = new TrajectoryExecutor(); + VehicleMotionState moving = CreateMeasuredState(0.10d, effectiveAt, 95L); + TrajectoryControlCommand following = executor.UpdateCommand(effectiveAt, moving, goalTrajectory, + TravelDirection.Forward, TravelDirection.Forward, false); + Verification.NearlyEqual(goalTrajectory.Points[0].SignedLongitudinalVelocity, following.SignedLongitudinalVelocity, + "goal approach command originates from trajectory point"); + Verification.NearlyEqual(goalTrajectory.Points[0].YawRate, following.YawRate, + "goal approach command preserves trajectory yaw rate"); + + TrajectoryControlCommand atGoal = executor.UpdateCommand(effectiveAt.AddSeconds(0.30d), + CreateMeasuredState(0d, effectiveAt.AddSeconds(0.30d), 96L), goalTrajectory, TravelDirection.Forward, + TravelDirection.Forward, false); + TrajectoryControlCommand afterGoal = executor.UpdateCommand(effectiveAt.AddSeconds(5d), + CreateMeasuredState(0d, effectiveAt.AddSeconds(5d), 97L), goalTrajectory, TravelDirection.Forward, + TravelDirection.Forward, false); + AssertCompletedCommand(atGoal, "exact goal terminal command"); + AssertCompletedCommand(afterGoal, "after goal terminal command"); + } + + private static void AssertCompletedCommand(TrajectoryControlCommand command, string name) + { + Verification.NearlyEqual(0d, command.SignedLongitudinalVelocity, name + " signed velocity"); + Verification.NearlyEqual(0d, command.YawRate, name + " yaw rate"); + Verification.True(command.HoldBrake && command.IsTrajectoryComplete, name + " holds completed trajectory"); + } + private static void AssertHeld(GearSwitchStateUpdate update, GearSwitchState expectedState, string name) { Verification.Equal(expectedState, update.State, name + " state"); diff --git a/ClumsyPilot/tests/EMPlannerVerificationHost/LateralIntegrationChecks.cs b/ClumsyPilot/tests/EMPlannerVerificationHost/LateralIntegrationChecks.cs index 04f20da..671e9d9 100644 --- a/ClumsyPilot/tests/EMPlannerVerificationHost/LateralIntegrationChecks.cs +++ b/ClumsyPilot/tests/EMPlannerVerificationHost/LateralIntegrationChecks.cs @@ -48,7 +48,11 @@ internal static class LateralIntegrationChecks { Directory.CreateDirectory(pluginDirectory); foreach (string sourcePath in Directory.GetFiles(AppContext.BaseDirectory)) + { + if (string.Equals(Path.GetFileName(sourcePath), "osqp.dll", StringComparison.OrdinalIgnoreCase)) + continue; File.Copy(sourcePath, Path.Combine(pluginDirectory, Path.GetFileName(sourcePath)), false); + } string nativeSource = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "ClumsyPilot", "ThirdParty", "OSQP", "win-x64", "osqp.dll")); Verification.True(File.Exists(nativeSource), "pinned OSQP DLL is available for the real lateral bundle"); diff --git a/ClumsyPilot/tests/EMPlannerVerificationHost/OsqpChecks.cs b/ClumsyPilot/tests/EMPlannerVerificationHost/OsqpChecks.cs index c878e11..26b60f1 100644 --- a/ClumsyPilot/tests/EMPlannerVerificationHost/OsqpChecks.cs +++ b/ClumsyPilot/tests/EMPlannerVerificationHost/OsqpChecks.cs @@ -86,6 +86,8 @@ internal static class OsqpChecks string[] hostFiles = Directory.GetFiles(sourceDirectory); for (int index = 0; index < hostFiles.Length; index++) { + if (string.Equals(Path.GetFileName(hostFiles[index]), "osqp.dll", StringComparison.OrdinalIgnoreCase)) + continue; string destinationPath = Path.Combine(destinationDirectory, Path.GetFileName(hostFiles[index])); File.Copy(hostFiles[index], destinationPath, false); } diff --git a/ClumsyPilot/tests/EMPlannerVerificationHost/Program.cs b/ClumsyPilot/tests/EMPlannerVerificationHost/Program.cs index dd2fb82..535c3c1 100644 --- a/ClumsyPilot/tests/EMPlannerVerificationHost/Program.cs +++ b/ClumsyPilot/tests/EMPlannerVerificationHost/Program.cs @@ -13,40 +13,40 @@ internal static class Program args[0] != "longitudinal-model" && args[0] != "longitudinal-integration" && args[0] != "longitudinal-real-osqp-probe" && args[0] != "trajectory" && args[0] != "em-planning-service" && args[0] != "em-core-all" && args[0] != "coordinator" && - args[0] != "executor" && args[0] != "plugin-package")) + args[0] != "executor" && args[0] != "plugin-package" && args[0] != "em-all")) { - Console.Error.WriteLine("Usage: EMPlannerVerificationHost foundation|segmentation|frenet|corridor|optimization|osqp|osqp-loader|all-foundation|lateral-model|lateral-integration|lateral-real-osqp|lateral-all|longitudinal-model|longitudinal-integration"); + Console.Error.WriteLine("Usage: EMPlannerVerificationHost foundation|segmentation|frenet|corridor|optimization|osqp|osqp-loader|all-foundation|lateral-model|lateral-integration|lateral-real-osqp|lateral-all|longitudinal-model|longitudinal-integration|em-core-all|coordinator|executor|plugin-package|em-all"); return 2; } try { - if (args[0] == "foundation" || args[0] == "all-foundation") + if (args[0] == "foundation" || args[0] == "all-foundation" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.FoundationChecks.Run(); Console.WriteLine("PASS foundation"); } - if (args[0] == "segmentation" || args[0] == "all-foundation") + if (args[0] == "segmentation" || args[0] == "all-foundation" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.SegmentationChecks.Run(); Console.WriteLine("PASS segmentation"); } - if (args[0] == "frenet" || args[0] == "all-foundation") + if (args[0] == "frenet" || args[0] == "all-foundation" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.FrenetChecks.Run(); Console.WriteLine("PASS frenet"); } - if (args[0] == "corridor" || args[0] == "all-foundation") + if (args[0] == "corridor" || args[0] == "all-foundation" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.CorridorChecks.Run(); Console.WriteLine("PASS corridor"); } - if (args[0] == "optimization") + if (args[0] == "optimization" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.OptimizationChecks.Run(); Console.WriteLine("PASS optimization"); } - if (args[0] == "osqp" || args[0] == "osqp-loader") + if (args[0] == "osqp" || args[0] == "osqp-loader" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.OsqpChecks.Run(); Console.WriteLine("PASS osqp-loader"); @@ -55,12 +55,12 @@ internal static class Program { MultiWheelC.TrajectoryPlanning.EMPlanner.OsqpChecks.RunProbe(); } - if (args[0] == "lateral-model" || args[0] == "lateral-all") + if (args[0] == "lateral-model" || args[0] == "lateral-all" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.LateralModelChecks.Run(); Console.WriteLine("PASS lateral-model"); } - if (args[0] == "lateral-integration" || args[0] == "lateral-all") + if (args[0] == "lateral-integration" || args[0] == "lateral-all" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.LateralIntegrationChecks.Run(); Console.WriteLine("PASS lateral-integration"); @@ -70,7 +70,7 @@ internal static class Program MultiWheelC.TrajectoryPlanning.EMPlanner.LateralIntegrationChecks.RunRealOsqp(); Console.WriteLine("PASS lateral-real-osqp"); } - if (args[0] == "lateral-real-osqp" || args[0] == "lateral-all") + if (args[0] == "lateral-real-osqp" || args[0] == "lateral-all" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.LateralIntegrationChecks.RunRealOsqpInCleanPluginBundle(); Console.WriteLine("PASS lateral-real-osqp"); @@ -95,9 +95,9 @@ internal static class Program MultiWheelC.TrajectoryPlanning.EMPlanner.TrajectoryChecks.Run(); Console.WriteLine("PASS trajectory"); } - if (args[0] == "em-planning-service" || args[0] == "em-core-all") + if (args[0] == "em-planning-service" || args[0] == "em-core-all" || args[0] == "em-all") { - if (args[0] == "em-core-all") + if (args[0] == "em-core-all" || args[0] == "em-all") { MultiWheelC.TrajectoryPlanning.EMPlanner.LongitudinalModelChecks.Run(); Console.WriteLine("PASS longitudinal-model"); @@ -109,21 +109,28 @@ internal static class Program MultiWheelC.TrajectoryPlanning.EMPlanner.EmPlanningServiceChecks.Run(); Console.WriteLine("PASS em-planning-service"); } - if (args[0] == "coordinator") + if (args[0] == "coordinator" || args[0] == "em-all") { CoordinatorChecks.Run(); Console.WriteLine("PASS coordinator"); } - if (args[0] == "executor") + if (args[0] == "executor" || args[0] == "em-all") { ExecutorChecks.Run(); Console.WriteLine("PASS executor"); } - if (args[0] == "plugin-package") + if (args[0] == "plugin-package" || args[0] == "em-all") { PluginPackagingChecks.Run(); Console.WriteLine("PASS plugin-package"); } + if (args[0] == "em-all") + { + CoordinatorChecks.RunRollingEndToEnd(); + Console.WriteLine("PASS rolling-end-to-end"); + ExecutorChecks.RunRollingEndToEnd(); + Console.WriteLine("PASS rolling-execution-tail"); + } return 0; } catch (Exception exception)