diff --git a/CHANGELOG.md b/CHANGELOG.md index 00be668571..66f5f432b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ sunnypilot Version 2025.001.000 (2025-10-25) * Intelligent longitudinal control adaptation * Speed Limit Assist (SLA) * Comprehensive speed limit integration featuring @pfeiferj's `mapd` for offline map limits downloads, a Speed Limit Resolver for sourcing data (from car, map, combined, etc), on-screen UI for Speed Limit Information/Warning, and Speed Limit Assist (SLA) to adjust cruise speed automatically. + * Currently disabled for Tesla with sunnypilot Longitudinal Control in release + * May return in future releases * Intelligent Cruise Button Management (ICBM) * System designed to manage the vehicle’s speed by sending cruise control button commands to the car’s ECU. * Smart Cruise Control Map & Vision (SCC-M / SCC-V) diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc index 50d9ccbb41..8724e68651 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/longitudinal/speed_limit/speed_limit_settings.cc @@ -105,6 +105,7 @@ SpeedLimitSettings::SpeedLimitSettings(QWidget *parent) : QStackedWidget(parent) } void SpeedLimitSettings::refresh() { + bool is_release = params.getBool("IsReleaseSpBranch"); bool is_metric_param = params.getBool("IsMetric"); SpeedLimitMode speed_limit_mode_param = static_cast(std::atoi(params.get("SpeedLimitMode").c_str())); SpeedLimitOffsetType offset_type_param = static_cast(std::atoi(params.get("SpeedLimitOffsetType").c_str())); @@ -126,9 +127,11 @@ void SpeedLimitSettings::refresh() { /* * Speed Limit Assist is available when: - * - has_longitudinal_control or has_icbm + * - has_longitudinal_control or has_icbm, and + * - is not a release branch or not a disallowed brand */ - sla_available = has_longitudinal_control || has_icbm; + bool sla_disallow_in_release = CP.getBrand() == "tesla" && is_release; + sla_available = (has_longitudinal_control || has_icbm) && !sla_disallow_in_release; if (!sla_available && speed_limit_mode_param == SpeedLimitMode::ASSIST) { params.put("SpeedLimitMode", std::to_string(static_cast(SpeedLimitMode::WARNING))); diff --git a/sunnypilot/selfdrive/controls/lib/speed_limit/helpers.py b/sunnypilot/selfdrive/controls/lib/speed_limit/helpers.py index c209e98dce..04a85f57c4 100644 --- a/sunnypilot/selfdrive/controls/lib/speed_limit/helpers.py +++ b/sunnypilot/selfdrive/controls/lib/speed_limit/helpers.py @@ -22,15 +22,22 @@ def compare_cluster_target(v_cruise_cluster: float, target_set_speed: float, is_ return req_plus, req_minus -def set_speed_limit_assist_availability(CP: car.CarParams, CP_SP: custom.CarParamsSP, params: Params = None) -> None: +def set_speed_limit_assist_availability(CP: car.CarParams, CP_SP: custom.CarParamsSP, params: Params = None) -> bool: if params is None: params = Params() + is_release = params.get_bool("IsReleaseSpBranch") + disallow_in_release = CP.brand == "tesla" and is_release allowed = True + if disallow_in_release: + allowed = False + if not CP.openpilotLongitudinalControl and CP_SP.pcmCruiseSpeed: allowed = False if not allowed: if params.get("SpeedLimitMode", return_default=True) == SpeedLimitMode.assist: params.put("SpeedLimitMode", int(SpeedLimitMode.warning)) + + return allowed diff --git a/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_assist.py b/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_assist.py index fcb5a98a2a..ff7be8a8be 100644 --- a/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_assist.py +++ b/sunnypilot/selfdrive/controls/lib/speed_limit/speed_limit_assist.py @@ -10,13 +10,13 @@ from cereal import custom, car from openpilot.common.params import Params from openpilot.common.constants import CV from openpilot.common.realtime import DT_MDL -from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N +from openpilot.selfdrive.modeld.constants import ModelConstants +from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit import PCM_LONG_REQUIRED_MAX_SET_SPEED, CONFIRM_SPEED_THRESHOLD from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Mode from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.helpers import compare_cluster_target, set_speed_limit_assist_availability -from openpilot.selfdrive.modeld.constants import ModelConstants ButtonType = car.CarState.ButtonEvent.Type EventNameSP = custom.OnroadEventSP.EventName diff --git a/sunnypilot/selfdrive/controls/lib/speed_limit/tests/test_speed_limit_assist.py b/sunnypilot/selfdrive/controls/lib/speed_limit/tests/test_speed_limit_assist.py index 8a3376a05c..5dc89cfd80 100644 --- a/sunnypilot/selfdrive/controls/lib/speed_limit/tests/test_speed_limit_assist.py +++ b/sunnypilot/selfdrive/controls/lib/speed_limit/tests/test_speed_limit_assist.py @@ -4,17 +4,21 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ -from cereal import custom +import pytest + +from cereal import custom from opendbc.car.car_helpers import interfaces +from opendbc.car.tesla.values import CAR as TESLA from opendbc.car.toyota.values import CAR as TOYOTA from openpilot.common.constants import CV from openpilot.common.params import Params from openpilot.common.realtime import DT_MDL from openpilot.selfdrive.car.cruise import V_CRUISE_UNSET +from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD from openpilot.sunnypilot.selfdrive.car import interfaces as sunnypilot_interfaces -from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Mode from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit import PCM_LONG_REQUIRED_MAX_SET_SPEED +from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.common import Mode from openpilot.sunnypilot.selfdrive.controls.lib.speed_limit.speed_limit_assist import SpeedLimitAssist, \ PRE_ACTIVE_GUARD_PERIOD, ACTIVE_STATES from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP @@ -30,14 +34,28 @@ SPEED_LIMITS = { 'freeway': 80 * CV.MPH_TO_MS, # 80 mph } +DEFAULT_CAR = TOYOTA.TOYOTA_RAV4_TSS2 + + +@pytest.fixture +def car_name(request): + return getattr(request, "param", DEFAULT_CAR) + + +@pytest.fixture(autouse=True) +def set_car_name_on_instance(request, car_name): + instance = getattr(request, "instance", None) + if instance: + instance.car_name = car_name + class TestSpeedLimitAssist: - def setup_method(self): + def setup_method(self, method): self.params = Params() self.reset_custom_params() self.events_sp = EventsSP() - CI = self._setup_platform(TOYOTA.TOYOTA_RAV4_TSS2) + CI = self._setup_platform(self.car_name) self.sla = SpeedLimitAssist(CI.CP, CI.CP_SP) self.sla.pre_active_timer = int(PRE_ACTIVE_GUARD_PERIOD[self.sla.pcm_op_long] / DT_MDL) self.pcm_long_max_set_speed = PCM_LONG_REQUIRED_MAX_SET_SPEED[self.sla.is_metric][1] # use 80 MPH for now @@ -51,10 +69,12 @@ class TestSpeedLimitAssist: CP = CarInterface.get_non_essential_params(car_name) CP_SP = CarInterface.get_non_essential_params_sp(CP, car_name) CI = CarInterface(CP, CP_SP) + CI.CP.openpilotLongitudinalControl = True # always assume it's openpilot longitudinal sunnypilot_interfaces.setup_interfaces(CI, self.params) return CI def reset_custom_params(self): + self.params.put("IsReleaseSpBranch", True) self.params.put("SpeedLimitMode", int(Mode.assist)) self.params.put_bool("IsMetric", False) self.params.put("SpeedLimitOffsetType", 0) @@ -84,6 +104,21 @@ class TestSpeedLimitAssist: assert not self.sla.is_active assert V_CRUISE_UNSET == self.sla.get_v_target_from_control() + @pytest.mark.parametrize("car_name", [TESLA.TESLA_MODEL_Y], indirect=True) + def test_disallowed_brands(self, car_name): + """ + Speed Limit Assist is disabled for the following brands and conditions: + - All Tesla and is a release branch + """ + assert not self.sla.enabled + + # stay disallowed even when the param may have changed from somewhere else + self.params.put("SpeedLimitMode", int(Mode.assist)) + for _ in range(int(PARAMS_UPDATE_PERIOD / DT_MDL)): + self.sla.update(True, False, SPEED_LIMITS['city'], 0, SPEED_LIMITS['highway'], SPEED_LIMITS['city'], + SPEED_LIMITS['city'], True, 0, self.events_sp) + assert not self.sla.enabled + def test_disabled(self): self.params.put("SpeedLimitMode", int(Mode.off)) for _ in range(int(10. / DT_MDL)):