33constexpr float kRadiusTolerance{1e-2f};
34constexpr float kLocationTolerance{1e-3f};
36void ExpectLocationNear(
40 EXPECT_NEAR(actual.
x, expected.
x, tolerance);
41 EXPECT_NEAR(actual.
y, expected.
y, tolerance);
42 EXPECT_NEAR(actual.
z, expected.
z, tolerance);
51TEST(TrafficManagerGeometry, ThreePointCircleRadius_EquilateralTriangle) {
53 constexpr float side{6.0f};
54 const float expected_radius{side / std::sqrt(3.0f)};
58 const cg::Location p3{side / 2.0f, side * std::sqrt(3.0f) / 2.0f, 0.0f};
60 const float radius{GetThreePointCircleRadius(p1, p2, p3)};
61 EXPECT_NEAR(radius, expected_radius, kRadiusTolerance);
64TEST(TrafficManagerGeometry, ThreePointCircleRadius_RightTriangle) {
71 const float radius{GetThreePointCircleRadius(p1, p2, p3)};
72 EXPECT_NEAR(radius, 2.5f, kRadiusTolerance);
75TEST(TrafficManagerGeometry, ThreePointCircleRadius_NearlyCollinearReturnsLarge) {
84 const float radius{GetThreePointCircleRadius(p1, p2, p3)};
86 EXPECT_LT(radius, std::numeric_limits<float>::max());
89TEST(TrafficManagerGeometry, ThreePointCircleRadius_PerfectlyCollinearReturnsMax) {
97 const float radius{GetThreePointCircleRadius(p1, p2, p3)};
98 EXPECT_EQ(radius, std::numeric_limits<float>::max());
105TEST(TrafficManagerInterpolation, InterpolateBufferAt_EmptyBufferReturnsVehicleLocation) {
106 const std::vector<cg::Location> empty;
109 const auto [location, index] = InterpolateBufferAt(empty, 5.0f, vehicle_location);
110 ExpectLocationNear(location, vehicle_location, kLocationTolerance);
111 EXPECT_EQ(index, 0u);
114TEST(TrafficManagerInterpolation, InterpolateBufferAt_SingleElementReturnsThatElement) {
115 const std::vector<cg::Location> single{{7.0f, 0.0f, 0.0f}};
118 const auto [location, index] = InterpolateBufferAt(single, 5.0f, vehicle_location);
119 ExpectLocationNear(location, single.front(), kLocationTolerance);
120 EXPECT_EQ(index, 0u);
123TEST(TrafficManagerInterpolation, InterpolateBufferAt_LinearInterpBetweenTwoPoints) {
126 const std::vector<cg::Location> buffer{
128 {10.0f, 0.0f, 0.0f}};
131 const auto [location, index] = InterpolateBufferAt(buffer, 5.0f, vehicle_location);
132 ExpectLocationNear(location,
cg::Location{5.0f, 0.0f, 0.0f}, kLocationTolerance);
133 EXPECT_EQ(index, 0u);
136TEST(TrafficManagerInterpolation, InterpolateBufferAt_DistanceShorterThanFirstWaypoint) {
141 const std::vector<cg::Location> buffer{
143 {20.0f, 0.0f, 0.0f}};
146 const auto [location, index] = InterpolateBufferAt(buffer, 3.0f, vehicle_location);
150 ExpectLocationNear(location,
cg::Location{3.0f, 0.0f, 0.0f}, kLocationTolerance);
151 EXPECT_EQ(index, 0u);
154TEST(TrafficManagerInterpolation, InterpolateBufferAt_DistanceBeyondLastWaypoint) {
157 const std::vector<cg::Location> buffer{
163 const auto [location, index] = InterpolateBufferAt(buffer, 100.0f, vehicle_location);
164 ExpectLocationNear(location, buffer.back(), kLocationTolerance);
165 EXPECT_EQ(index, buffer.size() - 1u);
168TEST(TrafficManagerInterpolation, InterpolateBufferAt_BracketBetweenLastTwoWaypoints) {
172 const std::vector<cg::Location> buffer{
175 {100.0f, 0.0f, 0.0f}};
178 const auto [location, index] = InterpolateBufferAt(buffer, 10.0f, vehicle_location);
182 ExpectLocationNear(location,
cg::Location{10.0f, 0.0f, 0.0f}, kLocationTolerance);
183 EXPECT_EQ(index, 1u);
186TEST(TrafficManagerInterpolation, InterpolateBufferAt_CoincidentBracketReturnsClosest) {
189 const std::vector<cg::Location> buffer{
192 {15.0f, 0.0f, 0.0f}};
195 const auto [location, index] = InterpolateBufferAt(buffer, 5.0f, vehicle_location);
196 ExpectLocationNear(location,
cg::Location{5.0f, 0.0f, 0.0f}, kLocationTolerance);
197 EXPECT_EQ(index, 0u);
206constexpr float kSampleSpacing{5.0f};
207constexpr float kLateralAcceleration{3.0f};
208constexpr float kBrakingDeceleration{2.0f};
209constexpr float kFreeSpeed{30.0f};
212std::vector<cg::Location> StraightThenArc(
213 float straight_length,
218 std::vector<cg::Location> path;
219 for (
float s = 0.0f; s < straight_length; s += spacing) {
222 const cg::Location centre{straight_length, radius, 0.0f};
223 const float arc_radians = arc_degrees * 3.14159265f / 180.0f;
224 for (
float travelled = 0.0f; travelled <= radius * arc_radians; travelled += spacing) {
225 const float angle = travelled / radius;
226 path.push_back(
cg::Location{centre.
x + radius * std::sin(angle),
227 centre.y - radius * std::cos(angle),
235TEST(TrafficManagerPathSpeed, PathSpeedLimit_StraightPathIsNotLimited) {
236 const std::vector<cg::Location> path{
237 {0.0f, 0.0f, 0.0f}, {5.0f, 0.0f, 0.0f}, {10.0f, 0.0f, 0.0f},
238 {15.0f, 0.0f, 0.0f}, {20.0f, 0.0f, 0.0f}};
241 GetPathSpeedLimit(path, 0.0f, kSampleSpacing, kLateralAcceleration,
242 kBrakingDeceleration, kFreeSpeed),
246TEST(TrafficManagerPathSpeed, PathSpeedLimit_ShortPathIsNotLimited) {
247 const std::vector<cg::Location> path{{0.0f, 0.0f, 0.0f}, {5.0f, 0.0f, 0.0f}};
250 GetPathSpeedLimit(path, 0.0f, kSampleSpacing, kLateralAcceleration,
251 kBrakingDeceleration, kFreeSpeed),
255TEST(TrafficManagerPathSpeed, PathSpeedLimit_ArcUnderfootAllowsItsOwnSpeed) {
256 const float radius = 11.0f;
257 const std::vector<cg::Location> path = StraightThenArc(0.0f, radius, 120.0f, kSampleSpacing);
260 GetPathSpeedLimit(path, 0.0f, kSampleSpacing, kLateralAcceleration,
261 kBrakingDeceleration, kFreeSpeed),
262 std::sqrt(radius * kLateralAcceleration),
266TEST(TrafficManagerPathSpeed, PathSpeedLimit_HoldsSteadyAsAnArcIsConsumed) {
267 const float radius = 11.0f;
268 const std::vector<cg::Location> path = StraightThenArc(0.0f, radius, 180.0f, kSampleSpacing);
270 std::vector<float> limits;
271 for (
size_t consumed = 0u; consumed < 4u; ++consumed) {
272 for (
float offset = 0.0f; offset < kSampleSpacing; offset += 1.0f) {
273 const std::vector<cg::Location> remaining(path.begin() +
static_cast<long>(consumed),
276 GetPathSpeedLimit(remaining, -offset, kSampleSpacing, kLateralAcceleration,
277 kBrakingDeceleration, kFreeSpeed));
281 const auto [lowest, highest] = std::minmax_element(limits.begin(), limits.end());
282 EXPECT_LT(*highest - *lowest, 0.35f) <<
"limit swings by " << (*highest - *lowest) <<
" m/s";
285TEST(TrafficManagerPathSpeed, PathSpeedLimit_AllowsMoreSpeedFurtherFromTheTurn) {
286 const float radius = 11.0f;
287 const std::vector<cg::Location> near_path = StraightThenArc(10.0f, radius, 90.0f, kSampleSpacing);
288 const std::vector<cg::Location> far_path = StraightThenArc(40.0f, radius, 90.0f, kSampleSpacing);
290 const float near_limit = GetPathSpeedLimit(
291 near_path, 0.0f, kSampleSpacing, kLateralAcceleration, kBrakingDeceleration, kFreeSpeed);
292 const float far_limit = GetPathSpeedLimit(
293 far_path, 0.0f, kSampleSpacing, kLateralAcceleration, kBrakingDeceleration, kFreeSpeed);
295 EXPECT_GT(far_limit, near_limit);
296 EXPECT_GT(near_limit, std::sqrt(radius * kLateralAcceleration));
299TEST(TrafficManagerPathSpeed, PathSpeedLimit_TighterTurnAllowsLessSpeed) {
301 constexpr float kJunctionSpacing{2.0f};
302 const std::vector<cg::Location> tight = StraightThenArc(0.0f, 6.0f, 120.0f, kJunctionSpacing);
303 const std::vector<cg::Location> open = StraightThenArc(0.0f, 25.0f, 120.0f, kJunctionSpacing);
306 GetPathSpeedLimit(tight, 0.0f, kSampleSpacing, kLateralAcceleration,
307 kBrakingDeceleration, kFreeSpeed),
308 GetPathSpeedLimit(open, 0.0f, kSampleSpacing, kLateralAcceleration,
309 kBrakingDeceleration, kFreeSpeed));
312TEST(TrafficManagerPathSpeed, PathSpeedLimit_PathShorterThanTwoSamplesIsNotLimited) {
313 const std::vector<cg::Location> stub = StraightThenArc(0.0f, 6.0f, 60.0f, 2.0f);
314 ASSERT_LT(stub.size() * 2.0f, 2.0f * kSampleSpacing);
317 GetPathSpeedLimit(stub, 0.0f, kSampleSpacing, kLateralAcceleration,
318 kBrakingDeceleration, kFreeSpeed),
322TEST(TrafficManagerPathSpeed, PathSpeedLimit_NonPositiveSpacingIsNotLimited) {
323 const std::vector<cg::Location> path = StraightThenArc(0.0f, 6.0f, 120.0f, 2.0f);
326 GetPathSpeedLimit(path, 0.0f, 0.0f, kLateralAcceleration, kBrakingDeceleration, kFreeSpeed),
330TEST(TrafficManagerPathSpeed, PathSpeedLimit_ArcBehindTheVehicleIsNotCreditedWithBraking) {
331 const float radius = 11.0f;
332 const std::vector<cg::Location> path = StraightThenArc(0.0f, radius, 180.0f, kSampleSpacing);
334 const float behind = GetPathSpeedLimit(
335 path, -kSampleSpacing, kSampleSpacing, kLateralAcceleration, kBrakingDeceleration,
337 const float ahead = GetPathSpeedLimit(
338 path, kSampleSpacing, kSampleSpacing, kLateralAcceleration, kBrakingDeceleration,
341 EXPECT_NEAR(behind, std::sqrt(radius * kLateralAcceleration), 0.1f);
342 EXPECT_GT(ahead, behind);
351constexpr float kProfileMaxOffset{2.0f};
352constexpr float kProfileMaxOffsetPoint{0.3f};
353constexpr float kProfileInboardScale{0.25f};
354constexpr float kProfileTolerance{1e-3f};
356float SampleProfile(
float t,
float inboard_scale) {
358 t, kProfileMaxOffset, kProfileMaxOffsetPoint, inboard_scale);
363TEST(TrafficManagerWideTurn, OffsetProfile_ZeroAtEntryAndExit) {
366 EXPECT_NEAR(SampleProfile(0.0f, kProfileInboardScale), 0.0f, kProfileTolerance);
367 EXPECT_NEAR(SampleProfile(1.0f, kProfileInboardScale), 0.0f, kProfileTolerance);
370TEST(TrafficManagerWideTurn, OffsetProfile_OutboardSwingReachesFullMagnitude) {
374 const float outboard{SampleProfile(1.0f - kProfileMaxOffsetPoint, kProfileInboardScale)};
375 EXPECT_NEAR(outboard, -kProfileMaxOffset, kProfileTolerance);
378TEST(TrafficManagerWideTurn, OffsetProfile_InboardExcursionIsCapped) {
382 const float inboard_cap{kProfileInboardScale * kProfileMaxOffset};
383 for (
int i = 0; i <= 100; ++i) {
384 const float t{
static_cast<float>(i) / 100.0f};
385 const float offset{SampleProfile(t, kProfileInboardScale)};
386 EXPECT_LE(offset, inboard_cap + kProfileTolerance);
387 EXPECT_GE(offset, -kProfileMaxOffset - kProfileTolerance);
391TEST(TrafficManagerWideTurn, OffsetProfile_ZeroInboardScaleRemovesCutIn) {
394 for (
int i = 0; i <= 100; ++i) {
395 const float t{
static_cast<float>(i) / 100.0f};
396 EXPECT_LE(SampleProfile(t, 0.0f), kProfileTolerance);
406constexpr float kRefLength{6.0f};
407constexpr float kOffsetGain{0.25f};
408constexpr float kOffsetCap{1.5f};
410float SampleMagnitude(
float length) {
416TEST(TrafficManagerWideTurn, OffsetMagnitude_ZeroAtOrBelowReferenceLength) {
417 EXPECT_NEAR(SampleMagnitude(kRefLength), 0.0f, kProfileTolerance);
418 EXPECT_NEAR(SampleMagnitude(kRefLength - 2.0f), 0.0f, kProfileTolerance);
421TEST(TrafficManagerWideTurn, OffsetMagnitude_RampsThenClampsToCap) {
423 EXPECT_NEAR(SampleMagnitude(8.0f), 0.5f, kProfileTolerance);
424 EXPECT_NEAR(SampleMagnitude(12.0f), kOffsetCap, kProfileTolerance);
425 EXPECT_NEAR(SampleMagnitude(20.0f), kOffsetCap, kProfileTolerance);
428TEST(TrafficManagerWideTurn, OffsetMagnitude_MonotonicNonDecreasingInLength) {
429 float previous{SampleMagnitude(0.0f)};
430 for (
float length = 0.0f; length <= 20.0f; length += 0.5f) {
431 const float current{SampleMagnitude(length)};
432 EXPECT_GE(current, previous - kProfileTolerance);
447constexpr float kOffsetMagnitude{1.5f};
448constexpr float kLateralClearance{1.0f};
449constexpr float kLongitudinalWindow{5.0f};
451bool SampleOccupied(
const std::vector<std::pair<cg::Location, float>> &neighbours) {
464TEST(TrafficManagerWideTurn, OffsetSideOccupied_EmptyNeighboursIsClear) {
465 EXPECT_FALSE(SampleOccupied({}));
468TEST(TrafficManagerWideTurn, OffsetSideOccupied_NeighbourInBandBlocks) {
470 EXPECT_TRUE(SampleOccupied({{{0.0f, 2.0f, 0.0f}, 1.0f}}));
473TEST(TrafficManagerWideTurn, OffsetSideOccupied_FarLateralNeighbourIsClear) {
475 EXPECT_FALSE(SampleOccupied({{{0.0f, 10.0f, 0.0f}, 1.0f}}));
478TEST(TrafficManagerWideTurn, OffsetSideOccupied_OppositeSideNeighbourIsClear) {
480 EXPECT_FALSE(SampleOccupied({{{0.0f, -3.0f, 0.0f}, 1.0f}}));
483TEST(TrafficManagerWideTurn, OffsetSideOccupied_NeighbourAheadOutsideWindowIsClear) {
485 EXPECT_FALSE(SampleOccupied({{{20.0f, 1.0f, 0.0f}, 1.0f}}));
498constexpr double kNeverRead{-std::numeric_limits<double>::infinity()};
502TEST(TrafficManagerRefreshCadence, IsRefreshDue_NothingReadYetIsDue) {
507TEST(TrafficManagerRefreshCadence, IsRefreshDue_SameFrameIsNotDue) {
511TEST(TrafficManagerRefreshCadence, IsRefreshDue_WithinThePeriodIsNotDue) {
515TEST(TrafficManagerRefreshCadence, IsRefreshDue_AtOrPastThePeriodIsDue) {
520TEST(TrafficManagerRefreshCadence, IsRefreshDue_ClockGoingBackwardsIsDue) {
531struct LightRefreshTrace {
533 int steps_from_registration_to_a_refresh{-1};
538LightRefreshTrace TraceLightRefreshes(
540 const double step_period,
541 const int registration_step) {
543 LightRefreshTrace trace{};
544 double last_update{kNeverRead};
545 bool missing_from_the_last_refresh{
false};
547 for (
int step{0}; step < steps; ++step) {
548 const double now{step_period *
static_cast<double>(step + 1)};
549 const bool refreshed{
553 missing_from_the_last_refresh =
false;
557 if (step < registration_step) {
560 if (refreshed && trace.steps_from_registration_to_a_refresh < 0) {
561 trace.steps_from_registration_to_a_refresh = step - registration_step;
564 last_update = kNeverRead;
567 missing_from_the_last_refresh =
true;
573constexpr int kThirtyFpsSteps{300};
574constexpr double kThirtyFpsPeriod{1.0 / 30.0};
578TEST(TrafficManagerRefreshCadence, IsEarlyRefreshDue_VehicleSeenForTheFirstTimeIsWorthARead) {
582TEST(TrafficManagerRefreshCadence, IsEarlyRefreshDue_VehicleTheServerOmitsIsNotWorthAnother) {
586TEST(TrafficManagerRefreshCadence, IsEarlyRefreshDue_StepThatAlreadyReadNeedsNoRead) {
591TEST(TrafficManagerRefreshCadence, EarlyRefresh_VehicleTheServerNeverReportsKeepsTheRegularCadence) {
592 const LightRefreshTrace reported{
593 TraceLightRefreshes(kThirtyFpsSteps, kThirtyFpsPeriod, kThirtyFpsSteps)};
594 const LightRefreshTrace omitted{TraceLightRefreshes(kThirtyFpsSteps, kThirtyFpsPeriod, 3)};
596 EXPECT_LE(omitted.refreshes, reported.refreshes + 1);
598 static_cast<double>(reported.refreshes),
599 1.0 +
static_cast<double>(kThirtyFpsSteps) * kThirtyFpsPeriod /
603TEST(TrafficManagerRefreshCadence, EarlyRefresh_NewlyRegisteredVehicleIsReadPromptly) {
604 const LightRefreshTrace omitted{TraceLightRefreshes(kThirtyFpsSteps, kThirtyFpsPeriod, 3)};
605 EXPECT_EQ(omitted.steps_from_registration_to_a_refresh, 1);
614struct BatchSyncTrace {
616 uint64_t deepest_queue{0u};
619BatchSyncTrace TraceBatchSyncs(
const int steps,
const uint64_t limit) {
620 BatchSyncTrace trace{};
621 uint64_t unwaited{limit};
622 for (
int step{0}; step < steps; ++step) {
629 trace.deepest_queue = std::max(trace.deepest_queue, unwaited);
635BatchSyncTrace TraceTimeGatedBatchSyncs(
637 const double fixed_delta_seconds,
638 const double period) {
640 BatchSyncTrace trace{};
641 uint64_t unwaited{0u};
642 double last_sync{kNeverRead};
643 for (
int step{0}; step < steps; ++step) {
644 const double now{fixed_delta_seconds *
static_cast<double>(step + 1)};
652 trace.deepest_queue = std::max(trace.deepest_queue, unwaited);
657constexpr int kBatchSteps{1000};
661TEST(TrafficManagerBatchSync, IsBatchSyncDue_WithinTheBoundNothingIsWaitedFor) {
667TEST(TrafficManagerBatchSync, IsBatchSyncDue_AtOrPastTheBoundOneIsWaitedFor) {
674TEST(TrafficManagerBatchSync, QueueNeverHoldsMoreThanThePermittedBatches) {
680TEST(TrafficManagerBatchSync, SlowServerWithAFixedDeltaIsBoundedTheSameWayAsAFastOne) {
684 const BatchSyncTrace timed{TraceTimeGatedBatchSyncs(kBatchSteps, 0.05, 1.0)};
696constexpr float kControlDt{0.05f};
697constexpr float kCruiseTarget{60.0f / 3.6f};
700 float previous_reference,
702 float target_velocity,
704 bool emergency_stop =
false) {
706 return tmgr::PID::ShapeReferenceVelocity(
707 previous_reference, vehicle_speed, target_velocity, control_dt, emergency_stop);
712TEST(TrafficManagerComfortConstants, ReferenceLeadOutrunsTheThrottleSaturationError) {
720TEST(TrafficManagerReferenceVelocity, ShapeReference_RampsAwayFromRestAtComfortAcceleration) {
722 Shape(0.0f, 0.0f, kCruiseTarget, kControlDt),
726TEST(TrafficManagerReferenceVelocity, ShapeReference_NeverExceedsTheTarget) {
728 Shape(kCruiseTarget - 0.05f, kCruiseTarget - 0.05f, kCruiseTarget,
733TEST(TrafficManagerReferenceVelocity, ShapeReference_DecelerationIsPassedThroughUnshaped) {
734 EXPECT_FLOAT_EQ(Shape(20.0f, 20.0f, 5.0f, kControlDt), 5.0f);
737TEST(TrafficManagerReferenceVelocity, ShapeReference_StaleLowReferenceIsRecoveredInOneStep) {
739 EXPECT_FLOAT_EQ(Shape(0.0f, 20.0f, 25.0f, kControlDt), 20.0f);
742TEST(TrafficManagerReferenceVelocity, ShapeReference_StaleHighReferenceIsCappedToTheLead) {
744 Shape(100.0f, 5.0f, 25.0f, kControlDt),
748TEST(TrafficManagerReferenceVelocity, ShapeReference_LeadStaysBoundedWhileTheVehicleCannotFollow) {
750 float reference{0.0f};
751 for (
int step = 0; step < 400; ++step) {
752 reference = Shape(reference, 0.0f, kCruiseTarget, kControlDt);
757TEST(TrafficManagerReferenceVelocity, ShapeReference_EmergencyStopDiscardsTheStoredReference) {
758 const float held{Shape(25.0f, 5.0f, 20.0f, kControlDt,
true)};
759 const float not_held{Shape(25.0f, 5.0f, 20.0f, kControlDt,
false)};
762 EXPECT_LT(held, not_held);
765TEST(TrafficManagerReferenceVelocity, ShapeReference_SlowServerStillRampsAtTheCompensatedRate) {
768 Shape(0.0f, 0.0f, kCruiseTarget, 1.0f),
772TEST(TrafficManagerReferenceVelocity, ShapeReference_ShortFrameStillAdvancesTheReference) {
774 Shape(0.0f, 0.0f, kCruiseTarget, 0.0001f),
782TEST(TrafficManagerReferenceVelocity, VelocityDeviation_MatchesThePlainRatioOnceCaughtUp) {
783 EXPECT_FLOAT_EQ(tmgr::PID::RelativeVelocityDeviation(20.0f, 10.0f, 20.0f), 0.5f);
786TEST(TrafficManagerReferenceVelocity, VelocityDeviation_ZeroTargetBehindAStoppedVehicleIsFinite) {
787 const float reference{Shape(0.0f, 0.0f, 0.0f, kControlDt)};
788 const float deviation{tmgr::PID::RelativeVelocityDeviation(reference, 0.0f, 0.0f)};
790 EXPECT_TRUE(std::isfinite(deviation));
791 EXPECT_FLOAT_EQ(deviation, 0.0f);
794TEST(TrafficManagerReferenceVelocity, VelocityDeviation_ZeroTargetDoesNotPoisonTheNextStep) {
798 const float reference{Shape(0.0f, 0.0f, 0.0f, kControlDt)};
799 current.velocity_deviation = tmgr::PID::RelativeVelocityDeviation(reference, 0.0f, 0.0f);
800 current.reference_velocity = reference;
805 EXPECT_TRUE(std::isfinite(
first.throttle));
806 EXPECT_TRUE(std::isfinite(
first.brake));
807 EXPECT_TRUE(std::isfinite(
first.steer));
812 EXPECT_TRUE(std::isfinite(second.steer));
813 EXPECT_TRUE(std::isfinite(second.throttle));
822StateEntry PreviousCommand(
float throttle,
float brake,
float steer) {
836 tmgr::PID::SmoothActuation(previous, control_dt, vehicle_speed, demand);
842TEST(TrafficManagerActuationSmoothing, LaunchRamp_LimitsTheThrottleRiseFromRest) {
844 PreviousCommand(0.0f, 0.0f, 0.0f), kControlDt, 0.0f,
850TEST(TrafficManagerActuationSmoothing, LaunchRamp_AlwaysClearsTheThrottleDeadband) {
852 PreviousCommand(0.0f, 0.0f, 0.0f), 0.0001f, 0.0f,
861TEST(TrafficManagerActuationSmoothing, LaunchRamp_ReachesFullThrottleInABoundedNumberOfSteps) {
862 StateEntry previous{PreviousCommand(0.0f, 0.0f, 0.0f)};
863 for (
int step = 0; step < 200; ++step) {
865 previous, kControlDt, 0.0f,
867 previous.
throttle = smoothed.throttle;
872TEST(TrafficManagerActuationSmoothing, LaunchRamp_IsReleasedAboveTheLaunchSpeed) {
874 PreviousCommand(0.0f, 0.0f, 0.0f), kControlDt,
881TEST(TrafficManagerActuationSmoothing, LaunchRamp_NeverRaisesAFallingThrottle) {
883 PreviousCommand(0.5f, 0.0f, 0.0f), kControlDt, 1.0f,
886 EXPECT_FLOAT_EQ(smoothed.throttle, 0.1f);
889TEST(TrafficManagerActuationSmoothing, Deadband_HoldsTheThrottleDitherAndPassesARealStep) {
890 const StateEntry previous{PreviousCommand(0.5f, 0.0f, 0.0f)};
893 Smooth(previous, kControlDt, 10.0f,
ActuationSignal{0.505f, 0.0f, 0.0f}).throttle, 0.5f);
895 Smooth(previous, kControlDt, 10.0f,
ActuationSignal{0.52f, 0.0f, 0.0f}).throttle, 0.52f);
898TEST(TrafficManagerActuationSmoothing, Deadband_HoldsTheBrakeDitherAndPassesARealStep) {
899 const StateEntry previous{PreviousCommand(0.0f, 0.4f, 0.0f)};
902 Smooth(previous, kControlDt, 10.0f,
ActuationSignal{0.0f, 0.4005f, 0.0f}).brake, 0.4f);
904 Smooth(previous, kControlDt, 10.0f,
ActuationSignal{0.0f, 0.45f, 0.0f}).brake, 0.45f);
907TEST(TrafficManagerActuationSmoothing, Deadband_ZeroPedalDemandIsAlwaysHonoured) {
909 PreviousCommand(0.005f, 0.005f, 0.0f), kControlDt, 10.0f,
912 EXPECT_FLOAT_EQ(smoothed.throttle, 0.0f);
913 EXPECT_FLOAT_EQ(smoothed.brake, 0.0f);
916TEST(TrafficManagerActuationSmoothing, Deadband_HoldsTheSteeringDitherAtUrbanSpeed) {
917 const StateEntry previous{PreviousCommand(0.0f, 0.0f, 0.1f)};
920 Smooth(previous, kControlDt, 5.0f,
ActuationSignal{0.0f, 0.0f, 0.1015f}).steer, 0.1f);
922 Smooth(previous, kControlDt, 5.0f,
ActuationSignal{0.0f, 0.0f, 0.105f}).steer, 0.105f);
925TEST(TrafficManagerActuationSmoothing, Deadband_SteeringBandShrinksWithSpeed) {
926 const StateEntry previous{PreviousCommand(0.0f, 0.0f, 0.1f)};
static const float MAX_THROTTLE
static const float COMFORT_ACCELERATION
static constexpr float MIN_CONTROL_DT
static const float REFERENCE_LEAD_FRACTION
static const std::vector< float > LONGITUDIAL_PARAM
static const std::vector< float > LONGITUDIAL_HIGHWAY_PARAM
static constexpr float MAX_LAUNCH_THROTTLE_RISE_RATE
static const float MAX_CONTROL_DT
static constexpr float THROTTLE_DEADBAND
static const float STEER_DEADBAND_REF_SPEED
static const float LAUNCH_RAMP_SPEED
static const std::vector< float > LATERAL_PARAM
static const float LARGE_VEHICLES_JUNCTION_MAX_RADIUS
static const double VEHICLE_LIGHT_STATES_REFRESH_PERIOD
bool IsRefreshDue(const double now, const double last, const double period)
Also true when the clock jumps backwards (new episode) or on NaN, so an unusable clock refreshes rath...
static const double EPISODE_SETTINGS_REFRESH_PERIOD
bool IsBatchSyncDue(const uint64_t unwaited_batches, const uint64_t limit)
static const uint64_t MAX_UNWAITED_CONTROL_BATCHES
bool IsEarlyRefreshDue(const bool refreshed_this_step, const bool missing_from_the_last_refresh)
A vehicle the server already omitted from a fresh list (dormant on a large map) must not re-arm the u...
float LargeVehicleJunctionOffsetProfile(float t, float max_offset, float max_offset_point, float inboard_scale)
Lateral offset profile for the large-vehicle wide turn, as a function of t, the fraction of the junct...
float GetPathSpeedLimit(const std::vector< cg::Location > &path, const float path_start_offset, const float sample_spacing, const float lateral_acceleration, const float braking_deceleration, const float max_speed)
Lowest sqrt(R * lateral_acceleration + 2 * braking_deceleration * distance) over every three consecut...
std::pair< cg::Location, uint64_t > InterpolateBufferAt(const std::vector< cg::Location > &waypoint_locations, float target_distance, cg::Location vehicle_location)
Locations-only variant of GetTargetData.
float GetThreePointCircleRadius(cg::Location first_location, cg::Location middle_location, cg::Location last_location)
Returns the radius of the circle defined by three points in the XY plane.
bool IsOffsetSideOccupied(cg::Location ego_location, cg::Vector3D ego_forward, cg::Vector3D offset_direction, float offset_magnitude, float lateral_clearance, float longitudinal_window, const std::vector< std::pair< cg::Location, float > > &neighbours)
Returns true when a neighbouring vehicle sits in the lateral band that the wide-turn offset would swi...
float LargeVehicleOffsetMagnitude(float vehicle_length, float reference_length, float gain, float offset_cap)
Wide-turn offset magnitude scaled by vehicle length: clamp(gain * (vehicle_length - reference_length)...
Structure to hold the actuation signals.
Structure to hold the controller state.
TEST(TrafficManagerGeometry, ThreePointCircleRadius_EquilateralTriangle)