diff --git a/openpilot/selfdrive/controls/controlsd.py b/openpilot/selfdrive/controls/controlsd.py index 7655a243e7..44ecc16baa 100755 --- a/openpilot/selfdrive/controls/controlsd.py +++ b/openpilot/selfdrive/controls/controlsd.py @@ -136,10 +136,13 @@ class Controls: "startupPidLimits": [self.LaC.pid.neg_limit, self.LaC.pid.pos_limit]}) from openpilot.starpilot.flm.live_trial_store import load_confirmed_history - self.global_learning = GlobalRuntime(self.CP, self.CI, self.LaC, confirmed_live_history=load_confirmed_history(self.params)) + from openpilot.starpilot.lateral.learning_preferences import read_preference + preference = read_preference(self.params, self.CP) + self.global_learning = (GlobalRuntime(self.CP, self.CI, self.LaC, confirmed_live_history=load_confirmed_history(self.params)) + if preference.valid and preference.enabled else None) # Load optional capture and live-trial code before the first control command. # Engagement must not compile/import replay and feedback modules in the loop. - if self.global_learning.descriptor is not None: + if self.global_learning is not None and self.global_learning.descriptor is not None: try: for module in ('controller_replay', 'physical_input_observation', 'feedback_wire', 'live_trial_wire', 'live_tracking_response'): importlib.import_module('openpilot.starpilot.flm.' + module) diff --git a/openpilot/starpilot/lateral/tests/test_automatic_learning_source.py b/openpilot/starpilot/lateral/tests/test_automatic_learning_source.py index 4b2202ef7c..3d25fba1c8 100644 --- a/openpilot/starpilot/lateral/tests/test_automatic_learning_source.py +++ b/openpilot/starpilot/lateral/tests/test_automatic_learning_source.py @@ -329,3 +329,50 @@ class TestLearningProjectionPreference(unittest.TestCase): host = self.make_car(HKG.HYUNDAI_IONIQ_6, preference, legacy) assert host.learning_stamp_observer is None assert getattr(host.CI.CC, 'learning_projection_observer', None) is None + + +class TestControlsLearningPreference(unittest.TestCase): + def make_controls(self, vehicle, preference=None, legacy=False): + from openpilot.selfdrive.controls.controlsd import Controls + params = Params() + cp = interfaces[vehicle].get_non_essential_params(vehicle) + params.put('CarParams', cp.to_bytes(), block=True) + params.put_bool('OpenpilotEnabledToggle', True, block=True) + params.put_bool(LEARNING_LEGACY_KEY, legacy, block=True) + if preference is not None: + params.put(LEARNING_KEY, replace_preference(None, cp, preference) if type(preference) is bool else preference, block=True) + before = (params.get(LEARNING_KEY), params.get(TORQUE_KEY)) + host = Controls() + assert before == (params.get(LEARNING_KEY), params.get(TORQUE_KEY)) + return host + + def test_saved_off_skips_actual_controls_learning_runtime(self): + from unittest.mock import patch + from openpilot.selfdrive.controls import controlsd + for vehicle in VEHICLES: + with self.subTest(vehicle=vehicle), OpenpilotPrefix(), patch.object(controlsd, 'GlobalRuntime', wraps=controlsd.GlobalRuntime) as runtime: + host = self.make_controls(vehicle, False) + assert host.global_learning is None + runtime.assert_not_called() + + def test_default_and_explicit_on_keep_actual_runtime(self): + from unittest.mock import patch + from openpilot.selfdrive.controls import controlsd + for vehicle, preference in ((HKG.HYUNDAI_IONIQ_6, None), (GM.CHEVROLET_BOLT_CC_2018_2021, True), + (TOYOTA.TOYOTA_COROLLA_TSS2, True)): + with self.subTest(vehicle=vehicle, preference=preference), OpenpilotPrefix(), \ + patch.object(controlsd, 'GlobalRuntime', wraps=controlsd.GlobalRuntime) as runtime: + host = self.make_controls(vehicle, preference) + assert host.global_learning is not None and type(host.global_learning).__name__ == 'GlobalRuntime' + runtime.assert_called_once() + + def test_scoped_on_wins_over_legacy_off(self): + with OpenpilotPrefix(): + host = self.make_controls(HKG.HYUNDAI_IONIQ_6, True, legacy=True) + assert host.global_learning is not None + + def test_legacy_off_and_invalid_preference_skip_runtime(self): + for preference, legacy in ((None, True), (b'not json', False)): + with self.subTest(preference=preference, legacy=legacy), OpenpilotPrefix(): + host = self.make_controls(HKG.HYUNDAI_IONIQ_6, preference, legacy) + assert host.global_learning is None diff --git a/prebuilt.json b/prebuilt.json index ab22337699..14324847a4 100644 --- a/prebuilt.json +++ b/prebuilt.json @@ -1 +1 @@ -{"protected_inventory_sha256": "4ab96a0de5c3b4741be6c2723f4f24d5fb29619b722a6745fe1158eb13e6fe5b", "schema_version": 1} +{"protected_inventory_sha256": "9a3f182efc3b1d8cf8b51f48ae55dbfae684aa7cf1c92f223f47b88fb7a8f697", "schema_version": 1}