From 00547795aaef074d3280fc181bc92579d48e94c3 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:17:31 -0500 Subject: [PATCH] Keep zero speed visible --- openpilot/starpilot/ui/runtime_snapshot.py | 12 ++++++++-- .../ui/tests/test_runtime_snapshot.py | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/openpilot/starpilot/ui/runtime_snapshot.py b/openpilot/starpilot/ui/runtime_snapshot.py index 2018b9bcba..a0e39d6182 100644 --- a/openpilot/starpilot/ui/runtime_snapshot.py +++ b/openpilot/starpilot/ui/runtime_snapshot.py @@ -124,6 +124,14 @@ def _finite(value: Any, *, positive: bool = False) -> float | None: return number +def _display_speed(value: Any) -> float | None: + try: + speed = float(value) + except (TypeError, ValueError, OverflowError): + return None + return max(0.0, speed) if math.isfinite(speed) else None + + def _model_confidence(model: Any | None) -> float | None: try: predictions = model.meta.disengagePredictions @@ -377,9 +385,9 @@ class RuntimeSnapshotAdapter: selfdrive is not None and selfdrive.enabled and car is not None and bool(getattr(car, "canValid", False)) and not getattr(car, "canTimeout", True) and ui.CP is not None and ui.CP.openpilotLongitudinalControl) - raw_speed = None if display_car is None else _finite(display_car.vEgoCluster) + raw_speed = None if display_car is None else _display_speed(display_car.vEgoCluster) if raw_speed is None or raw_speed == 0: - raw_speed = None if display_car is None else _finite(display_car.vEgo) + raw_speed = None if display_car is None else _display_speed(display_car.vEgo) display_car_valid = bool(display_car is not None and getattr(display_car, "canValid", False) and not getattr(display_car, "canTimeout", True)) timer_car_fresh = False diff --git a/openpilot/starpilot/ui/tests/test_runtime_snapshot.py b/openpilot/starpilot/ui/tests/test_runtime_snapshot.py index e58c12c27f..4641f461d7 100644 --- a/openpilot/starpilot/ui/tests/test_runtime_snapshot.py +++ b/openpilot/starpilot/ui/tests/test_runtime_snapshot.py @@ -519,6 +519,30 @@ class TestRuntimeSnapshot(unittest.TestCase): self.assertIsNone(snapshot.home.stats) self.assertEqual(snapshot.home.model_label, "") + def test_zero_speed_remains_visible_across_signed_filtered_estimates(self): + import pyray as rl + from openpilot.starpilot.ui.onroad_large_widgets import CurrentSpeedHud + + for metric in (False, True): + ui = ui_fake() + ui.is_metric = metric + adapter = RuntimeSnapshotAdapter(ui) + ui.sm.messages["carState"].vEgoCluster = 0.0 + for speed in (-0.238205, -0.001, 0.0, 0.001, 0.44704): + with self.subTest(metric=metric, speed=speed): + ui.sm.messages["carState"].vEgo = speed + state = adapter.build(ShellMode.ONROAD, now_ns=NOW).onroad + self.assertEqual(state.speed_mps, max(0.0, speed)) + fonts = Mock(spec=BitmapFonts) + fonts.measure.return_value = NS(width=10, height=20) + fonts.vertical_ink.return_value = (0., 20.) + CurrentSpeedHud(fonts).render(rl.Rectangle(0, 0, 1800, 1020), state) + self.assertEqual(fonts.draw.call_args_list[0].args[0], "1" if speed == 0.44704 and not metric else + str(round(max(0., speed) * (3.6 if metric else 2.2369362921)))) + self.assertEqual(fonts.draw.call_args_list[1].args[0], "km/h" if metric else "mph") + ui.sm.logMonoTime["carState"] = NOW - 2_000_000_000 + self.assertIsNone(adapter.build(ShellMode.ONROAD, now_ns=NOW).onroad.speed_mps) + def test_stale_and_malformed_values_never_become_displayed_speed(self): ui = ui_fake() ui.sm.logMonoTime["slcState"] = NOW - 500_000_000