From 34fe53630086ba90130b284b54865e630d23f422 Mon Sep 17 00:00:00 2001 From: rav4kumar Date: Tue, 8 Sep 2026 06:45:25 -0700 Subject: [PATCH] control: gate accel shaping by DEC policy --- .../controls/lib/longitudinal_planner.py | 4 +++- .../tests/test_accel_controller.py | 15 ++++++++++++++- .../controls/lib/longitudinal_planner.py | 7 +++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/openpilot/selfdrive/controls/lib/longitudinal_planner.py b/openpilot/selfdrive/controls/lib/longitudinal_planner.py index d39acf53a0..bb39528a87 100755 --- a/openpilot/selfdrive/controls/lib/longitudinal_planner.py +++ b/openpilot/selfdrive/controls/lib/longitudinal_planner.py @@ -145,8 +145,10 @@ class LongitudinalPlanner(LongitudinalPlannerSP): is_e2e = self.is_e2e(sm) + experimental_mode = sm['selfdriveState'].experimentalMode + dec_acc_policy = experimental_mode and self.dec.active() and self.dec.mode() == "acc" max_accel_override = self.get_max_accel_override(v_ego) - v_cruise = self.get_cruise_target_override(v_ego, v_cruise, force_decel) + v_cruise = self.get_cruise_target_override(v_ego, v_cruise, force_decel, experimental_mode, dec_acc_policy) a_cruise_prev = self.a_cruise gated_cruise = get_cruise_accel(is_e2e, v_cruise, v_ego, a_cruise_prev, steer_angle_without_offset, self.CP, self.dt, accel_coast, self.allow_throttle, max_accel_override) diff --git a/openpilot/sunnypilot/selfdrive/controls/lib/accel_controller/tests/test_accel_controller.py b/openpilot/sunnypilot/selfdrive/controls/lib/accel_controller/tests/test_accel_controller.py index 26fabe5f85..b1a5902a19 100644 --- a/openpilot/sunnypilot/selfdrive/controls/lib/accel_controller/tests/test_accel_controller.py +++ b/openpilot/sunnypilot/selfdrive/controls/lib/accel_controller/tests/test_accel_controller.py @@ -259,7 +259,20 @@ class TestPlannerIntegration(OpenpilotTestCase): planner.source = LongitudinalPlanSource.cruise assert planner.get_cruise_target_override(25.0, 0.0, force_decel=True) == 0.0 - def test_e2e_candidate_is_held_through_a_brake_but_not_otherwise(self): + def test_cruise_target_override_follows_dec_policy(self): + self.params.put_bool("AccelPersonalityEnabled", True, block=True) + planner = _bare_planner() + + # Experimental/model mode bypasses accel-personality braking unless DEC explicitly selects ACC policy. + assert planner.get_cruise_target_override(25.0, 22.5, force_decel=False, experimental_mode=True) == 22.5 + shaped = planner.get_cruise_target_override(25.0, 22.5, force_decel=False, + experimental_mode=True, dec_acc_policy=True) + assert 22.5 < shaped < 25.0 + + # Normal mode retains the existing accel-personality behavior. + shaped = planner.get_cruise_target_override(25.0, 22.5, force_decel=False, experimental_mode=False) + assert 22.5 < shaped < 25.0 + # Route 000005dd: e2e -> lead1 stepped +2.25 m/s^2 in one frame (45 m/s^3) and back the next, while the # model held desiredAcceleration at -1.63 and never moved more than 0.024. Dropping a candidate the model # still owns is what produced the brake/gas/brake flip. diff --git a/openpilot/sunnypilot/selfdrive/controls/lib/longitudinal_planner.py b/openpilot/sunnypilot/selfdrive/controls/lib/longitudinal_planner.py index 34196bf92b..47770d98e1 100644 --- a/openpilot/sunnypilot/selfdrive/controls/lib/longitudinal_planner.py +++ b/openpilot/sunnypilot/selfdrive/controls/lib/longitudinal_planner.py @@ -64,8 +64,11 @@ class LongitudinalPlannerSP: return self.accel_controller.get_max_accel(v_ego) - def get_cruise_target_override(self, v_ego: float, v_target: float, force_decel: bool) -> float: - if not self.accel_controller.is_enabled() or force_decel or self.source != LongitudinalPlanSource.cruise: + def get_cruise_target_override(self, v_ego: float, v_target: float, force_decel: bool, + experimental_mode: bool = False, dec_acc_policy: bool = False) -> float: + # Experimental/model mode owns braking unless DEC explicitly selects its ACC policy. + if ((experimental_mode and not dec_acc_policy) or not self.accel_controller.is_enabled() + or force_decel or self.source != LongitudinalPlanSource.cruise): return v_target return self.accel_controller.get_cruise_target(v_ego, v_target)