From 267c2bb2cedfea22f30a757b8933c19bdd15b857 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Wed, 11 Nov 2026 14:16:09 -0600 Subject: [PATCH] Keep unconfirmed stop forecasts current until explicit stop intent --- .../longitudinal/force_stop_runtime.py | 3 +- .../tests/test_force_stop_runtime.py | 39 +++++++++++++++++++ prebuilt.json | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/openpilot/starpilot/longitudinal/force_stop_runtime.py b/openpilot/starpilot/longitudinal/force_stop_runtime.py index ef27628ff5..1abffc3a0e 100644 --- a/openpilot/starpilot/longitudinal/force_stop_runtime.py +++ b/openpilot/starpilot/longitudinal/force_stop_runtime.py @@ -194,6 +194,7 @@ class ForceStopRuntime: self.vision_ranged_ns = vision_sign vision_distance = self.vision_stop.distance_m - float(car.vEgo) * (stamp - vision_sign) / 1e9 dashboard_sign = dashboard_stop_sign(sm, now_ns=now_ns, drive_id=drive_id) + # A stationary forecast tail alone does not identify a fixed stop line. frame = StopFrame(stamp, float(car.vEgo), horizon, light_context, horizon is not None and horizon < 50, bool(model.action.shouldStop), bool(car.standstill), True, bool(car.gasPressed), tracked is not None and tracked.tracked is True, bool(lead.present), float(lead.dRel), float(lead.vLead), @@ -203,7 +204,7 @@ class ForceStopRuntime: dashboard_sign=dashboard_sign, vision_distance_m=vision_distance, moving_preview=bool(perception_available and not model.action.shouldStop and len(model.velocity.x) == len(model.position.x) and - math.isfinite(model.velocity.x[-1]) and model.velocity.x[-1] > .3)) + math.isfinite(model.velocity.x[-1]))) tune = replace(vehicle_tune(str(cp.carFingerprint)), distance_control=distance_braking_eligible(cp)) self.plan = self.policy.step(frame, tune, self.offset) if takeoff_enabled: diff --git a/openpilot/starpilot/longitudinal/tests/test_force_stop_runtime.py b/openpilot/starpilot/longitudinal/tests/test_force_stop_runtime.py index 529da2dd8b..75d8db7e56 100644 --- a/openpilot/starpilot/longitudinal/tests/test_force_stop_runtime.py +++ b/openpilot/starpilot/longitudinal/tests/test_force_stop_runtime.py @@ -62,6 +62,45 @@ class ForceStopRuntimeTests(unittest.TestCase): self.assertTrue(output.forcing) return output + def test_unconfirmed_stationary_forecast_tail_keeps_preview_tracking(self): + from unittest.mock import patch + from openpilot.starpilot.longitudinal.tests.test_ioniq6_start import candidate + _, self.cp = candidate() + for tail in (0., .1, .3): + with self.subTest(tail=tail): + self.owner = ForceStopRuntime(self.params) + self.sample(Frame(0)) + sm = Frame(1) + sm['modelV2'].velocity.x = [10.] * 32 + [tail] + sm['modelV2'].action.shouldStop = False + with patch.object(self.owner.policy, 'step', wraps=self.owner.policy.step) as step: + self.sample(sm) + self.assertTrue(step.called) + self.assertTrue(step.call_args.args[0].moving_preview) + + def test_explicit_model_stop_still_freezes_the_target(self): + from openpilot.starpilot.longitudinal.tests.test_ioniq6_start import candidate + _, self.cp = candidate() + for tick in range(40): + self.sample(Frame(tick)) + sm = Frame(40, horizon=30.) + sm['modelV2'].velocity.x = [10.] * 32 + [0.] + sm['modelV2'].action.shouldStop = True + before = self.sample(sm) + self.assertFalse(self.owner.policy.preview_tracking) + after = self.sample(Frame(41, horizon=70.)) + self.assertLess(after.tracked_distance_m, before.tracked_distance_m) + + def test_invalid_forecast_still_uses_odometry_without_extending(self): + from openpilot.starpilot.longitudinal.tests.test_ioniq6_start import candidate + _, self.cp = candidate() + for tick in range(40): + before = self.sample(Frame(tick)) + sm = Frame(40, horizon=70.) + sm['modelV2'].velocity.x = [10.] * 32 + [-.1] + after = self.sample(sm) + self.assertAlmostEqual(after.tracked_distance_m, before.tracked_distance_m - .5) + def test_vision_expiry_gap_preserves_confirmation_but_not_control_authority(self): from unittest.mock import patch from openpilot.starpilot.speed_limits.vision.tests.test_stop_observation import evidence, message diff --git a/prebuilt.json b/prebuilt.json index 0675542920..2f7b0eab6f 100644 --- a/prebuilt.json +++ b/prebuilt.json @@ -1 +1 @@ -{"protected_inventory_sha256": "00fcb8440a365c107104fea6a9518c9d933cf3d71ba04e1a44eeed26e284f3ec", "schema_version": 1} +{"protected_inventory_sha256": "91f72124e5226a7fe335f8a4f3d46b2443d41f058cdcc4881e52307669e603cb", "schema_version": 1}