diff --git a/opendbc_repo/opendbc/car/fingerprints.py b/opendbc_repo/opendbc/car/fingerprints.py index 544e413c4..2eefbd0ca 100644 --- a/opendbc_repo/opendbc/car/fingerprints.py +++ b/opendbc_repo/opendbc/car/fingerprints.py @@ -72,6 +72,7 @@ MIGRATION = { "HONDA CR-V 2016 TOURING": HONDA.HONDA_CRV, "HONDA CR-V 2017 EX": HONDA.HONDA_CRV_5G, "HONDA CR-V 2019 HYBRID": HONDA.HONDA_CRV_HYBRID, + "HONDA CLARITY 2018": HONDA.HONDA_CLARITY, "HONDA FIT 2018 EX": HONDA.HONDA_FIT, "HONDA HRV 2019 TOURING": HONDA.HONDA_HRV, "HONDA INSIGHT 2019 TOURING": HONDA.HONDA_INSIGHT, diff --git a/opendbc_repo/opendbc/car/honda/fingerprints.py b/opendbc_repo/opendbc/car/honda/fingerprints.py index a7c21d001..7d7cb8780 100644 --- a/opendbc_repo/opendbc/car/honda/fingerprints.py +++ b/opendbc_repo/opendbc/car/honda/fingerprints.py @@ -143,6 +143,29 @@ FW_VERSIONS = { b'38897-TWD-J020\x00\x00', ], }, + CAR.HONDA_CLARITY: { + (Ecu.shiftByWire, 0x18da0bf1, None): [ + b'54008-TRW-A910\x00\x00', + ], + (Ecu.vsa, 0x18da28f1, None): [ + b'57114-TRW-A010\x00\x00', + b'57114-TRW-A020\x00\x00', + ], + (Ecu.eps, 0x18da30f1, None): [ + b'39990-TRW-A020\x00\x00', + b'39990-TRW,A020\x00\x00', + ], + (Ecu.srs, 0x18da53f1, None): [ + b'77959-TRW-A210\x00\x00', + b'77959-TRW-A220\x00\x00', + ], + (Ecu.gateway, 0x18daeff1, None): [ + b'38897-TRW-A010\x00\x00', + ], + (Ecu.fwdRadar, 0x18dab0f1, None): [ + b'36161-TRW-A110\x00\x00', + ], + }, CAR.HONDA_CIVIC: { (Ecu.transmission, 0x18da1ef1, None): [ b'28101-5CG-A040\x00\x00', diff --git a/opendbc_repo/opendbc/car/honda/interface.py b/opendbc_repo/opendbc/car/honda/interface.py index 54aefdecf..dbf83ac81 100644 --- a/opendbc_repo/opendbc/car/honda/interface.py +++ b/opendbc_repo/opendbc/car/honda/interface.py @@ -172,6 +172,11 @@ class CarInterface(CarInterfaceBase): else: ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] # TODO: can probably use some tuning + elif candidate == CAR.HONDA_CLARITY: + ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] + ret.stopAccel = 0.0 + elif candidate == CAR.ACURA_RDX: ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] @@ -235,7 +240,7 @@ class CarInterface(CarInterfaceBase): # min speed to enable ACC. if car can do stop and go, then set enabling speed # to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not # conflict with PCM acc - ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC}) + ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC, CAR.HONDA_CLARITY}) ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.51 * CV.MPH_TO_MS ret.steerLimitTimer = 0.8 diff --git a/opendbc_repo/opendbc/car/honda/tests/test_honda.py b/opendbc_repo/opendbc/car/honda/tests/test_honda.py index 255373c0a..01aefeeea 100644 --- a/opendbc_repo/opendbc/car/honda/tests/test_honda.py +++ b/opendbc_repo/opendbc/car/honda/tests/test_honda.py @@ -139,3 +139,25 @@ class TestHondaFingerprint: assert list(CP.lateralParams.torqueV) == [0, 4096] assert list(CP.lateralTuning.pid.kpV) == pytest.approx([0.8]) assert list(CP.lateralTuning.pid.kiV) == pytest.approx([0.24]) + + def test_honda_clarity_supports_pid_and_torque_paths(self): + pid_toggles = SimpleNamespace(force_torque_controller=False, nnff=False, nnff_lite=False) + car_fw = [CarParams.CarFw(ecu=CarParams.Ecu.eps, fwVersion=b'39990-TRW,A020\x00\x00', address=0x18DA30F1, subAddress=0)] + + pid_cp = CarInterface.get_params(CAR.HONDA_CLARITY, gen_empty_fingerprint(), car_fw, False, False, False, pid_toggles) + + assert not pid_cp.dashcamOnly + assert pid_cp.flags & HondaFlags.EPS_MODIFIED + assert pid_cp.lateralTuning.which() == "pid" + assert list(pid_cp.lateralParams.torqueBP) == [0, 2560] + assert list(pid_cp.lateralParams.torqueV) == [0, 2560] + assert list(pid_cp.lateralTuning.pid.kpV) == pytest.approx([0.8]) + assert list(pid_cp.lateralTuning.pid.kiV) == pytest.approx([0.24]) + assert pid_cp.autoResumeSng + assert pid_cp.minEnableSpeed == pytest.approx(-1.0) + assert pid_cp.stopAccel == pytest.approx(0.0) + + torque_toggles = SimpleNamespace(force_torque_controller=True, nnff=False, nnff_lite=False) + torque_cp = CarInterface.get_params(CAR.HONDA_CLARITY, gen_empty_fingerprint(), car_fw, False, False, False, torque_toggles) + + assert torque_cp.lateralTuning.which() == "torque" diff --git a/opendbc_repo/opendbc/car/honda/values.py b/opendbc_repo/opendbc/car/honda/values.py index e086fcb9f..7456642d5 100644 --- a/opendbc_repo/opendbc/car/honda/values.py +++ b/opendbc_repo/opendbc/car/honda/values.py @@ -323,6 +323,12 @@ class CAR(Platforms): radar_dbc_dict('acura_ilx_2016_can_generated'), flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES, ) + HONDA_CLARITY = HondaNidecPlatformConfig( + [HondaCarDocs("Honda Clarity 2018-21", "All", min_steer_speed=3. * CV.MPH_TO_MS)], + CarSpecs(mass=1838, wheelbase=2.75, centerToFrontRatio=0.4, steerRatio=16.5), + radar_dbc_dict('honda_clarity_hybrid_2018_can_generated'), + flags=HondaFlags.HAS_ALL_DOOR_STATES, + ) HONDA_ODYSSEY = HondaNidecPlatformConfig( [HondaCarDocs("Honda Odyssey 2018-20")], CarSpecs(mass=1900, wheelbase=3.0, steerRatio=14.35, centerToFrontRatio=0.41, tireStiffnessFactor=0.82), diff --git a/opendbc_repo/opendbc/car/torque_data/substitute.toml b/opendbc_repo/opendbc/car/torque_data/substitute.toml index 4d8fa581d..389bb07ca 100644 --- a/opendbc_repo/opendbc/car/torque_data/substitute.toml +++ b/opendbc_repo/opendbc/car/torque_data/substitute.toml @@ -49,6 +49,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "GENESIS_G70_2020" = "HYUNDAI_SONATA" "HONDA_FREED" = "HONDA_ODYSSEY" +"HONDA_CLARITY" = "HONDA_ACCORD" "HONDA_CRV_EU" = "HONDA_CRV" "HONDA_CIVIC_BOSCH_DIESEL" = "HONDA_CIVIC_BOSCH" "HONDA_E" = "HONDA_CIVIC_BOSCH" diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 83ca66b1d..4e58f5546 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -201,8 +201,6 @@ GENESIS_G90_TURN_IN_FRICTION_BOOST_RIGHT = 0.12 GENESIS_G90_UNWIND_FRICTION_REDUCTION_LEFT = 0.14 GENESIS_G90_UNWIND_FRICTION_REDUCTION_RIGHT = 0.22 -IONIQ_6_LATERAL_TESTING_GROUND_ID = testing_ground.id_5 -IONIQ_6_LATERAL_TESTING_GROUND_VARIANT = "C" IONIQ_6_FF_GAIN_LEFT = 0.040 IONIQ_6_FF_GAIN_RIGHT = 0.000 IONIQ_6_FF_ONSET = 0.10 @@ -240,10 +238,14 @@ IONIQ_6_LOW_MID_CENTER_TAPER_SPEED_WIDTH = 1.5 IONIQ_6_DIRECTIONAL_TAPER_LAT_START = 0.15 IONIQ_6_DIRECTIONAL_TAPER_LAT_END = 0.90 IONIQ_6_DIRECTIONAL_TAPER_LAT_WIDTH = 0.08 -IONIQ_6_DIRECTIONAL_TAPER_BASE_LEFT = 0.05 -IONIQ_6_DIRECTIONAL_TAPER_BASE_RIGHT = 0.47 -IONIQ_6_DIRECTIONAL_TAPER_UNWIND_LEFT = 1.00 -IONIQ_6_DIRECTIONAL_TAPER_UNWIND_RIGHT = 2.65 +IONIQ_6_DIRECTIONAL_TAPER_BASE_LEFT = 0.10 +IONIQ_6_DIRECTIONAL_TAPER_BASE_RIGHT = 0.40 +IONIQ_6_DIRECTIONAL_TAPER_UNWIND_LEFT = 1.20 +IONIQ_6_DIRECTIONAL_TAPER_UNWIND_RIGHT = 2.30 +IONIQ_6_DIRECTIONAL_TAPER_FLOOR_LEFT = 0.54 +IONIQ_6_DIRECTIONAL_TAPER_FLOOR_RIGHT = 0.60 +IONIQ_6_DIRECTIONAL_TAPER_UNWIND_FLOOR_LEFT = 0.10 +IONIQ_6_DIRECTIONAL_TAPER_UNWIND_FLOOR_RIGHT = 0.04 IONIQ_6_OUTPUT_TAPER_SPEED = 8.5 IONIQ_6_OUTPUT_TAPER_SPEED_WIDTH = 2.5 IONIQ_6_OUTPUT_CENTER_TAPER_BLEND = 0.90 @@ -680,10 +682,6 @@ def get_genesis_g90_friction_scale(v_ego: float, desired_lateral_accel: float, d return min(max(friction_scale, 0.92), 1.12) -def ioniq_6_lateral_testing_ground_active() -> bool: - return testing_ground.use(IONIQ_6_LATERAL_TESTING_GROUND_ID, IONIQ_6_LATERAL_TESTING_GROUND_VARIANT) - - def _ioniq_6_sigmoid(x: float) -> float: return _sigmoid(x) @@ -780,7 +778,8 @@ def get_ioniq_6_directional_taper_scale(desired_lateral_accel: float, desired_la base_reduction = _ioniq_6_side_value(desired_lateral_accel, IONIQ_6_DIRECTIONAL_TAPER_BASE_LEFT, IONIQ_6_DIRECTIONAL_TAPER_BASE_RIGHT) unwind_reduction = _ioniq_6_side_value(desired_lateral_accel, IONIQ_6_DIRECTIONAL_TAPER_UNWIND_LEFT, IONIQ_6_DIRECTIONAL_TAPER_UNWIND_RIGHT) reduction = band_weight * (base_reduction + unwind_reduction * unwind_weight) - floor = 0.56 - (0.06 * unwind_weight) + floor = _ioniq_6_side_value(desired_lateral_accel, IONIQ_6_DIRECTIONAL_TAPER_FLOOR_LEFT, IONIQ_6_DIRECTIONAL_TAPER_FLOOR_RIGHT) + floor -= _ioniq_6_side_value(desired_lateral_accel, IONIQ_6_DIRECTIONAL_TAPER_UNWIND_FLOOR_LEFT, IONIQ_6_DIRECTIONAL_TAPER_UNWIND_FLOOR_RIGHT) * unwind_weight return max(1.0 - reduction, floor) @@ -1052,7 +1051,7 @@ class LatControlTorque(LatControl): bolt_2018_2021_tuned_path_active = self.is_bolt_2018_2021 volt_standard_test_active = self.is_volt_standard and volt_standard_lateral_testing_ground_active() genesis_g90_test_active = self.is_genesis_g90 and genesis_g90_lateral_testing_ground_active() - ioniq_6_test_active = self.is_ioniq_6 and ioniq_6_lateral_testing_ground_active() + ioniq_6_test_active = self.is_ioniq_6 kia_ev6_test_active = self.is_kia_ev6 and kia_ev6_lateral_testing_ground_active() volt_plexy_test_active = self.is_volt_cc and volt_plexy_lateral_testing_ground_active() volt_standard_center_taper = get_volt_standard_center_taper_scale(setpoint, CS.vEgo) if volt_standard_test_active else 1.0 diff --git a/selfdrive/controls/tests/test_latcontrol.py b/selfdrive/controls/tests/test_latcontrol.py index 33a768901..cd6b70ac8 100644 --- a/selfdrive/controls/tests/test_latcontrol.py +++ b/selfdrive/controls/tests/test_latcontrol.py @@ -359,9 +359,8 @@ class TestLatControl: assert lac_log.active - def test_ioniq_6_testing_ground_update_path(self, monkeypatch): + def test_ioniq_6_default_update_path(self): controller, VM, CS, params, starpilot_toggles = self._build_torque_controller(HYUNDAI.HYUNDAI_IONIQ_6) - monkeypatch.setattr(latcontrol_torque, "ioniq_6_lateral_testing_ground_active", lambda: True) _, _, lac_log = controller.update(True, CS, VM, params, False, 0.0025, False, 0.2, None, None, starpilot_toggles) diff --git a/starpilot/common/testing_grounds.py b/starpilot/common/testing_grounds.py index a8803a58a..1235b6cfa 100644 --- a/starpilot/common/testing_grounds.py +++ b/starpilot/common/testing_grounds.py @@ -63,10 +63,9 @@ TESTING_GROUNDS_SLOT_DEFINITIONS = ( }, { "id": TESTING_GROUND_5, - "name": "Ioniq 6 Lateral", - "description": "Hyundai Ioniq 6 lateral sandbox.", + "name": "Unused", + "description": "Unused slot.", "aLabel": "A - Installed tune", - "cLabel": "C - Firestar Tune", }, { "id": TESTING_GROUND_6, diff --git a/starpilot/common/tests/test_testing_grounds.py b/starpilot/common/tests/test_testing_grounds.py index 86640f22f..db4447e06 100644 --- a/starpilot/common/tests/test_testing_grounds.py +++ b/starpilot/common/tests/test_testing_grounds.py @@ -30,3 +30,27 @@ 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_hidden_slot_invalid_variant_is_migrated_off_slot(tmp_path, monkeypatch): + state_path = tmp_path / "slots.json" + state_path.write_text(json.dumps({ + "schemaVersion": tg.TESTING_GROUNDS_SCHEMA_VERSION, + "activeSlot": tg.TESTING_GROUND_5, + "activeVariant": "C", + }), encoding="utf-8") + + monkeypatch.setattr(tg, "TESTING_GROUNDS_STATE_PATH", state_path) + monkeypatch.setattr(tg, "_CACHE_LAST_REFRESH", 0.0) + monkeypatch.setattr(tg, "_CACHE_LAST_MTIME_NS", -1) + monkeypatch.setattr(tg, "_CACHE_ACTIVE_SLOT", tg._DEFAULT_ACTIVE_SLOT) + monkeypatch.setattr(tg, "_CACHE_ACTIVE_VARIANT", tg.DEFAULT_TESTING_GROUND_VARIANT) + + active_slot, active_variant = tg.get_testing_ground_selection(refresh_interval_s=0.0) + + assert active_slot == tg.TESTING_GROUND_1 + assert active_variant == tg.DEFAULT_TESTING_GROUND_VARIANT + + 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