feat: configure MovementTest ST time controls
This commit is contained in:
+6
@@ -33,6 +33,10 @@ public sealed class TrajectoryObservationMovementTest : MovementTest
|
|||||||
public double ObserverPeriodSeconds = 0.05d;
|
public double ObserverPeriodSeconds = 0.05d;
|
||||||
public double SolverTimeoutSeconds = 0.50d;
|
public double SolverTimeoutSeconds = 0.50d;
|
||||||
public int MaximumOsqpIterations = 12000;
|
public int MaximumOsqpIterations = 12000;
|
||||||
|
/// <summary>单次 ST 轨迹覆盖的未来时长,单位 s;默认 6s,不等于观察循环周期。</summary>
|
||||||
|
public double TimeHorizonSeconds = 6d;
|
||||||
|
/// <summary>Trajectory 相邻 TimeFromStart 时间戳的间隔,单位 s;默认 0.10s,不等于观察循环周期。</summary>
|
||||||
|
public double OutputTimeStepSeconds = 0.10d;
|
||||||
public double VehicleLengthMeters = 0.80d;
|
public double VehicleLengthMeters = 0.80d;
|
||||||
public double VehicleWidthMeters = 0.60d;
|
public double VehicleWidthMeters = 0.60d;
|
||||||
public double SafetyMarginMeters = 0.05d;
|
public double SafetyMarginMeters = 0.05d;
|
||||||
@@ -63,6 +67,8 @@ public sealed class TrajectoryObservationMovementTest : MovementTest
|
|||||||
ObserverPeriodSeconds = ObserverPeriodSeconds,
|
ObserverPeriodSeconds = ObserverPeriodSeconds,
|
||||||
SolverTimeoutSeconds = SolverTimeoutSeconds,
|
SolverTimeoutSeconds = SolverTimeoutSeconds,
|
||||||
MaximumOsqpIterations = MaximumOsqpIterations,
|
MaximumOsqpIterations = MaximumOsqpIterations,
|
||||||
|
TimeHorizonSeconds = TimeHorizonSeconds,
|
||||||
|
OutputTimeStepSeconds = OutputTimeStepSeconds,
|
||||||
VehicleLengthMeters = VehicleLengthMeters,
|
VehicleLengthMeters = VehicleLengthMeters,
|
||||||
VehicleWidthMeters = VehicleWidthMeters,
|
VehicleWidthMeters = VehicleWidthMeters,
|
||||||
SafetyMarginMeters = SafetyMarginMeters,
|
SafetyMarginMeters = SafetyMarginMeters,
|
||||||
|
|||||||
+11
@@ -14,6 +14,10 @@ public sealed class TrajectoryObservationSettings
|
|||||||
public double ObserverPeriodSeconds { get; set; } = 0.05d;
|
public double ObserverPeriodSeconds { get; set; } = 0.05d;
|
||||||
public double SolverTimeoutSeconds { get; set; } = 0.50d;
|
public double SolverTimeoutSeconds { get; set; } = 0.50d;
|
||||||
public int MaximumOsqpIterations { get; set; } = 12000;
|
public int MaximumOsqpIterations { get; set; } = 12000;
|
||||||
|
/// <summary>单次 ST 轨迹覆盖的未来时长,单位 s;不等于观察循环周期。</summary>
|
||||||
|
public double TimeHorizonSeconds { get; set; } = 6d;
|
||||||
|
/// <summary>发布 Trajectory 相邻 TimeFromStart 时间戳的间隔,单位 s;不等于观察循环周期。</summary>
|
||||||
|
public double OutputTimeStepSeconds { get; set; } = 0.10d;
|
||||||
public double VehicleLengthMeters { get; set; } = 0.80d;
|
public double VehicleLengthMeters { get; set; } = 0.80d;
|
||||||
public double VehicleWidthMeters { get; set; } = 0.60d;
|
public double VehicleWidthMeters { get; set; } = 0.60d;
|
||||||
public double SafetyMarginMeters { get; set; } = 0.05d;
|
public double SafetyMarginMeters { get; set; } = 0.05d;
|
||||||
@@ -29,6 +33,8 @@ public sealed class TrajectoryObservationSettings
|
|||||||
ObserverPeriodSeconds = ObserverPeriodSeconds,
|
ObserverPeriodSeconds = ObserverPeriodSeconds,
|
||||||
SolverTimeoutSeconds = SolverTimeoutSeconds,
|
SolverTimeoutSeconds = SolverTimeoutSeconds,
|
||||||
MaximumOsqpIterations = MaximumOsqpIterations,
|
MaximumOsqpIterations = MaximumOsqpIterations,
|
||||||
|
TimeHorizonSeconds = TimeHorizonSeconds,
|
||||||
|
OutputTimeStepSeconds = OutputTimeStepSeconds,
|
||||||
VehicleLengthMeters = VehicleLengthMeters,
|
VehicleLengthMeters = VehicleLengthMeters,
|
||||||
VehicleWidthMeters = VehicleWidthMeters,
|
VehicleWidthMeters = VehicleWidthMeters,
|
||||||
SafetyMarginMeters = SafetyMarginMeters,
|
SafetyMarginMeters = SafetyMarginMeters,
|
||||||
@@ -47,6 +53,11 @@ public sealed class TrajectoryObservationSettings
|
|||||||
EnsurePositiveFinite(SolverTimeoutSeconds, nameof(SolverTimeoutSeconds));
|
EnsurePositiveFinite(SolverTimeoutSeconds, nameof(SolverTimeoutSeconds));
|
||||||
if (MaximumOsqpIterations <= 0)
|
if (MaximumOsqpIterations <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(MaximumOsqpIterations), "Value must be positive.");
|
throw new ArgumentOutOfRangeException(nameof(MaximumOsqpIterations), "Value must be positive.");
|
||||||
|
EnsurePositiveFinite(TimeHorizonSeconds, nameof(TimeHorizonSeconds));
|
||||||
|
EnsurePositiveFinite(OutputTimeStepSeconds, nameof(OutputTimeStepSeconds));
|
||||||
|
if (OutputTimeStepSeconds > TimeHorizonSeconds)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(OutputTimeStepSeconds),
|
||||||
|
"The trajectory timestamp spacing cannot exceed the ST time horizon.");
|
||||||
EnsurePositiveFinite(VehicleLengthMeters, nameof(VehicleLengthMeters));
|
EnsurePositiveFinite(VehicleLengthMeters, nameof(VehicleLengthMeters));
|
||||||
EnsurePositiveFinite(VehicleWidthMeters, nameof(VehicleWidthMeters));
|
EnsurePositiveFinite(VehicleWidthMeters, nameof(VehicleWidthMeters));
|
||||||
EnsurePositiveFinite(SafetyMarginMeters, nameof(SafetyMarginMeters));
|
EnsurePositiveFinite(SafetyMarginMeters, nameof(SafetyMarginMeters));
|
||||||
|
|||||||
+2
@@ -209,6 +209,8 @@ public sealed class TrajectoryObservationController
|
|||||||
configuration.Scheduling.ReplanPeriodSeconds = settings.ReplanPeriodSeconds;
|
configuration.Scheduling.ReplanPeriodSeconds = settings.ReplanPeriodSeconds;
|
||||||
configuration.Scheduling.SolverTimeoutSeconds = settings.SolverTimeoutSeconds;
|
configuration.Scheduling.SolverTimeoutSeconds = settings.SolverTimeoutSeconds;
|
||||||
configuration.Solver.MaximumOsqpIterations = settings.MaximumOsqpIterations;
|
configuration.Solver.MaximumOsqpIterations = settings.MaximumOsqpIterations;
|
||||||
|
configuration.Scheduling.TimeHorizonSeconds = settings.TimeHorizonSeconds;
|
||||||
|
configuration.Scheduling.OutputTimeStepSeconds = settings.OutputTimeStepSeconds;
|
||||||
coordinator = new EmPlanningCoordinator(planningService);
|
coordinator = new EmPlanningCoordinator(planningService);
|
||||||
executor = new TrajectoryExecutor(configuration);
|
executor = new TrajectoryExecutor(configuration);
|
||||||
this.sessionId = sessionId;
|
this.sessionId = sessionId;
|
||||||
|
|||||||
@@ -110,6 +110,12 @@ internal static class TrajectoryObservationChecks
|
|||||||
"observer MovementTest exposes the test solver timeout default");
|
"observer MovementTest exposes the test solver timeout default");
|
||||||
Verification.True(source.Contains("public int MaximumOsqpIterations = 12000;"),
|
Verification.True(source.Contains("public int MaximumOsqpIterations = 12000;"),
|
||||||
"observer MovementTest exposes the test OSQP iteration default");
|
"observer MovementTest exposes the test OSQP iteration default");
|
||||||
|
Verification.True(source.Contains("public double TimeHorizonSeconds = 6d;"),
|
||||||
|
"observer MovementTest exposes the ST time-horizon default");
|
||||||
|
Verification.True(source.Contains("public double OutputTimeStepSeconds = 0.10d;"),
|
||||||
|
"observer MovementTest exposes the ST timestamp-spacing default");
|
||||||
|
Verification.True(source.Contains("不等于观察循环周期"),
|
||||||
|
"observer MovementTest documents the distinction between output timestamps and observer ticks");
|
||||||
Verification.True(source.Contains("VehicleLengthMeters = VehicleLengthMeters,"),
|
Verification.True(source.Contains("VehicleLengthMeters = VehicleLengthMeters,"),
|
||||||
"observer MovementTest copies vehicle length into settings");
|
"observer MovementTest copies vehicle length into settings");
|
||||||
Verification.True(source.Contains("VehicleWidthMeters = VehicleWidthMeters,"),
|
Verification.True(source.Contains("VehicleWidthMeters = VehicleWidthMeters,"),
|
||||||
@@ -122,6 +128,10 @@ internal static class TrajectoryObservationChecks
|
|||||||
"observer MovementTest copies solver timeout into settings");
|
"observer MovementTest copies solver timeout into settings");
|
||||||
Verification.True(source.Contains("MaximumOsqpIterations = MaximumOsqpIterations,"),
|
Verification.True(source.Contains("MaximumOsqpIterations = MaximumOsqpIterations,"),
|
||||||
"observer MovementTest copies OSQP iteration limit into settings");
|
"observer MovementTest copies OSQP iteration limit into settings");
|
||||||
|
Verification.True(source.Contains("TimeHorizonSeconds = TimeHorizonSeconds,"),
|
||||||
|
"observer MovementTest copies ST time horizon into settings");
|
||||||
|
Verification.True(source.Contains("OutputTimeStepSeconds = OutputTimeStepSeconds,"),
|
||||||
|
"observer MovementTest copies ST timestamp spacing into settings");
|
||||||
string normalizedSource = source.Replace("\r\n", "\n");
|
string normalizedSource = source.Replace("\r\n", "\n");
|
||||||
Verification.True(normalizedSource.Contains(
|
Verification.True(normalizedSource.Contains(
|
||||||
"VehicleMotionState state = ReadVehicleState();\n DateTimeOffset now = state.CapturedAtUtc;"),
|
"VehicleMotionState state = ReadVehicleState();\n DateTimeOffset now = state.CapturedAtUtc;"),
|
||||||
@@ -130,6 +140,10 @@ internal static class TrajectoryObservationChecks
|
|||||||
"observer settings use the test solver timeout default");
|
"observer settings use the test solver timeout default");
|
||||||
Verification.Equal(12000, new TrajectoryObservationSettings().MaximumOsqpIterations,
|
Verification.Equal(12000, new TrajectoryObservationSettings().MaximumOsqpIterations,
|
||||||
"observer settings use the test OSQP iteration default");
|
"observer settings use the test OSQP iteration default");
|
||||||
|
Verification.NearlyEqual(6d, new TrajectoryObservationSettings().TimeHorizonSeconds,
|
||||||
|
"observer settings use the ST time-horizon default");
|
||||||
|
Verification.NearlyEqual(0.10d, new TrajectoryObservationSettings().OutputTimeStepSeconds,
|
||||||
|
"observer settings use the ST timestamp-spacing default");
|
||||||
|
|
||||||
var configured = new TrajectoryObservationSettings
|
var configured = new TrajectoryObservationSettings
|
||||||
{
|
{
|
||||||
@@ -139,6 +153,8 @@ internal static class TrajectoryObservationChecks
|
|||||||
MaximumCurvaturePerMeter = 0.55d,
|
MaximumCurvaturePerMeter = 0.55d,
|
||||||
SolverTimeoutSeconds = 0.42d,
|
SolverTimeoutSeconds = 0.42d,
|
||||||
MaximumOsqpIterations = 9000,
|
MaximumOsqpIterations = 9000,
|
||||||
|
TimeHorizonSeconds = 4d,
|
||||||
|
OutputTimeStepSeconds = 0.20d,
|
||||||
};
|
};
|
||||||
TrajectoryObservationSettings snapshot = configured.CreateValidatedSnapshot();
|
TrajectoryObservationSettings snapshot = configured.CreateValidatedSnapshot();
|
||||||
configured.VehicleLengthMeters = 9.10d;
|
configured.VehicleLengthMeters = 9.10d;
|
||||||
@@ -147,6 +163,8 @@ internal static class TrajectoryObservationChecks
|
|||||||
configured.MaximumCurvaturePerMeter = 9.40d;
|
configured.MaximumCurvaturePerMeter = 9.40d;
|
||||||
configured.SolverTimeoutSeconds = 9.50d;
|
configured.SolverTimeoutSeconds = 9.50d;
|
||||||
configured.MaximumOsqpIterations = 9500;
|
configured.MaximumOsqpIterations = 9500;
|
||||||
|
configured.TimeHorizonSeconds = 5d;
|
||||||
|
configured.OutputTimeStepSeconds = 0.25d;
|
||||||
|
|
||||||
Verification.NearlyEqual(1.10d, snapshot.VehicleLengthMeters,
|
Verification.NearlyEqual(1.10d, snapshot.VehicleLengthMeters,
|
||||||
"observer settings snapshot freezes vehicle length");
|
"observer settings snapshot freezes vehicle length");
|
||||||
@@ -160,6 +178,10 @@ internal static class TrajectoryObservationChecks
|
|||||||
"observer settings snapshot freezes solver timeout");
|
"observer settings snapshot freezes solver timeout");
|
||||||
Verification.Equal(9000, snapshot.MaximumOsqpIterations,
|
Verification.Equal(9000, snapshot.MaximumOsqpIterations,
|
||||||
"observer settings snapshot freezes OSQP iteration limit");
|
"observer settings snapshot freezes OSQP iteration limit");
|
||||||
|
Verification.NearlyEqual(4d, snapshot.TimeHorizonSeconds,
|
||||||
|
"observer settings snapshot freezes ST time horizon");
|
||||||
|
Verification.NearlyEqual(0.20d, snapshot.OutputTimeStepSeconds,
|
||||||
|
"observer settings snapshot freezes ST timestamp spacing");
|
||||||
|
|
||||||
CoarsePathPlanningJob job = TrajectoryObservationSetupFactory.CreateBootstrapJob(
|
CoarsePathPlanningJob job = TrajectoryObservationSetupFactory.CreateBootstrapJob(
|
||||||
new Pose2D(0d, 0d, 0d), new Pose2D(1d, 0d, 0d), snapshot,
|
new Pose2D(0d, 0d, 0d), new Pose2D(1d, 0d, 0d), snapshot,
|
||||||
@@ -183,6 +205,13 @@ internal static class TrajectoryObservationChecks
|
|||||||
AssertInvalidSetting(settings => settings.SolverTimeoutSeconds = 0d, "solver timeout");
|
AssertInvalidSetting(settings => settings.SolverTimeoutSeconds = 0d, "solver timeout");
|
||||||
AssertInvalidSetting(settings => settings.MaximumOsqpIterations = 0, "OSQP iteration limit");
|
AssertInvalidSetting(settings => settings.MaximumOsqpIterations = 0, "OSQP iteration limit");
|
||||||
AssertInvalidSetting(settings => settings.MaximumOsqpIterations = -1, "negative OSQP iteration limit");
|
AssertInvalidSetting(settings => settings.MaximumOsqpIterations = -1, "negative OSQP iteration limit");
|
||||||
|
AssertInvalidSetting(settings => settings.TimeHorizonSeconds = 0d, "ST time horizon");
|
||||||
|
AssertInvalidSetting(settings => settings.OutputTimeStepSeconds = 0d, "ST timestamp spacing");
|
||||||
|
AssertInvalidSetting(settings =>
|
||||||
|
{
|
||||||
|
settings.TimeHorizonSeconds = 1d;
|
||||||
|
settings.OutputTimeStepSeconds = 1.01d;
|
||||||
|
}, "ST timestamp spacing larger than the horizon");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssertInvalidSetting(Action<TrajectoryObservationSettings> mutate, string name)
|
private static void AssertInvalidSetting(Action<TrajectoryObservationSettings> mutate, string name)
|
||||||
@@ -404,7 +433,12 @@ internal static class TrajectoryObservationChecks
|
|||||||
Verification.NearlyEqual(10.25d, charts.LsSamples[0].PathS, "observer first LS path S");
|
Verification.NearlyEqual(10.25d, charts.LsSamples[0].PathS, "observer first LS path S");
|
||||||
Verification.NearlyEqual(0.10d, charts.LsSamples[0].LateralOffset, "observer first LS offset");
|
Verification.NearlyEqual(0.10d, charts.LsSamples[0].LateralOffset, "observer first LS offset");
|
||||||
|
|
||||||
var settings = new TrajectoryObservationSettings { MaximumOsqpIterations = 9000 };
|
var settings = new TrajectoryObservationSettings
|
||||||
|
{
|
||||||
|
MaximumOsqpIterations = 9000,
|
||||||
|
TimeHorizonSeconds = 4d,
|
||||||
|
OutputTimeStepSeconds = 0.20d,
|
||||||
|
};
|
||||||
CoarsePathPlanningJob job = TrajectoryObservationSetupFactory.CreateBootstrapJob(
|
CoarsePathPlanningJob job = TrajectoryObservationSetupFactory.CreateBootstrapJob(
|
||||||
new Pose2D(0d, 0d, 0d), new Pose2D(1d, 0d, 0d), settings,
|
new Pose2D(0d, 0d, 0d), new Pose2D(1d, 0d, 0d), settings,
|
||||||
Array.Empty<TrajectoryObservationObstacle>(), 0L);
|
Array.Empty<TrajectoryObservationObstacle>(), 0L);
|
||||||
@@ -431,6 +465,12 @@ internal static class TrajectoryObservationChecks
|
|||||||
Verification.Equal(settings.MaximumOsqpIterations,
|
Verification.Equal(settings.MaximumOsqpIterations,
|
||||||
planningService.Requests[0].Configuration.Solver.MaximumOsqpIterations,
|
planningService.Requests[0].Configuration.Solver.MaximumOsqpIterations,
|
||||||
"observer configured OSQP iteration limit");
|
"observer configured OSQP iteration limit");
|
||||||
|
Verification.NearlyEqual(settings.TimeHorizonSeconds,
|
||||||
|
planningService.Requests[0].Configuration.Scheduling.TimeHorizonSeconds,
|
||||||
|
"observer configured ST time horizon");
|
||||||
|
Verification.NearlyEqual(settings.OutputTimeStepSeconds,
|
||||||
|
planningService.Requests[0].Configuration.Scheduling.OutputTimeStepSeconds,
|
||||||
|
"observer configured ST timestamp spacing");
|
||||||
|
|
||||||
TrajectoryObservationObservation observation = controller.Observe(effectiveAt.AddSeconds(0.5d), state);
|
TrajectoryObservationObservation observation = controller.Observe(effectiveAt.AddSeconds(0.5d), state);
|
||||||
Verification.NearlyEqual(0.5d, observation.SelectedPoint.TimeFromStart,
|
Verification.NearlyEqual(0.5d, observation.SelectedPoint.TimeFromStart,
|
||||||
|
|||||||
Reference in New Issue
Block a user