fix: IONIQ_5_PE Enable Long and fix Check Driver Assistance alerts

Co-authored-by: otaku <696343+otaku@users.noreply.github.com>
This commit is contained in:
firestar5683
2026-08-06 16:38:23 -05:00
parent 9798511e2e
commit 5d5a04416a
6 changed files with 109 additions and 23 deletions
@@ -76,7 +76,7 @@ BLINDSPOT_WARNING_SOUND_SAMPLES = 36
def egmp_dynamic_longitudinal_tuning(CP) -> bool:
return CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9) or \
return CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE) or \
kia_ev6_gt_line_longitudinal_tuning(CP.carFingerprint, getattr(CP, "carVin", ""))
@@ -411,7 +411,7 @@ class CarController(CarControllerBase):
self.ecu_disable_failed = False
self._ecu_disable_checked = False
self._params = Params()
if CP.carFingerprint == CAR.KIA_EV9:
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
self._ev9_long_tuning = EV9LongitudinalTuningState()
self._left_blindspot_warning = BlindspotWarningState()
self._right_blindspot_warning = BlindspotWarningState()
@@ -515,6 +515,8 @@ class CarController(CarControllerBase):
drive_gear = CS.out.gearShifter == structs.CarState.GearShifter.drive
angle_lat_active = direct_angle_request_allowed(CS.out.vEgoRaw, measured_steering_angle, self.apply_angle_last,
drive_gear, self.BASELINE_VM, self.params) and not CS.angle_steering_fault
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_5_PE and CS.out.standstill:
angle_lat_active = False
self.direct_angle_request_allowed = angle_lat_active
apply_angle = measured_steering_angle
@@ -597,8 +599,8 @@ class CarController(CarControllerBase):
use_egmp_dynamic_long_tuning = egmp_dynamic_longitudinal_tuning(self.CP) and self.long_active_ecu and \
actuators.longControlState in (LongCtrlState.starting, LongCtrlState.pid, LongCtrlState.stopping)
is_ev6_gt_line = kia_ev6_gt_line_longitudinal_tuning(self.CP.carFingerprint, getattr(self.CP, "carVin", ""))
is_ev9 = self.CP.carFingerprint == CAR.KIA_EV9
if is_ev9 and (self._ev9_long_tuning.stop_request or not CC.enabled or CC.cruiseControl.override):
is_ccnc_angle_long = self.CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR
if is_ccnc_angle_long and (self._ev9_long_tuning.stop_request or not CC.enabled or CC.cruiseControl.override):
self._ioniq_6_long_tuning = reset_egmp_longitudinal_tuning(self._ioniq_6_long_tuning)
if should_reset_ev6_gt_line_longitudinal_tuning(self.CP, actuators.longControlState):
self._ioniq_6_long_tuning = reset_ev6_gt_line_longitudinal_tuning(self._ioniq_6_long_tuning, self.CP,
@@ -608,7 +610,7 @@ class CarController(CarControllerBase):
CS.out.vEgo, CS.out.aEgo,
actuators.longControlState, self.long_active_ecu,
ev6_gt_line=is_ev6_gt_line,
low_speed_stop_brake_cap=is_ev9)
low_speed_stop_brake_cap=is_ccnc_angle_long)
use_egmp_smoothed_accel = use_egmp_dynamic_long_tuning and (
accel_cmd >= self._ioniq_6_long_tuning.actual_accel or
self._ioniq_6_long_tuning.launch_active or
@@ -617,7 +619,7 @@ class CarController(CarControllerBase):
if should_use_ev6_gt_line_stop_direct_tracking(is_ev6_gt_line, self._ioniq_6_long_tuning.stopping,
CS.out.vEgo, accel_cmd, self._ioniq_6_long_tuning.actual_accel):
use_egmp_smoothed_accel = False
if is_ev9 and should_track_stop_accel_directly(self._ioniq_6_long_tuning.stopping, CS.out.vEgo,
if is_ccnc_angle_long and should_track_stop_accel_directly(self._ioniq_6_long_tuning.stopping, CS.out.vEgo,
accel_cmd, self._ioniq_6_long_tuning.actual_accel):
use_egmp_smoothed_accel = False
if use_egmp_dynamic_long_tuning:
+1 -1
View File
@@ -138,7 +138,7 @@ class CarState(CarStateBase):
self.blindspots_front_corner_1_ts = 0
self.left_blindspot_from_radar = False
self.right_blindspot_from_radar = False
if CP.carFingerprint == CAR.KIA_EV9:
if CP.carFingerprint in CANFD_ANGLE_LONGITUDINAL_CAR:
self.hba_icon = 0
self.main_cruise_on = False
self.angle_steering_angle = 0.0
@@ -843,6 +843,7 @@ def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
# brake, and accelerator bits are updated for the radar heartbeat.
_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000")
_KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("00000000ff006f00e80400001201030055ffff0000000000")
_HYUNDAI_IONIQ_5_PE_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000000000000000000000ff1fffff55ffff00a8000000")
# Neutral bodies verified across stock and successful suppression routes. Only
# rolling integrity fields and the decoded state above are changed at runtime.
_CCNC_ADRV_TEMPLATES = {
@@ -859,6 +860,19 @@ _CCNC_ADRV_TEMPLATES = {
0x1E0: bytes.fromhex("00000002000000000000000000000000"),
0x38C: bytes.fromhex("000000f71f000000000000000000000000000000000000000000000000000000"),
},
CAR.HYUNDAI_IONIQ_5_PE: {
0x160: bytes.fromhex("0000000000000000fffc0100a8001000"),
0x1DA: bytes.fromhex("0000002200010000000000000000000000000000000000000000000000000000"),
0x1EA: bytes.fromhex("000000080000000000000000000000ff000000000000000000000000000f0f00"),
0x200: bytes.fromhex("00000014401b0000"),
0x345: bytes.fromhex("0000001500560000"),
0x161: bytes.fromhex("0000000000000000c0fff0c003000040000000000000000000ff000000000000"),
0x162: bytes.fromhex("0000002700000000c0ff00000000000000000000000000000000000000000000"),
0x1BA: bytes.fromhex("00000000000000880200000000000000000100000000000f"),
0x1E5: bytes.fromhex("00000000000000000000220200000080"),
0x1E0: bytes.fromhex("00000002000000000000000000000000"),
0x38C: bytes.fromhex("000000f79f000000000000000000000000000000000000000000000000000000"),
},
}
_CCNC_ADRV_PERIODS = {
CAR.KIA_EV9: {
@@ -870,12 +884,26 @@ _CCNC_ADRV_PERIODS = {
0x1E0: 5,
0x38C: 20,
},
CAR.HYUNDAI_IONIQ_5_PE: {
0x160: 2,
0x1DA: 100,
0x1EA: 5,
0x200: 5,
0x345: 20,
0x1E0: 5,
0x38C: 20,
},
}
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool,
car_fingerprint=None) -> CanData:
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE if car_fingerprint == CAR.KIA_EV9 else _ACCEL_BRAKE_ALT_TEMPLATE
if car_fingerprint == CAR.KIA_EV9:
template = _KIA_EV9_ACCEL_BRAKE_ALT_TEMPLATE
elif car_fingerprint == CAR.HYUNDAI_IONIQ_5_PE:
template = _HYUNDAI_IONIQ_5_PE_ACCEL_BRAKE_ALT_TEMPLATE
else:
template = _ACCEL_BRAKE_ALT_TEMPLATE
d = bytearray(template)
d[2] = counter & 0xFF # COUNTER (bit 16, 8-bit)
d[4] = (d[4] & ~0x01) | (0x01 if brake_pressed else 0x00) # BRAKE_PRESSED (bit 32)
@@ -171,6 +171,8 @@ class CarInterface(CarInterfaceBase):
# panda safety or the carcontroller; the MDPS tolerating held torque at 0 speed
# is being validated on-road.
ret.steerAtStandstill = True
if candidate == CAR.HYUNDAI_IONIQ_5_PE:
ret.steerAtStandstill = True
if ret.flags & HyundaiFlags.CCNC and not ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CCNC.value
@@ -287,6 +289,10 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kiBP = [0.0, 8.0, 20.0, 35.0]
ret.longitudinalTuning.kiV = [0.02, 0.03, 0.05, 0.07]
if candidate == CAR.HYUNDAI_IONIQ_5_PE:
ret.longitudinalActuatorDelay = 0.35
ret.vEgoStarting = 0.4
if candidate == CAR.KIA_EV9 and ret.openpilotLongitudinalControl:
apply_kia_ev9_longitudinal_params(ret)
@@ -335,8 +341,8 @@ class CarInterface(CarInterfaceBase):
ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control,
reset=bool(CP.flags & HyundaiFlags.CAN_CANFD_BLENDED))
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
# Ioniq 6: track success/failure to auto-switch between openpilot long and stock ACC
if CP.carFingerprint in (CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_IONIQ_5_PE):
# Track success/failure to auto-switch between openpilot long and stock ACC
if ecu_disabled:
ECU_DISABLE_TIMESTAMP = time.monotonic()
params.put_bool("EcuDisableFailed", False)
@@ -182,6 +182,7 @@ class TestHyundaiFingerprint:
for candidate, radar_addr in (
(CAR.HYUNDAI_KONA_EV_2022, MRREVO14F_RADAR_START_ADDR),
(CAR.HYUNDAI_IONIQ_5, MRR30_RADAR_START_ADDR),
(CAR.HYUNDAI_IONIQ_5_PE, MRR35_RADAR_START_ADDR),
(CAR.HYUNDAI_IONIQ_5_N, MRR30_RADAR_START_ADDR),
(CAR.KIA_EV6, MRR30_RADAR_START_ADDR),
(CAR.KIA_EV6_2025, MRR30_RADAR_START_ADDR),
@@ -268,6 +269,32 @@ class TestHyundaiFingerprint:
CP = CarInterface.get_params(CAR.KIA_EV9, fingerprint, ev9_car_fw, False, False, False, None)
assert not CP.openpilotLongitudinalControl
assert not (CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CCNC)
ioniq_5_pe_radar_config = get_radar_track_config(CAR.HYUNDAI_IONIQ_5_PE)
fingerprint = gen_empty_fingerprint()
fingerprint[CanBus(None, fingerprint).CAM][0x110] = 32
fingerprint[ioniq_5_pe_radar_config.bus][ioniq_5_pe_radar_config.start_addr] = ioniq_5_pe_radar_config.expected_length
ioniq_5_pe_car_fw = [CarParams.CarFw(ecu=Ecu.adas, fwVersion=b"", address=0x730, brand="hyundai")]
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_5_PE, fingerprint, ioniq_5_pe_car_fw, True, False, False, None)
assert CP.alphaLongitudinalAvailable
assert CP.openpilotLongitudinalControl
assert not CP.radarUnavailable
assert CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
assert CP.flags & HyundaiFlags.CCNC
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CANFD_ANGLE_STEERING
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CCNC
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_5_PE, fingerprint, ioniq_5_pe_car_fw, False, False, False, None)
assert not CP.openpilotLongitudinalControl
assert not (CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG)
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_5_PE, fingerprint, ioniq_5_pe_car_fw, True, False, False, None)
expected_bits = (HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CCNC |
HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT |
HyundaiSafetyFlags.CANFD_ANGLE_STEERING | HyundaiSafetyFlags.EV_GAS)
assert (CP.safetyConfigs[-1].safetyParam & expected_bits) == expected_bits
for candidate in HYUNDAI_NON_SCC_CARS:
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], True, False, False, None)
assert bool(CP.flags & HyundaiFlags.NON_SCC)
@@ -320,13 +347,13 @@ class TestHyundaiFingerprint:
assert direct_angle_request_allowed(8.47, 140.0, 140.0, True, controller.BASELINE_VM, controller.params)
assert not direct_angle_request_allowed(8.47, 140.0, 140.0, False, controller.BASELINE_VM, controller.params)
def test_angle_platforms_disable_standstill_steering(self):
def test_angle_platforms_standstill_steering_flags(self):
ev9_cp = CarInterface.get_params(CAR.KIA_EV9, gen_empty_fingerprint(), [], False, False, False, None)
ioniq_5_pe_cp = CarInterface.get_params(CAR.HYUNDAI_IONIQ_5_PE, gen_empty_fingerprint(), [], False, False, False, None)
sportage_cp = CarInterface.get_params(CAR.KIA_SPORTAGE_HEV_2026, gen_empty_fingerprint(), [], False, False, False, None)
assert not ev9_cp.steerAtStandstill
assert not ioniq_5_pe_cp.steerAtStandstill
assert ioniq_5_pe_cp.steerAtStandstill
assert not sportage_cp.steerAtStandstill
@pytest.mark.parametrize("candidate", (CAR.KIA_K4_2025, CAR.KIA_CARNIVAL_2025, CAR.KIA_CARNIVAL_HEV_4TH_GEN))
@@ -1233,6 +1260,12 @@ class TestHyundaiFingerprint:
ioniq_6_cp = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, gen_empty_fingerprint(), [], True, False, False, toggles)
assert CarInterface.get_pid_accel_limits(ioniq_6_cp, 0.0, 0.0)[1] == pytest.approx(CarControllerParams.ACCEL_MAX)
def test_ioniq_5_pe_longitudinal_params_match_observed_response(self):
toggles = get_test_toggles()
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_5_PE, gen_empty_fingerprint(), [], True, False, False, toggles)
assert CP.longitudinalActuatorDelay == pytest.approx(0.35)
assert CP.vEgoStarting == pytest.approx(0.4)
def test_ioniq_6_longitudinal_tuning_helper_matches_dynamic_profile(self):
state = Ioniq6LongitudinalTuningState()
@@ -1342,6 +1375,14 @@ class TestHyundaiFingerprint:
assert not should_use_ev6_gt_line_stop_direct_tracking(False, True, 1.8, -2.05, -1.29)
assert not should_use_ev6_gt_line_stop_direct_tracking(True, True, 1.8, -1.0, -1.29)
@pytest.mark.parametrize("candidate", (CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE))
def test_ccnc_angle_long_carcontroller_initializes_ev9_tuning_state(self, candidate):
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], True, False, False, None)
controller = CarController(DBC[CP.carFingerprint], CP)
assert controller._ev9_long_tuning == EV9LongitudinalTuningState()
assert isinstance(controller._left_blindspot_warning, BlindspotWarningState)
assert isinstance(controller._right_blindspot_warning, BlindspotWarningState)
def test_ev9_longitudinal_tuning_matches_stock_stop_hold_release_timing(self):
state = update_ev9_longitudinal_tuning(EV9LongitudinalTuningState(), True, True, 1.0)
assert not state.stop_request
@@ -1761,7 +1802,8 @@ class TestHyundaiFingerprint:
CP = CarParams.new_message()
CP.carFingerprint = CAR.HYUNDAI_IONIQ_5_PE
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING |
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT |
HyundaiFlags.CCNC)
CP.openpilotLongitudinalControl = False
controller = CarController(DBC[CP.carFingerprint], CP)
@@ -2504,9 +2546,10 @@ class TestHyundaiFingerprint:
assert parser.vl["CCNC_0x161"]["HDA_ICON"] == 2
assert parser.vl["CCNC_0x161"]["LFA_ICON"] == 1
def test_ev9_ccnc_acc_control_uses_packer_counter(self):
@pytest.mark.parametrize("candidate", (CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE))
def test_ccnc_acc_control_uses_packer_counter(self, candidate):
CP = CarParams.new_message()
CP.carFingerprint = CAR.KIA_EV9
CP.carFingerprint = candidate
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CCNC | HyundaiFlags.CANFD_ANGLE_STEERING |
HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
@@ -2530,10 +2573,17 @@ class TestHyundaiFingerprint:
assert parser.vl["SCC_CONTROL"]["ACC_ObjDist"] == pytest.approx(27.5)
assert parser.vl["SCC_CONTROL"]["ACC_ObjRelSpd"] == pytest.approx(-1.2)
@pytest.mark.parametrize("candidate", (CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE))
def test_ccnc_adrv_templates_and_periods_present(self, candidate):
expected_addrs = {0x160, 0x1DA, 0x1EA, 0x200, 0x345, 0x161, 0x162, 0x1BA, 0x1E5, 0x1E0, 0x38C}
assert set(hyundaicanfd._CCNC_ADRV_TEMPLATES[candidate]) == expected_addrs
assert set(hyundaicanfd._CCNC_ADRV_PERIODS[candidate]).issubset(expected_addrs)
@pytest.mark.parametrize("candidate", (CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE))
@pytest.mark.parametrize(("steering_pressed", "steering_active"), ((False, True), (True, False)))
def test_ev9_ccnc_steering_icon_tracks_controller_authority(self, monkeypatch, steering_pressed, steering_active):
def test_ccnc_steering_icon_tracks_controller_authority(self, monkeypatch, steering_pressed, steering_active, candidate):
CP = CarParams.new_message()
CP.carFingerprint = CAR.KIA_EV9
CP.carFingerprint = candidate
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.EV | HyundaiFlags.CCNC |
HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.CANFD_LKA_STEERING |
HyundaiFlags.CANFD_LKA_STEERING_ALT)
+6 -6
View File
@@ -521,8 +521,8 @@ class CAR(Platforms):
car_parts=CarParts.common([CarHarness.hyundai_q]))
],
HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.CCNC,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
)
HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_s]))],
@@ -1183,13 +1183,13 @@ CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with
# CAN-FD cars with ADAS ECUs that work with the communication-control path.
CANFD_SECURITYACCESS_CAR = {
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN, CAR.KIA_EV9,
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_5_PE, CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN, CAR.KIA_EV9,
}
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
CANFD_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9}
CANFD_CORNER_RADAR_BSM_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV9}
CANFD_ANGLE_LONGITUDINAL_CAR = {CAR.KIA_EV9, CAR.HYUNDAI_IONIQ_5_PE}
CANFD_CORNER_RADAR_BSM_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_IONIQ_5_PE, CAR.KIA_EV9}
CANFD_RADAR_LIVE_LONGITUDINAL_CAR = {
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.KIA_EV9, CAR.GENESIS_GV60_EV_1ST_GEN,
CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_5_PE, CAR.HYUNDAI_IONIQ_6, CAR.KIA_EV6, CAR.KIA_EV9, CAR.GENESIS_GV60_EV_1ST_GEN,
}
RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | {
CAR.HYUNDAI_IONIQ,