Damp 2025 Ioniq 6 highway steering oscillation

This commit is contained in:
firestar5683
2026-11-11 10:57:51 -06:00
parent c68461e3b3
commit 33f60615ea
3 changed files with 84 additions and 1 deletions
@@ -29,6 +29,8 @@ from openpilot.starpilot.lateral.torque_shaping import (
)
HKG_CANFD_BASE_FRICTION_THRESHOLD = 0.39
IONIQ_6_2025_HIGHWAY_FRICTION_THRESHOLD_INCREASE = 0.50
IONIQ_6_CARS = (CAR.HYUNDAI_IONIQ_6,)
@@ -881,6 +883,8 @@ class Ioniq6TorquePolicy:
if self.surface is None and not self.is_2025 and not CS.steeringPressed and not self.prev_steering_pressed:
friction_threshold += get_ioniq_6_2023_center_friction_increment(
CS.vEgo, setpoint, measurement, desired_lateral_jerk, future_desired_lateral_accel) / max(center_taper, 1e-3)
if self.is_2025 and not CS.steeringPressed:
friction_threshold *= 1.0 + IONIQ_6_2025_HIGHWAY_FRICTION_THRESHOLD_INCREASE * float(np.interp(CS.vEgo, [20.0, 27.0], [0.0, 1.0]))
friction_scale = get_ioniq_6_friction_scale(CS.vEgo, setpoint, desired_lateral_jerk)
friction_scale = 1.0 + ((friction_scale - 1.0) * center_taper)
friction_scale *= get_ioniq_6_friction_center_fade_scale(setpoint, CS.vEgo)
@@ -184,3 +184,82 @@ class Ioniq6PolicyTests(unittest.TestCase):
for row, expected in zip(actual, parent[str(car)], strict=True):
for value, reference in zip(row, expected, strict=True):
self.assertAlmostEqual(value, reference, places=7)
class Ioniq6HighwayFrictionTests(unittest.TestCase):
def controller(self, *, firmware_2025=True, long=False):
cp = interfaces[HYUNDAI.HYUNDAI_IONIQ_6].get_non_essential_params(HYUNDAI.HYUNDAI_IONIQ_6)
cp.openpilotLongitudinalControl = long
cp.pcmCruise = not long
if firmware_2025:
fw = cp.init('carFw', 2)
fw[0].fwVersion = b'IONIQ6-230915'
fw[1].fwVersion = b'IONIQ6-240206'
controller = LatControlTorque(cp.as_reader(), interfaces[HYUNDAI.HYUNDAI_IONIQ_6](cp), DT_CTRL)
return controller, VehicleModel(cp)
def trace(self, *, speed=29.0, firmware_2025=True, long=False, tuning=True, pressed=False, center=-3.0):
controller, vm = self.controller(firmware_2025=firmware_2025, long=long)
params = SimpleNamespace(angleOffsetDeg=0.0, roll=0.0)
cs = structs.CarState.new_message(vEgo=speed, steeringPressed=pressed,
gearShifter=structs.CarState.GearShifter.drive)
rows = []
with mock.patch.object(tune, 'IONIQ_6_2025_HIGHWAY_FRICTION_THRESHOLD_INCREASE', .50 if tuning else 0.0):
for index in range(400):
cs.steeringAngleDeg = center + .5 * math.sin(index * DT_CTRL * 2 * math.pi)
output, _, state = controller.update(index != 0, cs, vm, params, True, .001, False, .322)
rows.append((output, state.f, state.desiredLateralAccel, state.desiredLateralJerk, state.p, state.i))
self.assertLessEqual(abs(output), 1.0)
self.assertTrue(all(math.isfinite(x) for x in rows[-1]))
return controller, rows
def test_highway_feedback_is_softer_without_changing_path_or_pid(self):
_, tuned = self.trace()
_, baseline = self.trace(tuning=False)
tuned_f = [row[1] for row in tuned[100:]]
original_f = [row[1] for row in baseline[100:]]
self.assertLess(max(tuned_f) - min(tuned_f), .9 * (max(original_f) - min(original_f)))
for row, old in zip(tuned, baseline, strict=True):
self.assertEqual(row[2:], old[2:])
def test_low_speed_and_older_firmware_are_unchanged(self):
for kwargs in ({'speed': 20.0}, {'speed': 5.0}, {'firmware_2025': False}):
with self.subTest(**kwargs):
self.assertEqual(self.trace(**kwargs)[1], self.trace(tuning=False, **kwargs)[1])
def test_stock_and_alpha_long_use_identical_steering(self):
self.assertEqual(self.trace(long=False)[1], self.trace(long=True)[1])
def test_driver_override_is_unchanged_and_inactive_resets(self):
controller, rows = self.trace(pressed=True)
self.assertEqual(rows, self.trace(pressed=True, tuning=False)[1])
vm = VehicleModel(interfaces[HYUNDAI.HYUNDAI_IONIQ_6].get_non_essential_params(HYUNDAI.HYUNDAI_IONIQ_6))
cs = structs.CarState.new_message(vEgo=29.0, steeringAngleDeg=5.0)
output, _, state = controller.update(False, cs, vm, SimpleNamespace(angleOffsetDeg=0.0, roll=0.0),
False, .001, False, .322)
self.assertEqual(output, 0.0)
self.assertFalse(state.active)
self.assertEqual(selected_policy(controller).measurement_rate_filter.x, 0.0)
def test_constant_turn_strength_live_parameters_and_limits_are_preserved(self):
results = []
for tuning in (False, True):
controller, vm = self.controller()
controller.update_torque_parameters(3.2, .01, .08)
self.assertAlmostEqual(controller.torque_params.latAccelFactor, 3.2 * 1.22, places=6)
self.assertAlmostEqual(controller.torque_params.friction, .08, places=6)
self.assertEqual(controller.pid.pos_limit, controller.lateral_accel_from_torque(1.0, controller.torque_params))
cs = structs.CarState.new_message(vEgo=29.0, steeringAngleDeg=-3.0,
gearShifter=structs.CarState.GearShifter.drive)
curve = -vm.calc_curvature(math.radians(cs.steeringAngleDeg), cs.vEgo, 0.0)
with mock.patch.object(tune, 'IONIQ_6_2025_HIGHWAY_FRICTION_THRESHOLD_INCREASE', .50 if tuning else 0.0):
for index in range(400):
output, _, _ = controller.update(index != 0, cs, vm, SimpleNamespace(angleOffsetDeg=0.0, roll=0.0),
True, curve, False, .322)
results.append(output)
self.assertAlmostEqual(*results, places=12)
def test_large_tracking_error_keeps_full_correction(self):
_, tuned = self.trace(center=20.0)
_, original = self.trace(center=20.0, tuning=False)
self.assertEqual(tuned[100:], original[100:])
+1 -1
View File
@@ -1 +1 @@
{"protected_inventory_sha256": "c0f79b07a47da3d1d798256c11737fc629f41db0d933e4bad584cf9a5e56e840", "schema_version": 1}
{"protected_inventory_sha256": "eddae796df726f04bf15b69bba8b0c93b4e98f67f50e368627bb5bd385ec01a9", "schema_version": 1}