From 013ecbed97522c4321863cdd514bddee922a7e5f Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Mon, 11 May 2026 15:34:33 -0500 Subject: [PATCH] i6 --- .../opendbc/car/hyundai/carcontroller.py | 57 +++++++++++++------ .../opendbc/car/hyundai/tests/test_hyundai.py | 14 ++--- selfdrive/controls/lib/latcontrol_torque.py | 14 ++--- 3 files changed, 54 insertions(+), 31 deletions(-) diff --git a/opendbc_repo/opendbc/car/hyundai/carcontroller.py b/opendbc_repo/opendbc/car/hyundai/carcontroller.py index 4f307de42..57c606698 100644 --- a/opendbc_repo/opendbc/car/hyundai/carcontroller.py +++ b/opendbc_repo/opendbc/car/hyundai/carcontroller.py @@ -54,9 +54,8 @@ IONIQ_6_STOP_RELEASE_JERK_V = [3.6 * IONIQ_6_RESPONSE_MULTIPLIER, 4.2 * IONIQ_6_RESPONSE_MULTIPLIER, 4.8 * IONIQ_6_RESPONSE_MULTIPLIER] IONIQ_6_IPEDAL_PRESS_SEND_COUNT = 6 -IONIQ_6_IPEDAL_LATCH_PRESS_SEND_COUNT = 10 +IONIQ_6_IPEDAL_LATCH_PRESS_SEND_COUNT = 6 IONIQ_6_IPEDAL_PADDLE_BURST_COUNT = 3 -IONIQ_6_IPEDAL_NEXT_COUNTER_BURST_COUNT = 1 IONIQ_6_MAX_REGEN_STATE = 0x3C IONIQ_6_MAX_REGEN_STATE_2 = 0x01 IONIQ_6_IPEDAL_REGEN_STATE = 0x50 @@ -246,6 +245,7 @@ class CarController(CarControllerBase): self._ioniq_6_last_buttons_counter = 0 self._ioniq_6_last_regen_control_counter = -1 self._ioniq_6_regen_request_sent = False + self._ioniq_6_ipedal_latch_counter = -1 self._ioniq_6_last_gear = structs.CarState.GearShifter.unknown self._genesis_g90_long_tuning = GenesisG90LongitudinalTuningState() @@ -254,12 +254,14 @@ class CarController(CarControllerBase): self._ioniq_6_always_ipedal_press_remaining = 0 self._ioniq_6_always_ipedal_retry_frame = 0 self._ioniq_6_regen_request_sent = False + self._ioniq_6_ipedal_latch_counter = -1 def _arm_ioniq_6_always_ipedal(self) -> None: self._ioniq_6_always_ipedal_pending = True self._ioniq_6_always_ipedal_press_remaining = 0 self._ioniq_6_always_ipedal_retry_frame = self.frame self._ioniq_6_regen_request_sent = False + self._ioniq_6_ipedal_latch_counter = -1 def _update_ioniq_6_always_ipedal(self, CC, CS, starpilot_toggles): can_sends = [] @@ -286,6 +288,12 @@ class CarController(CarControllerBase): regen_control_counter_changed = regen_control_counter != self._ioniq_6_last_regen_control_counter max_regen_state = regen_state == IONIQ_6_MAX_REGEN_STATE and regen_state_2 == IONIQ_6_MAX_REGEN_STATE_2 ipedal_latch_pending = regen_state == IONIQ_6_IPEDAL_REGEN_STATE and regen_state_2 == IONIQ_6_IPEDAL_REGEN_STATE_2_PENDING + was_max_regen_state = self._ioniq_6_last_ipedal_regen_state == IONIQ_6_MAX_REGEN_STATE and \ + self._ioniq_6_last_ipedal_regen_state_2 == IONIQ_6_MAX_REGEN_STATE_2 + was_ipedal_latch_pending = self._ioniq_6_last_ipedal_regen_state == IONIQ_6_IPEDAL_REGEN_STATE and \ + self._ioniq_6_last_ipedal_regen_state_2 == IONIQ_6_IPEDAL_REGEN_STATE_2_PENDING + entered_latch_stage = (max_regen_state and not was_max_regen_state) or \ + (ipedal_latch_pending and not was_ipedal_latch_pending) drive = gear == structs.CarState.GearShifter.drive park = gear == structs.CarState.GearShifter.park drive_edge = drive and self._ioniq_6_last_gear != structs.CarState.GearShifter.drive @@ -306,29 +314,46 @@ class CarController(CarControllerBase): self._ioniq_6_always_ipedal_pending = False self._ioniq_6_always_ipedal_press_remaining = 0 + if entered_latch_stage: + self._ioniq_6_always_ipedal_press_remaining = 0 + self._ioniq_6_always_ipedal_retry_frame = self.frame + self._ioniq_6_regen_request_sent = False + self._ioniq_6_ipedal_latch_counter = -1 + if target_gear and self._ioniq_6_always_ipedal_pending and not CS.ipedal_active and not CC.enabled: if self._ioniq_6_always_ipedal_press_remaining == 0 and self.frame >= self._ioniq_6_always_ipedal_retry_frame: self._ioniq_6_always_ipedal_press_remaining = IONIQ_6_IPEDAL_LATCH_PRESS_SEND_COUNT if (max_regen_state or ipedal_latch_pending) \ else IONIQ_6_IPEDAL_PRESS_SEND_COUNT self._ioniq_6_regen_request_sent = False - - # Mirror the current stock counter after seeing the real CRUISE_BUTTONS frame land on the bus. - # A single duplicate was enough to move the cluster-facing state, but not enough to reliably beat - # the stock no-paddle frame for the actual drivetrain latch path. - if self._ioniq_6_always_ipedal_press_remaining > 0 and buttons_counter_changed and \ - 0 <= buttons_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX: - paddle_msg = hyundaicanfd.create_ioniq_6_paddle_buttons(self.packer, self.CP, self.CAN, - buttons_counter, left_paddle=True) - can_sends.extend([paddle_msg] * IONIQ_6_IPEDAL_PADDLE_BURST_COUNT) if max_regen_state or ipedal_latch_pending: - next_counter = hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(buttons_counter) - next_paddle_msg = hyundaicanfd.create_ioniq_6_paddle_buttons(self.packer, self.CP, self.CAN, - next_counter, left_paddle=True) - can_sends.extend([next_paddle_msg] * IONIQ_6_IPEDAL_NEXT_COUNTER_BURST_COUNT) - self._ioniq_6_always_ipedal_press_remaining -= 1 + self._ioniq_6_ipedal_latch_counter = hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(buttons_counter) \ + if 0 <= buttons_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX else -1 + else: + self._ioniq_6_ipedal_latch_counter = -1 + + if self._ioniq_6_always_ipedal_press_remaining > 0: + if max_regen_state or ipedal_latch_pending: + if self._ioniq_6_ipedal_latch_counter < 0 and 0 <= buttons_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX: + self._ioniq_6_ipedal_latch_counter = hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(buttons_counter) + + if 0 <= self._ioniq_6_ipedal_latch_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX: + # A real successful i-Pedal pull is a short held press followed by release, not a continuous hold. + # Mirror that with a stock-like six-counter sequence, then stop transmitting to give the car a release window. + paddle_msg = hyundaicanfd.create_ioniq_6_paddle_buttons(self.packer, self.CP, self.CAN, + self._ioniq_6_ipedal_latch_counter, left_paddle=True) + can_sends.append(paddle_msg) + self._ioniq_6_ipedal_latch_counter = hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(self._ioniq_6_ipedal_latch_counter) + self._ioniq_6_always_ipedal_press_remaining -= 1 + elif buttons_counter_changed and 0 <= buttons_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX: + paddle_msg = hyundaicanfd.create_ioniq_6_paddle_buttons(self.packer, self.CP, self.CAN, + buttons_counter, left_paddle=True) + can_sends.extend([paddle_msg] * IONIQ_6_IPEDAL_PADDLE_BURST_COUNT) + self._ioniq_6_always_ipedal_press_remaining -= 1 + if self._ioniq_6_always_ipedal_press_remaining == 0: retry_wait_frames = IONIQ_6_IPEDAL_PROGRESS_RETRY_WAIT_FRAMES if regen_state_changed else IONIQ_6_IPEDAL_RETRY_WAIT_FRAMES self._ioniq_6_always_ipedal_retry_frame = self.frame + retry_wait_frames + self._ioniq_6_ipedal_latch_counter = -1 # The drivetrain latch uses a second HKG CAN-FD request path in addition to the left paddle bit. # Mirror the next stock 0x25A frame once per retry burst instead of spamming it continuously. diff --git a/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py b/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py index 2fa9be021..d27ad7cdc 100644 --- a/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py +++ b/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py @@ -8,7 +8,7 @@ from opendbc.car import Bus, ButtonType, gen_empty_fingerprint, structs from opendbc.car.structs import CarControl, CarParams from opendbc.car.fw_versions import build_fw_dict, match_fw_to_car from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalTuningState, GenesisG90LongitudinalTuningState, \ - IONIQ_6_IPEDAL_PADDLE_BURST_COUNT, IONIQ_6_IPEDAL_NEXT_COUNTER_BURST_COUNT, \ + IONIQ_6_IPEDAL_PADDLE_BURST_COUNT, \ update_ioniq_6_longitudinal_tuning, \ update_genesis_g90_longitudinal_tuning from opendbc.car.hyundai.carstate import CarState, decode_ioniq_6_blindspot_radar_state, decode_ioniq_6_ipedal_intermediate_state, \ @@ -484,7 +484,8 @@ class TestHyundaiFingerprint: sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles) assert sends - assert controller._ioniq_6_always_ipedal_press_remaining == 9 + assert [msg[1].hex() for msg in sends if msg[0] == 0x1CF] == ["9060002800000000"] + assert controller._ioniq_6_always_ipedal_press_remaining == 5 def test_ioniq_6_always_ipedal_sends_regen_control_companion_once_max_regen_is_shown(self): toggles = get_test_toggles() @@ -550,13 +551,12 @@ class TestHyundaiFingerprint: sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles) paddle_msgs = [msg for msg in sends if msg[0] == 0x1CF] - assert len(paddle_msgs) == IONIQ_6_IPEDAL_PADDLE_BURST_COUNT + IONIQ_6_IPEDAL_NEXT_COUNTER_BURST_COUNT - assert [msg[1].hex() for msg in paddle_msgs[:IONIQ_6_IPEDAL_PADDLE_BURST_COUNT]] == ["4650002800000000"] * IONIQ_6_IPEDAL_PADDLE_BURST_COUNT - assert [msg[1].hex() for msg in paddle_msgs[IONIQ_6_IPEDAL_PADDLE_BURST_COUNT:]] == ["9060002800000000"] * IONIQ_6_IPEDAL_NEXT_COUNTER_BURST_COUNT + assert [msg[1].hex() for msg in paddle_msgs] == ["9060002800000000"] regen_cmd = next(msg for msg in sends if msg[0] == 0x25A) assert regen_cmd[1][24:28] == bytes.fromhex("c00c1200") checksum = hyundaicanfd.hkg_can_fd_checksum(regen_cmd[0], None, bytearray(regen_cmd[1])) assert regen_cmd[1][0] | (regen_cmd[1][1] << 8) == checksum + assert controller._ioniq_6_always_ipedal_press_remaining == 5 controller.frame = 1 cs.buttons_counter = 6 @@ -564,9 +564,7 @@ class TestHyundaiFingerprint: sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles) paddle_msgs = [msg for msg in sends if msg[0] == 0x1CF] - assert len(paddle_msgs) == IONIQ_6_IPEDAL_PADDLE_BURST_COUNT + IONIQ_6_IPEDAL_NEXT_COUNTER_BURST_COUNT - assert [msg[1].hex() for msg in paddle_msgs[:IONIQ_6_IPEDAL_PADDLE_BURST_COUNT]] == ["9060002800000000"] * IONIQ_6_IPEDAL_PADDLE_BURST_COUNT - assert [msg[1].hex() for msg in paddle_msgs[IONIQ_6_IPEDAL_PADDLE_BURST_COUNT:]] == ["2970002800000000"] * IONIQ_6_IPEDAL_NEXT_COUNTER_BURST_COUNT + assert [msg[1].hex() for msg in paddle_msgs] == ["2970002800000000"] assert not any(msg[0] == 0x25A for msg in sends) def test_ioniq_6_longitudinal_params_match_canfd_tune(self): diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 5b2e11342..3abdd6d52 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -284,18 +284,18 @@ IONIQ_6_TRANSITION_SPEED = 10.0 IONIQ_6_PHASE_SCALE = 0.10 IONIQ_6_TURN_IN_BOOST_LEFT = 1.58 IONIQ_6_TURN_IN_BOOST_RIGHT = 1.82 -IONIQ_6_UNWIND_TAPER_LEFT = 2.84 +IONIQ_6_UNWIND_TAPER_LEFT = 3.05 IONIQ_6_UNWIND_TAPER_RIGHT = 6.35 IONIQ_6_FRICTION_MULT = 0.928 IONIQ_6_FRICTION_LAT_RISE = 0.20 IONIQ_6_FRICTION_JERK_RISE = 0.24 IONIQ_6_TURN_IN_THRESHOLD_REDUCTION_LEFT = 0.74 IONIQ_6_TURN_IN_THRESHOLD_REDUCTION_RIGHT = 1.18 -IONIQ_6_UNWIND_THRESHOLD_INCREASE_LEFT = 3.35 +IONIQ_6_UNWIND_THRESHOLD_INCREASE_LEFT = 3.70 IONIQ_6_UNWIND_THRESHOLD_INCREASE_RIGHT = 7.85 IONIQ_6_TURN_IN_FRICTION_BOOST_LEFT = 0.40 IONIQ_6_TURN_IN_FRICTION_BOOST_RIGHT = 0.72 -IONIQ_6_UNWIND_FRICTION_REDUCTION_LEFT = 3.10 +IONIQ_6_UNWIND_FRICTION_REDUCTION_LEFT = 3.35 IONIQ_6_UNWIND_FRICTION_REDUCTION_RIGHT = 7.30 IONIQ_6_CENTER_TAPER_MAX = 0.082 IONIQ_6_CENTER_TAPER_LAT = 0.24 @@ -311,9 +311,9 @@ IONIQ_6_LOW_MID_CENTER_TAPER_SPEED_WIDTH = 1.5 IONIQ_6_DIRECTIONAL_TAPER_LAT_START = 0.19 IONIQ_6_DIRECTIONAL_TAPER_LAT_END = 0.90 IONIQ_6_DIRECTIONAL_TAPER_LAT_WIDTH = 0.06 -IONIQ_6_DIRECTIONAL_TAPER_BASE_LEFT = 0.14 -IONIQ_6_DIRECTIONAL_TAPER_BASE_RIGHT = 0.48 -IONIQ_6_DIRECTIONAL_TAPER_UNWIND_LEFT = 1.64 +IONIQ_6_DIRECTIONAL_TAPER_BASE_LEFT = 0.13 +IONIQ_6_DIRECTIONAL_TAPER_BASE_RIGHT = 0.45 +IONIQ_6_DIRECTIONAL_TAPER_UNWIND_LEFT = 1.82 IONIQ_6_DIRECTIONAL_TAPER_UNWIND_RIGHT = 3.28 IONIQ_6_DIRECTIONAL_TAPER_FLOOR_LEFT = 0.48 IONIQ_6_DIRECTIONAL_TAPER_FLOOR_RIGHT = 0.52 @@ -325,7 +325,7 @@ IONIQ_6_HEAVY_DIRECTIONAL_TAPER_LAT_START = 0.82 IONIQ_6_HEAVY_DIRECTIONAL_TAPER_LAT_WIDTH = 0.12 IONIQ_6_HEAVY_DIRECTIONAL_TAPER_BASE_LEFT = 0.10 IONIQ_6_HEAVY_DIRECTIONAL_TAPER_BASE_RIGHT = 0.17 -IONIQ_6_HEAVY_DIRECTIONAL_TAPER_UNWIND_LEFT = 0.56 +IONIQ_6_HEAVY_DIRECTIONAL_TAPER_UNWIND_LEFT = 0.62 IONIQ_6_HEAVY_DIRECTIONAL_TAPER_UNWIND_RIGHT = 0.94 IONIQ_6_OUTPUT_TAPER_SPEED = 8.5 IONIQ_6_OUTPUT_TAPER_SPEED_WIDTH = 2.5