From 332dfdf0990898efa32e78ef149323f3e042d4ad Mon Sep 17 00:00:00 2001 From: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Date: Thu, 6 Aug 2026 10:52:50 -0400 Subject: [PATCH] Dango Unchained --- selfdrive/car/card.py | 20 +++++------ selfdrive/car/tests/test_redneck_cruise.py | 41 +++++++++++++++++++++- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index f6fe149de..c1d31b3d3 100644 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -427,18 +427,8 @@ class Car: self.CI.CS.redneck_v_target = v_target def _get_redneck_target_speed(self, CS: car.CarState, CC: car.CarControl) -> tuple[float, bool]: - # With openpilot longitudinal active, project its acceleration demand into the stock cruise setpoint. - if self.CP.openpilotLongitudinalControl: - return CS.vEgo * 1.01 + 3 * CC.actuators.accel, bool(CC.hudControl.leadVisible) - - # Preserve the existing button-only SLC path when LongControl is disabled. starpilot_target_speed = 0.0 slc_target_speed = 0.0 - allow_plan_decrease = False - lead_present = False - lead_distance_m = 0.0 - lead_rel_speed_ms = 0.0 - lookahead_points = REDNECK_DECREASE_LOOKAHEAD_POINTS if self.sm.seen['starpilotPlan'] and self.sm.valid['starpilotPlan']: starpilot_plan = self.sm['starpilotPlan'] starpilot_target_speed = float(starpilot_plan.vCruise) @@ -448,6 +438,16 @@ class Car: float(starpilot_plan.slcSpeedLimit) + float(starpilot_plan.slcSpeedLimitOffset), ) + # Use acceleration projection only when SLC has no resolved target. + if self.CP.openpilotLongitudinalControl and slc_target_speed <= 0.0: + return CS.vEgo * 1.01 + 3 * CC.actuators.accel, bool(CC.hudControl.leadVisible) + + allow_plan_decrease = False + lead_present = False + lead_distance_m = 0.0 + lead_rel_speed_ms = 0.0 + lookahead_points = REDNECK_DECREASE_LOOKAHEAD_POINTS + plan_speeds = [] if self.sm.seen['longitudinalPlan'] and self.sm.valid['longitudinalPlan']: longitudinal_plan = self.sm['longitudinalPlan'] diff --git a/selfdrive/car/tests/test_redneck_cruise.py b/selfdrive/car/tests/test_redneck_cruise.py index 012ac8d02..8513195fe 100644 --- a/selfdrive/car/tests/test_redneck_cruise.py +++ b/selfdrive/car/tests/test_redneck_cruise.py @@ -1,5 +1,6 @@ import unittest from types import SimpleNamespace +from unittest.mock import MagicMock from cereal import car from openpilot.common.constants import CV @@ -184,7 +185,14 @@ class TestRedneckCruise(unittest.TestCase): self.assertAlmostEqual(slc_mph * CV.MPH_TO_MS, target_speed) def test_card_target_speed_uses_longitudinal_acceleration(self): - card = SimpleNamespace(CP=SimpleNamespace(openpilotLongitudinalControl=True)) + sm = MagicMock() + sm.seen = {"starpilotPlan": False, "longitudinalPlan": False, "radarState": False} + sm.valid = sm.seen.copy() + card = SimpleNamespace( + CP=SimpleNamespace(openpilotLongitudinalControl=True), + sm=sm, + starpilot_toggles=SimpleNamespace(speed_limit_controller=False), + ) car_state = SimpleNamespace(vEgo=55.0 * CV.MPH_TO_MS) car_control = SimpleNamespace( actuators=SimpleNamespace(accel=0.5), @@ -196,6 +204,37 @@ class TestRedneckCruise(unittest.TestCase): self.assertAlmostEqual(55.0 * CV.MPH_TO_MS * 1.01 + 1.5, target_speed) self.assertTrue(lead_present) + def test_card_target_speed_uses_slc_target_with_longitudinal_control(self): + slc_target = 80.0 * CV.KPH_TO_MS + starpilot_plan = SimpleNamespace( + vCruise=110.0 * CV.KPH_TO_MS, + slcOverriddenSpeed=0.0, + slcSpeedLimit=slc_target, + slcSpeedLimitOffset=0.0, + ) + sm = MagicMock() + sm.seen = {"starpilotPlan": True, "longitudinalPlan": False, "radarState": False} + sm.valid = sm.seen.copy() + sm.__getitem__.side_effect = {"starpilotPlan": starpilot_plan}.__getitem__ + card = SimpleNamespace( + CP=SimpleNamespace(openpilotLongitudinalControl=True), + sm=sm, + starpilot_toggles=SimpleNamespace(speed_limit_controller=True), + ) + car_state = SimpleNamespace( + vEgo=100.0 * CV.KPH_TO_MS, + cruiseState=SimpleNamespace(speedCluster=70.0 * CV.KPH_TO_MS), + ) + car_control = SimpleNamespace( + actuators=SimpleNamespace(accel=-1.0), + hudControl=SimpleNamespace(leadVisible=False), + ) + + target_speed, lead_present = Car._get_redneck_target_speed(card, car_state, car_control) + + self.assertAlmostEqual(slc_target, target_speed) + self.assertFalse(lead_present) + def test_target_speed_returns_plan_minimum_when_slowing_down(self): target_speed = select_redneck_target_speed( 120.0,