diff --git a/opendbc_repo/opendbc/car/gm/interface.py b/opendbc_repo/opendbc/car/gm/interface.py index 6819db0fb..e6e2fc2ea 100755 --- a/opendbc_repo/opendbc/car/gm/interface.py +++ b/opendbc_repo/opendbc/car/gm/interface.py @@ -24,6 +24,7 @@ from opendbc.car.gm.values import ( from opendbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, LateralAccelFromTorqueCallbackType from opendbc.safety import ALTERNATIVE_EXPERIENCE from openpilot.common.params import Params, UnknownKeyName +from openpilot.starpilot.common.testing_grounds import testing_ground TransmissionType = structs.CarParams.TransmissionType NetworkLocation = structs.CarParams.NetworkLocation @@ -76,7 +77,7 @@ VOLT_LIKE_CARS = { CAR.CHEVROLET_MALIBU_HYBRID_CC, } -VOLT_LONG_TUNE_CARS = { +VOLT_LONG_TEST_TUNE_CARS = { CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_VOLT_ASCM, @@ -565,14 +566,15 @@ class CarInterface(CarInterfaceBase): ret.pcmCruise = False ret.openpilotLongitudinalControl = not disable_openpilot_long - volt_long_tune_active = ( + volt_test_tune_active = ( + testing_ground.use_2 and ret.openpilotLongitudinalControl and - candidate in VOLT_LONG_TUNE_CARS + candidate in VOLT_LONG_TEST_TUNE_CARS ) - if volt_long_tune_active: + if volt_test_tune_active: # Volt long can still fall back to an all-I tune on both the interceptor and - # ASCM-int paths. Use the promoted tune by default: add a modest P term, - # trim mid/high-speed I memory, and keep a dedicated starting state so + # ASCM-int paths. The test-ground tune adds a modest P term, trims + # mid/high-speed I memory, and uses a dedicated starting state so # stop-and-go launches do not wind up the PID. ret.longitudinalTuning.kpBP = [0.0, 4.0, 12.0, 35.0] ret.longitudinalTuning.kpV = [0.10, 0.072, 0.050, 0.040] diff --git a/opendbc_repo/opendbc/car/gm/tests/test_gm.py b/opendbc_repo/opendbc/car/gm/tests/test_gm.py index ae4559c60..9ad923a75 100644 --- a/opendbc_repo/opendbc/car/gm/tests/test_gm.py +++ b/opendbc_repo/opendbc/car/gm/tests/test_gm.py @@ -4,6 +4,7 @@ from parameterized import parameterized from opendbc.car.car_helpers import interfaces from opendbc.car.gm.carcontroller import should_spoof_dash_speed +import opendbc.car.gm.interface as gm_interface from opendbc.car.common.conversions import Conversions as CV from opendbc.car.gm.fingerprints import FINGERPRINTS from opendbc.car.gm.values import CAMERA_ACC_CAR, CAR, CC_ONLY_CAR, GM_RX_OFFSET @@ -60,13 +61,15 @@ class TestGMInterface: ("interceptor", True), ("ascm_int", False), ]) - def test_volt_default_long_tune_sets_nonzero_p_and_starting_state(self, _name, pedal_present): + def test_volt_testing_ground_tune_sets_nonzero_p_and_starting_state(self, _name, pedal_present, monkeypatch): CarInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM] fingerprint = _empty_fingerprint() if pedal_present: fingerprint[0][0x201] = 8 # pedal detected fingerprint[0][0x2FF] = 8 # SASCM detected + monkeypatch.setattr(gm_interface.testing_ground, "use_2", True, raising=False) + car_params = CarInterface.get_params(CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=False, is_release=False, docs=False, starpilot_toggles=_test_starpilot_toggles()) diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 574d5a13e..454f6779d 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -6,6 +6,7 @@ from openpilot.common.pid import PIDController from openpilot.selfdrive.modeld.constants import ModelConstants from openpilot.common.filter_simple import FirstOrderFilter from opendbc.car.gm.values import CarControllerParams, GMFlags +from openpilot.starpilot.common.testing_grounds import testing_ground CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N] clip = np.clip @@ -154,9 +155,9 @@ class LongControl: self.integrator_hold_frames = 0 def _get_pedal_long_freeze(self, a_target, error, v_ego, accel_limits): - volt_long_handoff = self.is_volt + volt_test_tune_handoff = self.is_volt and testing_ground.use_2 - if not self.is_gm_pedal_long and not volt_long_handoff: + if not self.is_gm_pedal_long and not volt_test_tune_handoff: self.last_a_target = a_target self.integrator_hold_frames = 0 return False @@ -183,8 +184,8 @@ class LongControl: return self.integrator_hold_frames > 0 or sat_pushing_lower or sat_pushing_upper - def _shape_volt_integrator(self, error, v_ego): - if not self.is_volt: + def _shape_volt_test_tune_integrator(self, error, v_ego): + if not (self.is_volt and testing_ground.use_2): return # Bleed stale I quickly when the target reverses against stored integrator. @@ -223,7 +224,7 @@ class LongControl: else: # LongCtrlState.pid error = a_target - CS.aEgo self.update_mpc_mode(self.experimental_mode) - self._shape_volt_integrator(error, CS.vEgo) + self._shape_volt_test_tune_integrator(error, CS.vEgo) feedforward = a_target * self.feedforward_gain freeze_integrator = self._get_pedal_long_freeze(a_target, error, CS.vEgo, accel_limits) raw_output_accel = self.pid.update(error, speed=CS.vEgo, feedforward=feedforward, diff --git a/selfdrive/controls/tests/test_longcontrol.py b/selfdrive/controls/tests/test_longcontrol.py index adc5aeab0..11633d7fb 100644 --- a/selfdrive/controls/tests/test_longcontrol.py +++ b/selfdrive/controls/tests/test_longcontrol.py @@ -2,6 +2,7 @@ from types import SimpleNamespace from cereal import car +import openpilot.selfdrive.controls.lib.longcontrol as longcontrol from openpilot.selfdrive.controls.lib.longcontrol import LongControl, LongCtrlState, long_control_state_trans @@ -124,7 +125,7 @@ def test_starting_accel_obeys_a_target_cap_when_custom_profile_enabled(): assert output_accel == 0.1 -def test_volt_pedal_handoff_freezes_integrator(): +def test_volt_testing_ground_handoff_freezes_integrator(monkeypatch): CP = car.CarParams.new_message() CP.brand = "gm" CP.enableGasInterceptorDEPRECATED = True @@ -134,6 +135,8 @@ def test_volt_pedal_handoff_freezes_integrator(): CP.longitudinalTuning.kiBP = [0.0] CP.longitudinalTuning.kiV = [0.03] + monkeypatch.setattr(longcontrol.testing_ground, "use_2", True, raising=False) + lc = LongControl(CP) freeze = lc._get_pedal_long_freeze(a_target=0.7, error=0.7, v_ego=8.0, accel_limits=(-3.0, 2.0)) @@ -141,7 +144,7 @@ def test_volt_pedal_handoff_freezes_integrator(): assert lc.integrator_hold_frames > 0 -def test_non_interceptor_volt_handoff_freezes_integrator(): +def test_non_interceptor_volt_testing_ground_handoff_freezes_integrator(monkeypatch): CP = car.CarParams.new_message() CP.brand = "gm" CP.enableGasInterceptorDEPRECATED = False @@ -151,6 +154,8 @@ def test_non_interceptor_volt_handoff_freezes_integrator(): CP.longitudinalTuning.kiBP = [0.0] CP.longitudinalTuning.kiV = [0.03] + monkeypatch.setattr(longcontrol.testing_ground, "use_2", True, raising=False) + lc = LongControl(CP) freeze = lc._get_pedal_long_freeze(a_target=0.7, error=0.7, v_ego=8.0, accel_limits=(-3.0, 2.0)) diff --git a/starpilot/common/testing_grounds.py b/starpilot/common/testing_grounds.py index 04372c7af..377978f9c 100644 --- a/starpilot/common/testing_grounds.py +++ b/starpilot/common/testing_grounds.py @@ -40,9 +40,10 @@ TESTING_GROUNDS_SLOT_DEFINITIONS = ( }, { "id": TESTING_GROUND_2, - "name": "Unused", - "description": "", - "aLabel": "A", + "name": "Volt Long Tune", + "description": "Volt longitudinal tuning sandbox.", + "aLabel": "A - Installed tune", + "bLabel": "B - Firestar Tune", }, { "id": TESTING_GROUND_3, @@ -149,18 +150,6 @@ def _normalize_selection(slot_id, variant): return normalized_slot_id, _normalize_variant(variant, normalized_slot_id) -def migrate_testing_ground_selection(slot_id, variant, default_slot_id=None): - normalized_slot_id = str(slot_id or "").strip() - normalized_variant = str(variant or "").strip().upper() - fallback_slot_id = str(default_slot_id or _DEFAULT_ACTIVE_SLOT).strip() or _DEFAULT_ACTIVE_SLOT - - # Retire the Volt B sandbox cleanly when the tune graduates to default behavior. - if normalized_slot_id == TESTING_GROUND_2 and normalized_variant == TESTING_GROUND_TEST_VARIANT: - return fallback_slot_id, DEFAULT_TESTING_GROUND_VARIANT, True - - return normalized_slot_id, normalized_variant, False - - def _write_testing_ground_selection(payload, slot_id, variant): normalized_payload = dict(payload) if isinstance(payload, dict) else {} normalized_payload["schemaVersion"] = TESTING_GROUNDS_SCHEMA_VERSION @@ -209,12 +198,10 @@ def get_testing_ground_selection(refresh_interval_s=0.5): raw_slot_id = str(payload.get("activeSlot") or "").strip() raw_variant = payload.get("activeVariant") - migrated_slot_id, migrated_variant, selection_migrated = migrate_testing_ground_selection(raw_slot_id, raw_variant) - normalized_slot_id, normalized_variant = _normalize_selection(migrated_slot_id, migrated_variant) + normalized_slot_id, normalized_variant = _normalize_selection(raw_slot_id, raw_variant) raw_variant_text = str(raw_variant or "").strip().upper() if ( payload.get("schemaVersion") != TESTING_GROUNDS_SCHEMA_VERSION or - selection_migrated or raw_slot_id != normalized_slot_id or raw_variant_text != normalized_variant ): diff --git a/starpilot/common/tests/test_testing_grounds.py b/starpilot/common/tests/test_testing_grounds.py index b9716e9fc..72f028620 100644 --- a/starpilot/common/tests/test_testing_grounds.py +++ b/starpilot/common/tests/test_testing_grounds.py @@ -5,7 +5,7 @@ import pytest from openpilot.starpilot.common import testing_grounds as tg -@pytest.mark.parametrize("hidden_slot_id", [tg.TESTING_GROUND_2, tg.TESTING_GROUND_5]) +@pytest.mark.parametrize("hidden_slot_id", [tg.TESTING_GROUND_5]) def test_hidden_testing_ground_selection_is_migrated(tmp_path, monkeypatch, hidden_slot_id): state_path = tmp_path / "slots.json" state_path.write_text(json.dumps({ @@ -28,11 +28,3 @@ def test_hidden_testing_ground_selection_is_migrated(tmp_path, monkeypatch, hidd payload = json.loads(state_path.read_text(encoding="utf-8")) assert payload["activeSlot"] == tg.TESTING_GROUND_1 assert payload["activeVariant"] == tg.DEFAULT_TESTING_GROUND_VARIANT - - -def test_retired_volt_b_selection_is_explicitly_migrated_to_default_a(): - slot_id, variant, migrated = tg.migrate_testing_ground_selection(tg.TESTING_GROUND_2, tg.TESTING_GROUND_TEST_VARIANT, tg.TESTING_GROUND_1) - - assert migrated - assert slot_id == tg.TESTING_GROUND_1 - assert variant == tg.DEFAULT_TESTING_GROUND_VARIANT diff --git a/starpilot/system/the_pond/the_pond.py b/starpilot/system/the_pond/the_pond.py index 80183ac41..5c36c6365 100644 --- a/starpilot/system/the_pond/the_pond.py +++ b/starpilot/system/the_pond/the_pond.py @@ -71,7 +71,6 @@ from openpilot.starpilot.common.testing_grounds import ( TESTING_GROUNDS_SCHEMA_VERSION as SHARED_TESTING_GROUNDS_SCHEMA_VERSION, TESTING_GROUNDS_SLOT_DEFINITIONS as SHARED_TESTING_GROUNDS_SLOT_DEFINITIONS, TESTING_GROUNDS_STATE_PATH as SHARED_TESTING_GROUNDS_STATE_PATH, - migrate_testing_ground_selection as migrate_shared_testing_ground_selection, ) from openpilot.starpilot.system.the_pond import utilities @@ -2937,8 +2936,6 @@ def _load_testing_grounds_state_unlocked(): } default_slot_id = _get_first_selectable_testing_ground_slot_id(state["slots"]) active_slot = str(raw_state.get("activeSlot") or "").strip() - raw_active_variant = str(raw_state.get("activeVariant") or "").strip().upper() - active_slot, migrated_variant, selection_migrated = migrate_shared_testing_ground_selection(active_slot, raw_active_variant, default_slot_id) active_slot_migrated = active_slot not in fallback_slot_ids or active_slot not in selectable_slot_ids if active_slot_migrated: active_slot = default_slot_id @@ -2946,10 +2943,11 @@ def _load_testing_grounds_state_unlocked(): state["activeSlot"] = active_slot active_slot_data = _find_testing_ground_slot(state, active_slot) - if active_slot_migrated or selection_migrated: + raw_active_variant = str(raw_state.get("activeVariant") or "").strip().upper() + if active_slot_migrated: active_variant = _TESTING_GROUNDS_DEFAULT_VARIANT else: - active_variant = _normalize_testing_ground_variant(active_slot, migrated_variant, active_slot_data) + active_variant = _normalize_testing_ground_variant(active_slot, raw_active_variant, active_slot_data) if raw_active_variant != active_variant: needs_write = True state["activeVariant"] = active_variant