Keep unconfirmed stop forecasts current until explicit stop intent

This commit is contained in:
firestar5683
2026-11-11 14:16:09 -06:00
parent dc60049a25
commit 267c2bb2ce
3 changed files with 42 additions and 2 deletions
@@ -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:
@@ -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
+1 -1
View File
@@ -1 +1 @@
{"protected_inventory_sha256": "00fcb8440a365c107104fea6a9518c9d933cf3d71ba04e1a44eeed26e284f3ec", "schema_version": 1}
{"protected_inventory_sha256": "91f72124e5226a7fe335f8a4f3d46b2443d41f058cdcc4881e52307669e603cb", "schema_version": 1}