Qualify split HKG angle EPS publications

This commit is contained in:
firestar5683
2026-11-06 22:15:29 -06:00
parent 287da30f08
commit 665bbc8b35
9 changed files with 1669 additions and 1662 deletions
@@ -37,12 +37,23 @@ jobs:
opendbc_repo/opendbc/dbc
openpilot/selfdrive/controls/lib/longitudinal_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so
openpilot/selfdrive/locationd/models/generated/libcar.so
- name: Verify paired controller-default replay contract
run: .venv/bin/python tools/ci/review_hkg_defaults/review.py
- name: Run steering retention and independent safety veto regressions
run: |
.venv/bin/python -m pytest -q --junitxml=qualification.xml openpilot/starpilot/aol/tests/test_hkg_angle_eps_retention.py openpilot/starpilot/aol/tests/test_pe_combined_profile_contract.py openpilot/starpilot/aol/tests/test_stock_eps_recovery.py openpilot/starpilot/aol/tests/test_runtime.py openpilot/starpilot/aol/tests/test_source_pause_driver_monitoring.py openpilot/system/hardware/tests openpilot/starpilot/drive_state/tests/test_hardware_lifecycle.py openpilot/starpilot/ui/tests/test_weather.py openpilot/starpilot/flm/tests/test_pid_global_capture.py openpilot/starpilot/flm/tests/test_registered_controls_global.py::test_actual_controls_source_freshness_calibration_and_override_rejection openpilot/starpilot/lateral/tests/test_ev6_default.py openpilot/starpilot/lateral/tests/test_ioniq6_policy.py tools/ci/tests/test_replay_references.py
- name: Check owned Python files
run: |
.venv/bin/ruff check openpilot/starpilot/aol/temporary_steering.py openpilot/starpilot/aol/tests/test_hkg_angle_eps_retention.py openpilot/starpilot/aol/transport_pause.py openpilot/system/hardware/hardwared.py openpilot/system/hardware/hardware_timing.py openpilot/system/hardware/tests/test_hardware_timing.py openpilot/starpilot/ui/tests/test_weather.py openpilot/starpilot/lateral/tests/test_ev6_default.py openpilot/starpilot/lateral/tests/test_ioniq6_policy.py
.venv/bin/ty check openpilot/starpilot/aol/temporary_steering.py openpilot/starpilot/aol/tests/test_hkg_angle_eps_retention.py openpilot/starpilot/aol/transport_pause.py openpilot/system/hardware/hardwared.py openpilot/system/hardware/hardware_timing.py openpilot/system/hardware/tests/test_hardware_timing.py openpilot/starpilot/ui/tests/test_weather.py openpilot/starpilot/lateral/tests/test_ev6_default.py openpilot/starpilot/lateral/tests/test_ioniq6_policy.py
- name: Compare both reviewed default-controller recordings
run: .venv/bin/python openpilot/selfdrive/test/process_replay/test_processes.py --whitelist-cars HYUNDAI HYUNDAI2 --whitelist-procs controlsd --output reviewed-defaults -j2
- name: Save exact results
if: always()
uses: actions/upload-artifact@v4
with:
name: hkg-angle-recovery-results
path: |
review-results/
baseline.xml
baseline-result.json
qualification.xml
reviewed-defaults/coverage.json
reviewed-defaults/diff.txt
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
"""Untuned EV6 lateral selection and steering command boundaries."""
"""EV6 vehicle-policy defaults and steering command boundaries."""
import unittest
@@ -15,6 +15,7 @@ from opendbc.car.hyundai.values import CAR, DBC, HyundaiFlags, CarControllerPara
from opendbc.car.lateral import apply_driver_steer_torque_limits
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
from openpilot.starpilot.lateral.torque_extension import selected_policy
from openpilot.starpilot.lateral.hkg_vehicle_policy import HKGVehicleTorquePolicy
from openpilot.starpilot.lateral.torque_runtime import runtime_enabled
@@ -26,7 +27,7 @@ def ev6(lka_steering: bool):
class TestEV6DefaultLateral(unittest.TestCase):
def test_hda_topologies_keep_vehicle_tune_and_generic_controller(self):
def test_hda_topologies_keep_vehicle_tune_and_vehicle_policy(self):
for lka_steering in (False, True):
with self.subTest(lka_steering=lka_steering), OpenpilotPrefix():
cp = ev6(lka_steering)
@@ -40,7 +41,8 @@ class TestEV6DefaultLateral(unittest.TestCase):
self.assertFalse(runtime_enabled(cp, Params()))
self.assertEqual(cp.lateralTuning.to_dict(), original_tune)
lateral = LatControlTorque(cp.as_reader(), CarInterface(cp), DT_CTRL)
self.assertIsNone(selected_policy(lateral))
self.assertIsInstance(selected_policy(lateral), HKGVehicleTorquePolicy)
self.assertEqual(selected_policy(lateral).profile, "kia_ev6")
self.assertAlmostEqual(lateral.torque_params.latAccelFactor, cp.lateralTuning.torque.latAccelFactor)
controller = CarController(DBC[cp.carFingerprint], cp)
self.assertIsNone(controller.ioniq6_longitudinal)
@@ -28,7 +28,7 @@ def _legacy_friction(controller, error, deadzone, threshold, _cs, _setpoint):
def _rows(car, sequence, *, profile='2023', matched_frozen_cp=False, passive=False, direct_original_controller=False, turn_assist=True,
roll=None):
roll=None, controller_mode=None):
cp = interfaces[car].get_non_essential_params(car)
cp.passive = passive
if matched_frozen_cp:
@@ -44,7 +44,7 @@ def _rows(car, sequence, *, profile='2023', matched_frozen_cp=False, passive=Fal
versions[0].fwVersion = b'IONIQ6-230915'
versions[1].fwVersion = b'IONIQ6-240206'
ci = interfaces[car](cp)
controller = LatControlTorque(cp.as_reader(), ci, DT_CTRL, turn_assist=turn_assist)
controller = LatControlTorque(cp.as_reader(), ci, DT_CTRL, turn_assist=turn_assist, controller_mode=controller_mode)
if direct_original_controller:
# The older frozen vectors called the controller directly, before the
# original controlsd drive loop replaced the PID gain curve each tick.
@@ -178,7 +178,8 @@ class Ioniq6PolicyTests(unittest.TestCase):
parent = json.loads((TESTDATA / 'non_ioniq_parent.json').read_text())
for car in (TOYOTA.TOYOTA_COROLLA_TSS2, HYUNDAI.HYUNDAI_IONIQ_5):
with self.subTest(car=str(car)):
controller, actual = _rows(car, sequence, passive=car == TOYOTA.TOYOTA_COROLLA_TSS2, turn_assist=False)
controller, actual = _rows(car, sequence, passive=car == TOYOTA.TOYOTA_COROLLA_TSS2, turn_assist=False,
controller_mode='standard')
self.assertIsNone(selected_policy(controller))
for row, expected in zip(actual, parent[str(car)], strict=True):
for value, reference in zip(row, expected, strict=True):
@@ -1,7 +0,0 @@
def default_selection(CP) -> ControllerSelection:
policy = policy_for(CP)
from openpilot.starpilot.lateral.hkg_vehicle_policy import PROFILES
forte_non_scc = policy == 'kia_forte' and str(CP.carFingerprint) in ('KIA_FORTE_2019_NON_SCC', 'KIA_FORTE_2021_NON_SCC')
dom_default = forte_non_scc or policy == 'kia_carnival'
mode = ControllerMode.STARPILOT if policy and policy != 'generic' and (policy not in PROFILES or dom_default) else ControllerMode.STANDARD
return ControllerSelection(mode, policy, 'default')
-38
View File
@@ -1,38 +0,0 @@
from pathlib import Path
import ast,hashlib,json,subprocess,sys
R=Path.cwd();D=Path(__file__).parent;O=R/'review-results';O.mkdir(exist_ok=True)
selection=R/'openpilot/starpilot/lateral/controller_selection.py'
original=selection.read_bytes();text=original.decode();node=next(n for n in ast.parse(text).body if isinstance(n,ast.FunctionDef) and n.name=='default_selection')
current=ast.get_source_segment(text,node);previous=(D/'old_default.txt').read_text().rstrip()
assert hashlib.sha256((previous+'\n').encode()).hexdigest()=='c046839822779ce34ef902bc5698ee894a164880bdceb38d2473bde71c2a3aa2'
assert text.count(current)==1
args=[sys.executable,'openpilot/selfdrive/test/process_replay/test_processes.py','--whitelist-cars','HYUNDAI','HYUNDAI2','--whitelist-procs','controlsd','-j2']
def run(label,expected):
result=subprocess.run([*args,'--output',str(O/label)],stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
(O/(label+'.log')).write_bytes(result.stdout)
print(label,'returncode',result.returncode,flush=True)
assert result.returncode==expected,result.stdout.decode(errors='replace')[-3000:]
try:
selection.write_text(text.replace(current,previous))
run('previous-default',0)
finally:
selection.write_bytes(original)
assert selection.read_bytes()==original
run('current-default',1)
from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS
from openpilot.selfdrive.test.process_replay.compare_logs import compare_logs
from openpilot.selfdrive.test.process_replay.test_processes import get_log_data
from openpilot.tools.lib.logreader import LogReader
from tools.ci.replay_references import config_signature
cfg=next(c for c in CONFIGS if c.proc_name=='controlsd');rows=[]
for segment in ('regenAA0FC4ED71E|2025-04-08--22-57-50--0','regenAFB9780D823|2025-04-08--23-00-34--0'):
stem=segment.replace('|','_')+'_controlsd';fresh=next((O/'current-default/new').glob(stem+'_*.zst'));prior=next((O/'previous-default/new').glob(stem+'_*.zst'));expected=D/(stem+'.zst')
fresh_msgs=list(LogReader(str(fresh)));expected_msgs=list(LogReader(str(expected)));prior_msgs=list(LogReader(str(prior)))
diffs=compare_logs(expected_msgs,fresh_msgs,cfg.ignore,[],cfg.tolerance);assert not diffs,str(diffs[:3])
assert {m.controlsState.lateralControlState.torqueState.version for m in fresh_msgs if m.which()=='controlsState'}=={2}
assert {m.controlsState.lateralControlState.torqueState.version for m in prior_msgs if m.which()=='controlsState'}=={1}
assert any(m.which()=='carControl' and m.carControl.latActive and abs(m.carControl.actuators.torque)>.01 for m in fresh_msgs)
_,raw,params=get_log_data(segment);cp=next(e.carParams for e in LogReader.from_bytes(raw) if e.which()=='carParams')
rows.append({'segment':segment,'process':'controlsd','input_sha256':hashlib.sha256(raw).hexdigest(),'input_bytes':len(raw),'config_sha256':config_signature(cfg),'car_fingerprint':cp.carFingerprint,'expected_file':expected.name,'expected_bytes':expected.stat().st_size,'expected_sha256':hashlib.sha256(expected.read_bytes()).hexdigest(),'messages':len(fresh_msgs),'current_vs_published_differences':len(diffs),'previous_default_vs_prior_reference_differences':0,'old_version':1,'current_version':2,'fixture_param_keys':sorted(params or {})})
result={'sourceCommit':subprocess.check_output(['git','rev-parse','HEAD'],text=True).strip(),'shippingSourceRestored':selection.read_bytes()==original,'selection_sha256':hashlib.sha256(original).hexdigest(),'old_default_sha256':hashlib.sha256((previous+'\n').encode()).hexdigest(),'extraIgnoredFields':[],'extraIgnoredMessages':[],'comparisons':'Original complete-message comparator and original configuration/tolerances','intentionalCommit':'13839683908c449dfbb055cb4950e339ed2b1a1f','rows':rows}
(O/'paired-review.json').write_text(json.dumps(result,indent=2));print(json.dumps(result),flush=True)