Compare commits

...

69 Commits

Author SHA1 Message Date
StarPilot Build Bot 3c2f0f4a14 build 2026-05-29 04:33:28 +00:00
firestarsdog b12fdf182d Slooooow doooooown 2026-05-29 00:01:13 -04:00
firestarsdog 75b1deaf60 BigUI WIP: Try dock 2026-05-28 21:48:23 -04:00
firestar5683 a9930207ba v16 2026-05-28 17:38:14 -05:00
firestar5683 742c104964 on 2026-05-28 15:42:42 -05:00
firestarsdog 4183698fc6 BigUI: Widget Scale 2026-05-28 16:05:59 -04:00
firestar5683 f06c82b2b8 ev6 2026-05-28 14:19:03 -05:00
firestarsdog b23b4384f1 BigUI WIP: Aethergauge offset location 2026-05-28 15:11:44 -04:00
firestar5683 93bad13469 patches 2026-05-28 13:31:59 -05:00
firestar5683 31e0a5b8cc volt bsm 2026-05-28 13:29:45 -05:00
firestar5683 732830b095 g90 radar 2026-05-28 13:18:20 -05:00
firestarsdog 43d42594ef BigUI WIP: Aethergauge Helpers 2026-05-28 13:58:40 -04:00
firestar5683 e61039bb67 DM ruh roh 2026-05-28 12:27:45 -05:00
firestar5683 8e8225b6ae Nav Long 2026-05-28 11:41:05 -05:00
firestar5683 01bd291b78 you used to drive me onto sidewalks 2026-05-28 10:41:46 -05:00
firestar5683 61e28a0ac9 build 2026-05-28 10:23:35 -05:00
firestar5683 c744f66b2a Optimus Prime 2026-05-28 10:21:01 -05:00
firestarsdog 9b177b25b5 Revert "test cycle"
This reverts commit b9d89a3e85.
2026-05-28 11:05:47 -04:00
firestarsdog b9d89a3e85 test cycle 2026-05-28 11:04:09 -04:00
firestar5683 903fd2264e build 2026-05-28 00:37:45 -05:00
firestar5683 0f8142a15c default on 2026-05-28 00:35:16 -05:00
firestar5683 b95b5b1d53 build 2026-05-28 00:12:16 -05:00
firestar5683 3d0c3a8a45 Powers You Never Knew You Had and What To Do With Them Now You've Wised Up 2026-05-28 00:09:41 -05:00
firestar5683 9af23999d1 navgal 2026-05-28 00:09:34 -05:00
firestar5683 74a9bb5a4e build 2026-05-28 00:09:34 -05:00
firestar5683 cf506e59b0 nav 2026-05-28 00:09:20 -05:00
firestar5683 68d7fd09e2 Legion 2026-05-27 23:26:52 -05:00
firestarsdog b70680aa86 Silverado CC 2026-05-27 23:47:46 -04:00
Dom 823ff696ab Merge pull request #59 from Thinkpad4by3/Dom
Dom
2026-05-27 21:55:13 -05:00
firestar5683 9b530d520c XT5 2026-05-27 21:37:23 -05:00
firestar5683 3d35284a49 build 2026-05-27 19:53:14 -05:00
Jason Jackrel f425d86457 update tire stiffness 2026-05-27 16:48:27 -07:00
Jason Jackrel 98a9373346 finally the volt tune 2026-05-27 16:47:18 -07:00
firestar5683 35a7e43045 blocky block 2026-05-27 17:40:56 -05:00
firestar5683 b535c0845e ioniq 5 radar 2026-05-27 17:40:56 -05:00
whoisdomi 0ed821d32d 25hz 2026-05-27 17:35:19 -05:00
whoisdomi 2317057411 50hz poll 2026-05-27 17:35:19 -05:00
whoisdomi dc3b39a198 are we there? 2026-05-27 17:35:19 -05:00
whoisdomi ce5611f24c is this radar data? 2026-05-27 17:35:19 -05:00
firestar5683 f819386399 happy wife happy life 2026-05-26 22:20:19 -05:00
firestar5683 e1812ec3d7 build 2026-05-26 21:59:47 -05:00
firestar5683 e9935624f7 smoosh smoosh 2026-05-26 21:59:46 -05:00
firestar5683 0fec51a5d9 volt 2026-05-26 18:58:11 -05:00
firestar5683 3fa2d370bf i6 2026-05-26 18:19:51 -05:00
firestar5683 0750072ef0 build 2026-05-26 16:05:46 -05:00
firestar5683 fb93198a92 logg 2026-05-26 16:02:58 -05:00
firestar5683 a4789c9f61 i6 2026-05-26 15:53:05 -05:00
firestar5683 7386073c71 build 2026-05-26 11:36:09 -05:00
firestar5683 7d8be7079c I h8 u nudgeless 2026-05-26 11:33:49 -05:00
firestar5683 148929d2f1 i5 2026-05-26 11:09:12 -05:00
firestar5683 13e4f301b9 oopsie 2026-05-26 10:42:59 -05:00
firestarsdog dc91ac13b1 BigUI WIP: Clip lanes 2026-05-26 02:15:52 -04:00
firestar5683 a129d591e7 hkg radar 2026-05-26 00:17:24 -05:00
firestar5683 8aa0cf327a build 2026-05-26 00:00:25 -05:00
firestar5683 b78e44303d CCNC 2026-05-25 23:57:56 -05:00
firestarsdog feba46db30 BigUI WIP: Onroad Path Cleanup 2026-05-26 00:56:31 -04:00
firestarsdog a8d501fcd9 BigUI WIP: Scissor Borders 2026-05-26 00:40:47 -04:00
firestarsdog fb17126f68 BigUI WIP: Consolidated Border Effects 2026-05-26 00:32:31 -04:00
firestar5683 693b1f08a3 color calib 2026-05-25 02:12:44 -05:00
firestar5683 6e81630e49 build 2026-05-25 01:42:33 -05:00
firestar5683 76dbf9412a cameradisableFullDisable 2026-05-25 01:40:01 -05:00
firestar5683 68123093c3 stop UI log 2026-05-25 00:48:26 -05:00
firestar5683 73cbee1b85 tune 2026-05-25 00:48:20 -05:00
firestar5683 0cb613b6ce volt aeb 2026-05-25 00:48:13 -05:00
firestarsdog 7834d15127 BigUI WIP: Curves again 2026-05-25 01:02:08 -04:00
firestarsdog 71ce49a301 BigUI WIP: Useless banner 2026-05-24 23:17:21 -04:00
firestarsdog fd7f75578d BigUI WIP: Remove white border on sign + less steppy movement 2026-05-24 03:59:11 -04:00
firestarsdog 4c8452de78 BigUI WIP: Update Curves Again 2026-05-24 01:48:08 -04:00
firestarsdog 7bebf0ef3c BigUI WIP: Force Stop -> Aethergauge 2026-05-24 01:01:31 -04:00
249 changed files with 10562 additions and 3584 deletions
Binary file not shown.
+1
View File
@@ -2179,6 +2179,7 @@ struct DriverStateV2 {
rightBlinkProb @8 :Float32;
sunglassesProb @9 :Float32;
phoneProb @13 :Float32;
sleepProb @14 :Float32;
notReadyProbDEPRECATED @12 :List(Float32);
occludedProbDEPRECATED @10 :Float32;
readyProbDEPRECATED @11 :List(Float32);
Binary file not shown.
+8 -1
View File
@@ -367,6 +367,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"LoudBlindspotAlert", {PERSISTENT, BOOL, "0", "0", 0}},
{"LowVoltageShutdown", {PERSISTENT, FLOAT, "11.8", "11.8", 3}},
{"ManualUpdateInitiated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"AMapKey1", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"AMapKey2", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"ApiCache_NavDestinations", {PERSISTENT, JSON, "[]", "[]"}},
{"MapAcceleration", {PERSISTENT, BOOL, "0", "0", 1}},
{"MapboxPublicKey", {PERSISTENT | DONT_LOG, STRING, "", "", 0}},
{"MapBoxRequests", {PERSISTENT, JSON, "{}", "{}"}},
@@ -376,6 +379,10 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"MapGears", {PERSISTENT, BOOL, "0", "0", 2}},
{"MapsSelected", {PERSISTENT, STRING, "", "", 0}},
{"MapSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"NavDesiresAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
{"NavLongitudinalAllowed", {PERSISTENT, BOOL, "1", "0", 2}},
{"NavDestination", {PERSISTENT, STRING, "", ""}},
{"NavInstructionState", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
{"NextMapSpeedLimit", {CLEAR_ON_MANAGER_START, JSON, "{}", "{}"}},
{"VisionSpeedLimit", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
{"VisionSpeedLimitConfidence", {CLEAR_ON_MANAGER_START, FLOAT, "0.0", "0.0"}},
@@ -403,7 +410,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"NNFFModelName", {CLEAR_ON_MANAGER_START, STRING, "", "", 0}},
{"NoLogging", {PERSISTENT, BOOL, "0", "0", 2}},
{"NoUploads", {PERSISTENT, BOOL, "0", "0", 2}},
{"NudgelessLaneChange", {PERSISTENT, BOOL, "1", "0", 0}},
{"NudgelessLaneChange", {PERSISTENT, BOOL, "0", "0", 0}},
{"NumericalTemp", {PERSISTENT, BOOL, "1", "0", 3}},
{"Offset1", {PERSISTENT, FLOAT, "5.0", "0.0", 0}},
{"Offset2", {PERSISTENT, FLOAT, "5.0", "0.0", 0}},
Binary file not shown.
+1 -58
View File
@@ -33,64 +33,7 @@ function agnos_init {
# StarPilot variables
sudo chmod 0777 /cache
# Weston loads display color correction from /data/misc/display/color_cal/color_cal.
# Prefer a factory /persist/comma/color_cal blob when present. Otherwise, derive a
# Weston-compatible calibration blob from the device's legacy dwo gamma tables.
COLOR_CAL_SRC="/persist/comma/color_cal"
DWO_GAMMA_SRC="/persist/comma/dwo_gamma_curves"
COLOR_CAL_DST_DIR="/data/misc/display/color_cal"
COLOR_CAL_DST="${COLOR_CAL_DST_DIR}/color_cal"
COLOR_CAL_HASH_PATH="${COLOR_CAL_DST_DIR}/source.sha256"
DWO_REFERENCE="$DIR/tools/reference_dwo_gamma_curves.txt"
DWO_GENERATOR="$DIR/tools/generate_color_cal_from_dwo.py"
COLOR_CAL_UPDATED=0
COLOR_CAL_TMP=""
DWO_SOURCE_HASH=""
if [ -f "$COLOR_CAL_SRC" ]; then
sudo mkdir -p "$COLOR_CAL_DST_DIR"
if [ ! -f "$COLOR_CAL_DST" ] || ! cmp -s "$COLOR_CAL_SRC" "$COLOR_CAL_DST"; then
sudo cp "$COLOR_CAL_SRC" "$COLOR_CAL_DST"
sudo chown -R comma:comma "$COLOR_CAL_DST_DIR"
sudo chmod 664 "$COLOR_CAL_DST"
sudo rm -f "$COLOR_CAL_HASH_PATH"
COLOR_CAL_UPDATED=1
fi
elif [ -f "$DWO_GAMMA_SRC" ] && [ -f "$DWO_REFERENCE" ] && [ -f "$DWO_GENERATOR" ]; then
DWO_SOURCE_HASH="$(cat "$DWO_GAMMA_SRC" "$DWO_REFERENCE" "$DWO_GENERATOR" | sha256sum | awk '{print $1}')"
if [ ! -f "$COLOR_CAL_DST" ] || [ ! -f "$COLOR_CAL_HASH_PATH" ] || [ "$(cat "$COLOR_CAL_HASH_PATH" 2>/dev/null)" != "$DWO_SOURCE_HASH" ]; then
COLOR_CAL_TMP="$(mktemp)"
if python3 "$DWO_GENERATOR" --reference "$DWO_REFERENCE" --input "$DWO_GAMMA_SRC" --output "$COLOR_CAL_TMP"; then
sudo mkdir -p "$COLOR_CAL_DST_DIR"
if [ ! -f "$COLOR_CAL_DST" ] || ! cmp -s "$COLOR_CAL_TMP" "$COLOR_CAL_DST"; then
sudo cp "$COLOR_CAL_TMP" "$COLOR_CAL_DST"
COLOR_CAL_UPDATED=1
fi
printf '%s' "$DWO_SOURCE_HASH" | sudo tee "$COLOR_CAL_HASH_PATH" >/dev/null
sudo chown -R comma:comma "$COLOR_CAL_DST_DIR"
sudo chmod 664 "$COLOR_CAL_DST" "$COLOR_CAL_HASH_PATH"
fi
rm -f "$COLOR_CAL_TMP"
fi
fi
if [ "$COLOR_CAL_UPDATED" = "1" ] && systemctl is-active --quiet weston.service; then
sudo systemctl restart weston.service
# Weston can recreate wayland-0 as root on service restart before weston-ready
# fixes ownership. Repair it here so the Qt UI can always reconnect.
if [ -d /var/tmp/weston ]; then
for _ in $(seq 1 50); do
if [ -S /var/tmp/weston/wayland-0 ]; then
sudo chown -R comma:comma /var/tmp/weston 2>/dev/null || true
sudo chmod -R 700 /var/tmp/weston 2>/dev/null || true
SOCKET_OWNER="$(stat -c '%U:%G' /var/tmp/weston/wayland-0 2>/dev/null || true)"
[ "$SOCKET_OWNER" = "comma:comma" ] && break
fi
sleep 0.1
done
fi
fi
sudo rm -f /data/misc/display/color_cal/color_cal /data/misc/display/color_cal/source.sha256
# Check if AGNOS update is required
if [ $(< /VERSION) != "$AGNOS_VERSION" ]; then
+3 -1
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import argparse
import os
from types import SimpleNamespace
from typing import get_args
from collections import defaultdict
@@ -32,7 +33,8 @@ def get_params_for_docs(platform) -> CarParams:
cp_platform = platform if platform in interfaces else MOCK.MOCK
CP: CarParams = interfaces[cp_platform].get_params(cp_platform, fingerprint=gen_empty_fingerprint(),
car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)],
alpha_long=True, is_release=False, docs=True)
alpha_long=True, is_release=False, docs=True,
starpilot_toggles=SimpleNamespace())
return CP
@@ -131,6 +131,7 @@ class CarHarness(EnumBase):
hyundai_p = BaseCarHarness("Hyundai P connector")
hyundai_q = BaseCarHarness("Hyundai Q connector")
hyundai_r = BaseCarHarness("Hyundai R connector")
hyundai_s = BaseCarHarness("Hyundai S connector")
custom = BaseCarHarness("Developer connector")
obd_ii = BaseCarHarness("OBD-II connector", parts=[Cable.long_obdc_cable, Cable.usbc_coupler], has_connector=False)
gm = BaseCarHarness("GM connector", parts=[Accessory.harness_box])
+21
View File
@@ -193,29 +193,43 @@ MIGRATION = {
"HYUNDAI IONIQ PLUG-IN HYBRID 2019": HYUNDAI.HYUNDAI_IONIQ_PHEV_2019,
"HYUNDAI IONIQ PHEV 2020": HYUNDAI.HYUNDAI_IONIQ_PHEV,
"HYUNDAI KONA 2020": HYUNDAI.HYUNDAI_KONA,
"HYUNDAI KONA 2ND GEN": HYUNDAI.HYUNDAI_KONA_2ND_GEN,
"HYUNDAI KONA ELECTRIC 2019": HYUNDAI.HYUNDAI_KONA_EV,
"HYUNDAI KONA ELECTRIC 2022": HYUNDAI.HYUNDAI_KONA_EV_2022,
"HYUNDAI KONA ELECTRIC 2ND GEN": HYUNDAI.HYUNDAI_KONA_EV_2ND_GEN,
"HYUNDAI KONA HYBRID 2020": HYUNDAI.HYUNDAI_KONA_HEV,
"HYUNDAI KONA HYBRID 2ND GEN": HYUNDAI.HYUNDAI_KONA_HEV_2ND_GEN,
"HYUNDAI SANTA FE 2019": HYUNDAI.HYUNDAI_SANTA_FE,
"HYUNDAI SANTA FE 2022": HYUNDAI.HYUNDAI_SANTA_FE_2022,
"HYUNDAI SANTA FE HYBRID 2022": HYUNDAI.HYUNDAI_SANTA_FE_HEV_2022,
"HYUNDAI SANTA FE HYBRID 5TH GEN": HYUNDAI.HYUNDAI_SANTA_FE_HEV_5TH_GEN,
"HYUNDAI SANTA FE PlUG-IN HYBRID 2022": HYUNDAI.HYUNDAI_SANTA_FE_PHEV_2022,
"HYUNDAI SONATA 2020": HYUNDAI.HYUNDAI_SONATA,
"HYUNDAI SONATA 2024": HYUNDAI.HYUNDAI_SONATA_2024,
"HYUNDAI SONATA 2019": HYUNDAI.HYUNDAI_SONATA_LF,
"HYUNDAI STARIA 4TH GEN": HYUNDAI.HYUNDAI_STARIA_4TH_GEN,
"HYUNDAI TUCSON 2019": HYUNDAI.HYUNDAI_TUCSON,
"HYUNDAI TUCSON 2025": HYUNDAI.HYUNDAI_TUCSON_2025,
"HYUNDAI TUCSON HYBRID 2025": HYUNDAI.HYUNDAI_TUCSON_HEV_2025,
"HYUNDAI TUCSON PLUG-IN HYBRID 2025": HYUNDAI.HYUNDAI_TUCSON_PHEV_2025,
"HYUNDAI PALISADE 2020": HYUNDAI.HYUNDAI_PALISADE,
"HYUNDAI PALISADE 2023": HYUNDAI.HYUNDAI_PALISADE_2023,
"HYUNDAI VELOSTER 2019": HYUNDAI.HYUNDAI_VELOSTER,
"HYUNDAI SONATA HYBRID 2021": HYUNDAI.HYUNDAI_SONATA_HYBRID,
"HYUNDAI SONATA HYBRID 2024": HYUNDAI.HYUNDAI_SONATA_HEV_2024,
"HYUNDAI IONIQ 5 2022": HYUNDAI.HYUNDAI_IONIQ_5,
"HYUNDAI IONIQ 5 2025": HYUNDAI.HYUNDAI_IONIQ_5_PE,
"HYUNDAI IONIQ 5 N 2024": HYUNDAI.HYUNDAI_IONIQ_5_N,
"HYUNDAI IONIQ 6 2023": HYUNDAI.HYUNDAI_IONIQ_6,
"HYUNDAI IONIQ 9 2025": HYUNDAI.HYUNDAI_IONIQ_9,
"HYUNDAI TUCSON 4TH GEN": HYUNDAI.HYUNDAI_TUCSON_4TH_GEN,
"HYUNDAI SANTA CRUZ 1ST GEN": HYUNDAI.HYUNDAI_SANTA_CRUZ_1ST_GEN,
"HYUNDAI SANTA CRUZ 2025": HYUNDAI.HYUNDAI_SANTA_CRUZ_2025,
"HYUNDAI CUSTIN 1ST GEN": HYUNDAI.HYUNDAI_CUSTIN_1ST_GEN,
"KIA FORTE E 2018 & GT 2021": HYUNDAI.KIA_FORTE,
"KIA K4 2025": HYUNDAI.KIA_K4_2025,
"KIA K5 2021": HYUNDAI.KIA_K5_2021,
"KIA K5 2025": HYUNDAI.KIA_K5_2025,
"KIA K5 HYBRID 2020": HYUNDAI.KIA_K5_HEV_2020,
"KIA K8 HYBRID 1ST GEN": HYUNDAI.KIA_K8_HEV_1ST_GEN,
"KIA NIRO EV 2020": HYUNDAI.KIA_NIRO_EV,
@@ -230,22 +244,29 @@ MIGRATION = {
"KIA OPTIMA HYBRID 4TH GEN FACELIFT": HYUNDAI.KIA_OPTIMA_H_G4_FL,
"KIA SELTOS 2021": HYUNDAI.KIA_SELTOS,
"KIA SPORTAGE 5TH GEN": HYUNDAI.KIA_SPORTAGE_5TH_GEN,
"KIA SPORTAGE 2026": HYUNDAI.KIA_SPORTAGE_2026,
"KIA SPORTAGE HYBRID 2026": HYUNDAI.KIA_SPORTAGE_HEV_2026,
"KIA SORENTO GT LINE 2018": HYUNDAI.KIA_SORENTO,
"KIA SORENTO 4TH GEN": HYUNDAI.KIA_SORENTO_4TH_GEN,
"KIA SORENTO 2024": HYUNDAI.KIA_SORENTO_2024,
"KIA SORENTO HYBRID 4TH GEN": HYUNDAI.KIA_SORENTO_HEV_4TH_GEN,
"KIA SORENTO HYBRID 4TH GEN LFA2": HYUNDAI.KIA_SORENTO_HEV_4TH_GEN_LFA2,
"KIA STINGER GT2 2018": HYUNDAI.KIA_STINGER,
"KIA STINGER 2022": HYUNDAI.KIA_STINGER_2022,
"KIA CEED INTRO ED 2019": HYUNDAI.KIA_CEED,
"KIA EV6 2022": HYUNDAI.KIA_EV6,
"KIA EV6 2025": HYUNDAI.KIA_EV6_2025,
"KIA EV9 2025": HYUNDAI.KIA_EV9,
"KIA CARNIVAL 4TH GEN": HYUNDAI.KIA_CARNIVAL_4TH_GEN,
"GENESIS GV60 ELECTRIC 1ST GEN": HYUNDAI.GENESIS_GV60_EV_1ST_GEN,
"GENESIS G70 2018": HYUNDAI.GENESIS_G70,
"GENESIS G70 2020": HYUNDAI.GENESIS_G70_2020,
"GENESIS GV70 1ST GEN": HYUNDAI.GENESIS_GV70_1ST_GEN,
"GENESIS GV70 ELECTRIFIED 2026": HYUNDAI.GENESIS_GV70_ELECTRIFIED_2ND_GEN,
"GENESIS G80 2017": HYUNDAI.GENESIS_G80,
"GENESIS G90 2017": HYUNDAI.GENESIS_G90,
"GENESIS GV80 2023": HYUNDAI.GENESIS_GV80,
"GENESIS GV80 2025": HYUNDAI.GENESIS_GV80_2025,
"MAZDA CX-5": MAZDA.MAZDA_CX5,
"MAZDA CX-9": MAZDA.MAZDA_CX9,
"MAZDA 3": MAZDA.MAZDA_3,
+26 -2
View File
@@ -92,6 +92,29 @@ def get_acc_dashboard_fcw_alert(hud_alert, CS):
return 0
def get_acc_dashboard_status_values(enabled, target_speed_kph, hud_control, CS):
if enabled:
return {
"ACCCruiseState": 0,
"ACCLeadCar": int(hud_control.leadVisible) & 0x1,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": target_speed_kph,
"ACCGapLevel": int(hud_control.leadDistanceBars) & 0x3,
"ACCCmdActive": 1,
}
# Replay the stock camera dashboard context when openpilot long is enabled
# but openpilot itself is not actively driving the ACC cluster state.
return {
"ACCCruiseState": int(getattr(CS, "stock_acc_cruise_state", 0)) & 0x7,
"ACCLeadCar": int(getattr(CS, "stock_acc_lead_car", 0)) & 0x1,
"ACCResumeButton": int(getattr(CS, "stock_acc_resume_button", 0)) & 0x1,
"ACCSpeedSetpoint": float(getattr(CS, "stock_acc_speed_setpoint_kph", 0.0)),
"ACCGapLevel": int(getattr(CS, "stock_acc_gap_level", 0)) & 0x3,
"ACCCmdActive": int(getattr(CS, "stock_acc_cmd_active", 0)) & 0x1,
}
ECM_CRUISE_SPOOF_CARS = {
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
@@ -703,9 +726,10 @@ class CarController(CarControllerBase):
CS.auto_hold_engaged = False
if should_send_acc_dashboard_status(self.CP, dash_speed_spoof_active):
acc_dashboard_status = get_acc_dashboard_status_values(CC.enabled, hud_v_cruise * CV.MS_TO_KPH, hud_control, CS)
fcw_alert = get_acc_dashboard_fcw_alert(hud_alert, CS)
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, CC.enabled,
hud_v_cruise * CV.MS_TO_KPH, hud_control, fcw_alert))
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN,
acc_dashboard_status, fcw_alert))
# Radar needs to know current speed and yaw rate (50hz),
# and that ADAS is alive (10hz)
+24 -4
View File
@@ -81,6 +81,12 @@ class CarState(CarStateBase):
self.lkas_enabled = 0
self.pcm_acc_status = AccState.OFF
self.stock_fcw_alert = 0
self.stock_acc_cruise_state = 0
self.stock_acc_lead_car = 0
self.stock_acc_resume_button = 0
self.stock_acc_speed_setpoint_kph = 0.0
self.stock_acc_gap_level = 0
self.stock_acc_cmd_active = 0
def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]):
if not self.CP.pcmCruise:
@@ -267,17 +273,25 @@ class CarState(CarStateBase):
ret.cruiseState.enabled = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] != AccState.OFF
ret.cruiseState.standstill = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.STANDSTILL
self.stock_fcw_alert = 0
ret.stockFcw = False
if self.CP.networkLocation == NetworkLocation.fwdCamera and not self.CP.flags & GMFlags.NO_CAMERA.value:
has_acc_dashboard_status = self.CP.carFingerprint not in CC_ONLY_CAR or self.CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL
if has_acc_dashboard_status:
acc_dashboard_status = cam_cp.vl["ASCMActiveCruiseControlStatus"]
if self.CP.carFingerprint not in CC_ONLY_CAR:
ret.cruiseState.speed = acc_dashboard_status["ACCSpeedSetpoint"] * CV.KPH_TO_MS
self.stock_acc_cruise_state = int(acc_dashboard_status["ACCCruiseState"])
self.stock_acc_lead_car = int(acc_dashboard_status["ACCLeadCar"])
self.stock_acc_resume_button = int(acc_dashboard_status["ACCResumeButton"])
self.stock_acc_speed_setpoint_kph = float(acc_dashboard_status["ACCSpeedSetpoint"])
self.stock_acc_gap_level = int(acc_dashboard_status["ACCGapLevel"])
self.stock_acc_cmd_active = int(acc_dashboard_status["ACCCmdActive"])
# Preserve the stock camera FCW level from 0x370 so the controller can
# replay it when that message is blocked and spoofed by openpilot long.
self.stock_fcw_alert = int(acc_dashboard_status["FCWAlert"])
ret.stockFcw = self.stock_fcw_alert != 0
if self.CP.carFingerprint not in (SDGM_CAR | ASCM_INT):
if self.CP.carFingerprint not in SDGM_CAR:
ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0
else:
ret.stockAeb = False
@@ -424,7 +438,7 @@ class CarState(CarStateBase):
("ASCMSteeringButton", 33),
]
if CP.enableBsm:
pt_messages.append(("BCMBlindSpotMonitor", 10))
pt_messages.append(("BCMBlindSpotMonitor", 0))
if CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value:
if ("ECMAcceleratorPos", 80) in pt_messages:
@@ -466,8 +480,14 @@ class CarState(CarStateBase):
("ASCMSteeringButton", 33),
]
if CP.enableBsm:
cam_messages.append(("BCMBlindSpotMonitor", 10))
elif CP.carFingerprint not in (SDGM_CAR | ASCM_INT):
cam_messages.append(("BCMBlindSpotMonitor", 0))
elif CP.carFingerprint in ASCM_INT:
# Volt/ASCM-int variants don't reliably have AEBCmd present at startup,
# but when it appears we still want to surface OEM AEB state.
cam_messages += [
("AEBCmd", 0),
]
elif CP.carFingerprint not in SDGM_CAR:
cam_messages += [
("AEBCmd", 10),
]
@@ -216,6 +216,7 @@ FINGERPRINTS.update({
CAR.CHEVROLET_BLAZER: FINGERPRINTS[CAR.CHEVROLET_TRAVERSE],
CAR.CHEVROLET_MALIBU_SDGM: FINGERPRINTS[CAR.CHEVROLET_MALIBU_CC],
CAR.BUICK_BABYENCLAVE: FINGERPRINTS[CAR.CHEVROLET_TRAVERSE],
CAR.CHEVROLET_SILVERADO_CC: FINGERPRINTS[CAR.CHEVROLET_SILVERADO],
})
FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = {
+7 -6
View File
@@ -209,17 +209,18 @@ def create_friction_brake_command(packer, bus, apply_brake, idx, enabled, near_s
return packer.make_can_msg("EBCMFrictionBrakeCmd", bus, values)
def create_acc_dashboard_command(packer, bus, enabled, target_speed_kph, hud_control, fcw_alert):
target_speed = min(target_speed_kph, 255)
def create_acc_dashboard_command(packer, bus, status_values, fcw_alert):
target_speed = min(max(float(status_values.get("ACCSpeedSetpoint", 0.0)), 0.0), 255.0)
values = {
"ACCAlwaysOne": 1,
"ACCResumeButton": 0,
"ACCCruiseState": int(status_values.get("ACCCruiseState", 0)) & 0x7,
"ACCResumeButton": int(status_values.get("ACCResumeButton", 0)) & 0x1,
"ACCSpeedSetpoint": target_speed,
"ACCGapLevel": hud_control.leadDistanceBars * enabled, # 3 "far", 0 "inactive"
"ACCCmdActive": enabled,
"ACCGapLevel": int(status_values.get("ACCGapLevel", 0)) & 0x3,
"ACCCmdActive": int(status_values.get("ACCCmdActive", 0)) & 0x1,
"ACCAlwaysOne2": 1,
"ACCLeadCar": hud_control.leadVisible,
"ACCLeadCar": int(status_values.get("ACCLeadCar", 0)) & 0x1,
"FCWAlert": int(fcw_alert) & 0x3,
}
+20 -3
View File
@@ -58,6 +58,14 @@ NON_LINEAR_TORQUE_PARAMS = {
"left": [3.8, 0.81, 0.24, 0.0465122],
"right": [3.8, 0.81, 0.24, 0.0465122],
},
CAR.CHEVROLET_SILVERADO_CC: {
"left": [3.8, 0.81, 0.24, 0.0465122],
"right": [3.8, 0.81, 0.24, 0.0465122],
},
CAR.CHEVROLET_VOLT: {
"left": [1.5, 1.0, 0.155, 0.0],
"right": [1.5, 1.0, 0.155, 0.0],
},
}
PEDAL_MSG = 0x201
@@ -85,6 +93,14 @@ VOLT_LONG_TEST_TUNE_CARS = {
CAR.CHEVROLET_VOLT_CC,
}
VOLT_BSM_CARS = {
CAR.CHEVROLET_VOLT,
CAR.CHEVROLET_VOLT_2019,
CAR.CHEVROLET_VOLT_ASCM,
CAR.CHEVROLET_VOLT_CAMERA,
CAR.CHEVROLET_VOLT_CC,
}
BOLT_PEDAL_LONG_CARS = {
CAR.CHEVROLET_BOLT_CC_2017,
CAR.CHEVROLET_BOLT_CC_2018_2021,
@@ -201,7 +217,8 @@ class CarInterface(CarInterfaceBase):
ret.brand = "gm"
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.gm)]
ret.autoResumeSng = False
ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN]
# Some Volt installs don't expose the BSM frame during startup fingerprinting.
ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN] or candidate in VOLT_BSM_CARS
has_sascm = 0x2FF in fingerprint[CanBus.POWERTRAIN]
if has_sascm:
ret.flags |= GMFlags.SASCM.value
@@ -452,7 +469,7 @@ class CarInterface(CarInterfaceBase):
# ACC Bolts use pedal for full longitudinal control, not just SNG.
ret.flags |= GMFlags.PEDAL_LONG.value
elif candidate == CAR.CHEVROLET_SILVERADO:
elif candidate in (CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_SILVERADO_CC):
# On the Bolt, the ECM and camera independently check that you are either above 5 kph or at a stop
# with foot on brake to allow engagement, but this platform only has that check in the camera.
# TODO: check if this is split by EV/ICE with more platforms in the future
@@ -489,7 +506,7 @@ class CarInterface(CarInterfaceBase):
ret.minSteerSpeed = 7 * CV.MPH_TO_MS
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.CADILLAC_XT5_CC:
elif candidate in (CAR.CADILLAC_XT5, CAR.CADILLAC_XT5_CC):
ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
+141 -4
View File
@@ -3,12 +3,14 @@ from types import SimpleNamespace
from parameterized import parameterized
from opendbc.can import CANPacker, CANParser
from opendbc.car import Bus, DT_CTRL
from opendbc.car import Bus, DT_CTRL, structs
from opendbc.car.car_helpers import interfaces
from opendbc.car.gm import gmcan
from opendbc.car.gm.carstate import CarState as GMCarState
from opendbc.car.gm.carcontroller import (
VisualAlert,
get_acc_dashboard_fcw_alert,
get_acc_dashboard_status_values,
should_send_acc_dashboard_status,
should_send_cc_button_spam,
should_spoof_dash_speed,
@@ -130,6 +132,44 @@ class TestGMInterface:
assert "ECMAcceleratorPos" not in pt_parser.vl
assert "EBCMBrakePedalPosition" in pt_parser.vl
@parameterized.expand(VOLT_CARS)
def test_volt_bsm_is_enabled_without_fingerprint_match(self, car_model):
CarInterface = interfaces[car_model]
car_params = CarInterface.get_params(car_model, _empty_fingerprint(), [], alpha_long=False, is_release=False, docs=False,
starpilot_toggles=_test_starpilot_toggles())
assert car_params.enableBsm
def test_volt_bsm_parser_is_optional(self):
cp = SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_ASCM,
networkLocation=structs.CarParams.NetworkLocation.fwdCamera,
flags=0,
transmissionType=structs.CarParams.TransmissionType.direct,
enableGasInterceptorDEPRECATED=False,
enableBsm=True,
)
pt_parser = GMCarState.get_can_parsers(cp)[Bus.pt]
bsm_addr = pt_parser.dbc.name_to_msg["BCMBlindSpotMonitor"].address
assert "BCMBlindSpotMonitor" in pt_parser.vl
assert pt_parser.message_states[bsm_addr].ignore_alive
def test_volt_ascm_cam_parser_includes_optional_aeb_cmd(self):
cam_parser = GMCarState.get_can_parsers(SimpleNamespace(
carFingerprint=CAR.CHEVROLET_VOLT_ASCM,
networkLocation=structs.CarParams.NetworkLocation.fwdCamera,
flags=0,
transmissionType=structs.CarParams.TransmissionType.direct,
enableGasInterceptorDEPRECATED=False,
enableBsm=False,
))[Bus.cam]
aeb_addr = cam_parser.dbc.name_to_msg["AEBCmd"].address
assert "AEBCmd" in cam_parser.vl
assert cam_parser.message_states[aeb_addr].ignore_alive
def test_bolt_gen2_pedal_cancel_remap_sets_alt_exp(self):
CarInterface = interfaces[CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL]
fingerprint = _empty_fingerprint()
@@ -147,6 +187,30 @@ class TestGMInterface:
assert car_params.alternativeExperience & ALTERNATIVE_EXPERIENCE.GM_REMAP_CANCEL_TO_DISTANCE
assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_BOLT_2022_PEDAL.value
def test_cadillac_xt5_sdgm_sascm_gates_alpha_long(self):
CarInterface = interfaces[CAR.CADILLAC_XT5]
fingerprint = _empty_fingerprint()
fingerprint[0][0xBE] = 6
stock_params = CarInterface.get_params(CAR.CADILLAC_XT5, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert stock_params.networkLocation == structs.CarParams.NetworkLocation.fwdCamera
assert stock_params.pcmCruise
assert stock_params.alphaLongitudinalAvailable is False
assert stock_params.openpilotLongitudinalControl is False
assert stock_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_SDGM.value
fingerprint[0][0x2FF] = 8
sascm_params = CarInterface.get_params(CAR.CADILLAC_XT5, fingerprint, [], alpha_long=True, is_release=False,
docs=False, starpilot_toggles=_test_starpilot_toggles())
assert sascm_params.flags & GMFlags.SASCM.value
assert sascm_params.alphaLongitudinalAvailable
assert sascm_params.openpilotLongitudinalControl
assert not sascm_params.pcmCruise
assert sascm_params.safetyConfigs[0].safetyParam & GMSafetyFlags.HW_CAM_LONG.value
class TestGMCarController:
def test_dash_speed_spoof_respects_live_stock_acc_toggles(self):
@@ -259,9 +323,14 @@ class TestGMCarController:
msg = gmcan.create_acc_dashboard_command(
packer,
0,
True,
100,
SimpleNamespace(leadDistanceBars=3, leadVisible=True),
{
"ACCCruiseState": 0,
"ACCLeadCar": 1,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": 100,
"ACCGapLevel": 3,
"ACCCmdActive": 1,
},
0x2,
)
@@ -269,6 +338,24 @@ class TestGMCarController:
assert parser.vl["ASCMActiveCruiseControlStatus"]["FCWAlert"] == 2
def test_acc_dashboard_command_can_replay_stock_status_payload(self):
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_ASCM][Bus.pt])
msg = gmcan.create_acc_dashboard_command(
packer,
0,
{
"ACCCruiseState": 0,
"ACCLeadCar": 1,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": 50,
"ACCGapLevel": 2,
"ACCCmdActive": 0,
},
0x3,
)
assert msg[1].hex() == "010023200113"
def test_acc_dashboard_fcw_alert_prefers_openpilot_alert(self):
cs = SimpleNamespace(
stock_fcw_alert=1,
@@ -292,3 +379,53 @@ class TestGMCarController:
)
assert get_acc_dashboard_fcw_alert(VisualAlert.none, cs) == 0x3
def test_acc_dashboard_fcw_alert_falls_back_to_stock_fcw_event(self):
cs = SimpleNamespace(
stock_fcw_alert=0,
out=SimpleNamespace(stockAeb=False, stockFcw=True),
)
assert get_acc_dashboard_fcw_alert(VisualAlert.none, cs) == 0x3
def test_acc_dashboard_status_values_use_openpilot_hud_when_enabled(self):
cs = SimpleNamespace(
stock_acc_cruise_state=5,
stock_acc_lead_car=0,
stock_acc_resume_button=1,
stock_acc_speed_setpoint_kph=42.0,
stock_acc_gap_level=1,
stock_acc_cmd_active=0,
)
values = get_acc_dashboard_status_values(True, 105.0, SimpleNamespace(leadDistanceBars=3, leadVisible=True), cs)
assert values == {
"ACCCruiseState": 0,
"ACCLeadCar": 1,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": 105.0,
"ACCGapLevel": 3,
"ACCCmdActive": 1,
}
def test_acc_dashboard_status_values_reuse_stock_camera_status_when_disabled(self):
cs = SimpleNamespace(
stock_acc_cruise_state=0,
stock_acc_lead_car=1,
stock_acc_resume_button=0,
stock_acc_speed_setpoint_kph=50.0,
stock_acc_gap_level=2,
stock_acc_cmd_active=0,
)
values = get_acc_dashboard_status_values(False, 0.0, SimpleNamespace(leadDistanceBars=0, leadVisible=False), cs)
assert values == {
"ACCCruiseState": 0,
"ACCLeadCar": 1,
"ACCResumeButton": 0,
"ACCSpeedSetpoint": 50.0,
"ACCGapLevel": 2,
"ACCCmdActive": 0,
}
+15 -2
View File
@@ -233,7 +233,7 @@ class CAR(Platforms):
)
CHEVROLET_VOLT = GMASCMPlatformConfig(
[GMCarDocs("Chevrolet Volt 2017-18", min_enable_speed=0, video="https://youtu.be/QeMCN_4TFfQ")],
GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=15.7, centerToFrontRatio=0.45, tireStiffnessFactor=0.469, minEnableSpeed=-1),
GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=15.7, centerToFrontRatio=0.45, tireStiffnessFactor=1.0, minEnableSpeed=-1), #tire stiffness factor hasn't been updated since 2018 and every other gm is on 1.0
dbc_dict={
Bus.pt: "gm_global_a_powertrain_volt",
Bus.radar: "gm_global_a_object",
@@ -329,6 +329,13 @@ class CAR(Platforms):
],
GMCarSpecs(mass=2994, wheelbase=3.75, steerRatio=16.3, tireStiffnessFactor=1.0),
)
CHEVROLET_SILVERADO_CC = GMPlatformConfig(
[
GMCarDocs("Chevrolet Silverado 1500 - No-ACC"),
GMCarDocs("GMC Sierra 1500 - No-ACC"),
],
CHEVROLET_SILVERADO.specs,
)
CHEVROLET_EQUINOX = GMPlatformConfig(
[GMCarDocs("Chevrolet Equinox 2019-22")],
GMCarSpecs(mass=1588, wheelbase=2.72, steerRatio=14.4, centerToFrontRatio=0.4),
@@ -353,6 +360,10 @@ class CAR(Platforms):
[GMCarDocs("Cadillac XT4 2023", "Driver Assist Package")],
GMCarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4),
)
CADILLAC_XT5 = GMSDGMPlatformConfig(
[GMCarDocs("Cadillac XT5 2022", "Driver Assist Package")],
CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5),
)
CADILLAC_XT6 = GMPlatformConfig(
[GMCarDocs("Cadillac XT6 2020", "Driver Assist Package")],
GMCarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.5, centerToFrontRatio=0.4),
@@ -383,7 +394,7 @@ class CAR(Platforms):
)
CADILLAC_XT5_CC = GMPlatformConfig(
[GMCarDocs("Cadillac XT5 - No-ACC")],
CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5),
CADILLAC_XT5.specs,
)
CHEVROLET_EQUINOX_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Equinox 2019-22 - No-ACC")],
@@ -527,6 +538,7 @@ ALT_ACCS = {CAR.GMC_YUKON, CAR.GMC_YUKON_CC}
# We're integrated at the Safety Data Gateway Module on these cars
SDGM_CAR = {
CAR.CADILLAC_XT4,
CAR.CADILLAC_XT5,
CAR.CADILLAC_XT6,
CAR.CHEVROLET_TRAVERSE,
CAR.CHEVROLET_BLAZER,
@@ -549,6 +561,7 @@ CC_ONLY_CAR = {
CAR.CADILLAC_XT5_CC,
CAR.CHEVROLET_MALIBU_CC,
CAR.CHEVROLET_MALIBU_HYBRID_CC,
CAR.CHEVROLET_SILVERADO_CC,
}
CC_REGEN_PADDLE_CAR = {
CAR.CHEVROLET_BOLT_CC_2018_2021,
@@ -7,7 +7,7 @@ from opendbc.car.lateral import apply_driver_steer_torque_limits, apply_steer_an
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.hyundai import hyundaicanfd, hyundaican
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CANFD_RADAR_LIVE_LONGITUDINAL_CAR
from opendbc.car.interfaces import CarControllerBase
from opendbc.car.vehicle_model import VehicleModel
from openpilot.common.params import Params
@@ -527,6 +527,7 @@ class CarController(CarControllerBase):
lka_steering = self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING
lka_steering_long = lka_steering and self.long_active_ecu
ccnc_non_hda2 = self.CP.flags & HyundaiFlags.CCNC and not lka_steering
use_ioniq_6_dynamic_long_tuning = self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and self.long_active_ecu and \
CC.actuators.longControlState == LongCtrlState.pid
use_ioniq_6_smoothed_accel = use_ioniq_6_dynamic_long_tuning and CC.actuators.accel >= self._ioniq_6_long_tuning.actual_accel
@@ -546,8 +547,13 @@ class CarController(CarControllerBase):
# LFA and HDA icons
if self.frame % 5 == 0 and (not lka_steering or lka_steering_long):
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, CS.stock_lfahda_cluster_msg,
lfa_icon=lfa_icon))
if ccnc_non_hda2:
can_sends.extend(hyundaicanfd.create_ccnc(self.packer, self.CAN, self.long_active_ecu, CC.enabled, CC.hudControl,
CC.leftBlinker, CC.rightBlinker, CS.msg_161, CS.msg_162, CS.msg_1b5,
CS.is_metric, CS.out, CS.out.cruiseState.available, lfa_icon))
else:
can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, CS.stock_lfahda_cluster_msg,
lfa_icon=lfa_icon))
# blinkers
if lka_steering and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
@@ -577,7 +583,12 @@ class CarController(CarControllerBase):
if self.long_active_ecu:
if lka_steering:
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
else:
# Ioniq 5/6: front radar treats ADAS_DRV's 0x100 broadcast as its host heartbeat
# and stops publishing object tracks when it disappears. Spoof it periodically on
# PT bus so the radar keeps tracking.
if self.CP.carFingerprint in CANFD_RADAR_LIVE_LONGITUDINAL_CAR and self.frame % 4 == 0:
can_sends.append(hyundaicanfd.create_accelerator_brake_alt_spoof(0, self.frame // 4, CS.out.brakePressed, CS.out.gasPressed))
elif not ccnc_non_hda2:
can_sends.extend(hyundaicanfd.create_fca_warning_light(self.packer, self.CAN, self.frame))
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and self.frame % 5 == 0:
rear_stale = now_nanos - CS.blindspots_rear_corners_ts > CANFD_BLINDSPOT_STATUS_STALE_NS
@@ -612,7 +623,8 @@ class CarController(CarControllerBase):
acc_kwargs["jerk_lower"] = self._ioniq_6_long_tuning.jerk_lower
acc_kwargs["jerk_upper"] = self._ioniq_6_long_tuning.jerk_upper
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
set_speed_in_units, hud_control, **acc_kwargs))
set_speed_in_units, hud_control, cruise_info=CS.cruise_info if ccnc_non_hda2 else None,
**acc_kwargs))
self.accel_last = accel
else:
# button presses
+23 -4
View File
@@ -7,7 +7,7 @@ from opendbc.can import CANDefine, CANParser
from opendbc.car import Bus, create_button_events, structs
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, HyundaiStarPilotFlags, CAR, DBC, Buttons, CarControllerParams, \
from opendbc.car.hyundai.values import HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags, CAR, DBC, Buttons, CarControllerParams, \
hyundai_cancel_button_enables_cruise
from opendbc.car.interfaces import CarStateBase
@@ -108,6 +108,9 @@ class CarState(CarStateBase):
self.buttons_counter = 0
self.cruise_info = {}
self.msg_161 = {}
self.msg_162 = {}
self.msg_1b5 = {}
self.msg_364 = {}
self.stock_lkas_msg = {}
self.stock_lfa_msg = {}
@@ -306,7 +309,7 @@ class CarState(CarStateBase):
prev_lda_button = self.lda_button
self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
if self.CP.flags & HyundaiFlags.HAS_LDA_BUTTON:
if self.FPCP.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON:
self.lda_button = cp.vl["BCM_PO_11"]["LDA_BTN"]
ret.buttonEvents = [*self.create_cruise_button_events(self.cruise_buttons[-1], prev_cruise_buttons),
@@ -365,8 +368,16 @@ class CarState(CarStateBase):
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0
left_blinker_sig, right_blinker_sig = self.get_canfd_blinker_sig_names(self.CP.carFingerprint,
cp.vl["BLINKERS"]["USE_ALT_LAMP"] == 1)
ccnc_non_hda2 = self.CP.flags & HyundaiFlags.CCNC and not self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING
if ccnc_non_hda2:
self.msg_161 = copy.copy(cp_cam.vl["CCNC_0x161"])
self.msg_162 = copy.copy(cp_cam.vl["CCNC_0x162"])
self.msg_1b5 = copy.copy(cp_cam.vl["FR_CMR_03_50ms"])
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
use_alt_lamp = cp.vl["BLINKERS"]["USE_ALT_LAMP"] == 1 or bool(self.CP.flags & HyundaiFlags.CCNC)
left_blinker_sig, right_blinker_sig = self.get_canfd_blinker_sig_names(self.CP.carFingerprint, use_alt_lamp)
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
cp.vl["BLINKERS"][right_blinker_sig])
self.left_blindspot_from_radar = False
@@ -380,6 +391,9 @@ class CarState(CarStateBase):
self.left_blindspot_from_radar)
ret.rightBlindspot = (bool(cp.vl["BLINDSPOTS_REAR_CORNERS"]["BCW_RtIndSta"]) or
self.right_blindspot_from_radar)
elif self.CP.flags & HyundaiFlags.CCNC:
ret.leftBlindspot = bool(cp.vl["BLINDSPOTS_REAR_CORNERS"]["BCW_LtIndSta"])
ret.rightBlindspot = bool(cp.vl["BLINDSPOTS_REAR_CORNERS"]["BCW_RtIndSta"])
else:
ret.leftBlindspot = bool(cp.vl["BLINDSPOTS_REAR_CORNERS"]["BCW_LtIndSta"])
ret.rightBlindspot = bool(cp.vl["BLINDSPOTS_REAR_CORNERS"]["BCW_RtIndSta"])
@@ -487,6 +501,11 @@ class CarState(CarStateBase):
else:
cam_msgs.append(("FR_CMR_02_100ms", 0)) # optional: not all non-LKA CANFD cars have this on CAM bus
cam_msgs.append(("FR_CMR_03_50ms", 0)) # optional: camera lead/cipv data is not present on every CAN-FD trim
if CP.flags & HyundaiFlags.CCNC:
cam_msgs += [
("CCNC_0x161", 0),
("CCNC_0x162", 0),
]
msgs += [
("LFA", 0), # optional: may stop once OP takes over, but preserve stock UI fields when present
("LFAHDA_CLUSTER", 0), # optional: carries cluster icon state on some variants
@@ -741,6 +741,27 @@ FW_VERSIONS = {
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SX2EMFC AT KOR LHD 1.00 1.00 99211-BF000 230410',
b'\xf1\x00SX2EMFC AT USA LHD 1.00 1.02 99211-BF000 230823',
],
},
CAR.HYUNDAI_KONA_2ND_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SX2 MFC AT USA LHD 1.00 1.03 99211-BE000 230517',
b'\xf1\x00SX2 MFC AT USA LHD 1.00 1.07 99211-BE000 240611',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE000 ',
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE500 ',
],
},
CAR.HYUNDAI_KONA_HEV_2ND_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SX2HMFC AT AUS RHD 1.00 1.00 99211-BE001 241015',
b'\xf1\x00SX2HMFC AT EUR RHD 1.00 1.04 99211-BE000 231010',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE000 ',
b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE500 ',
],
},
CAR.KIA_NIRO_EV: {
@@ -1159,6 +1180,186 @@ FW_VERSIONS = {
b'\xf1\x00NQ5__ 1.00 1.04 99110CH100 ',
],
},
CAR.HYUNDAI_SANTA_FE_HEV_5TH_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00MX5HMFC AT CAN LHD 1.00 1.07 99211-P6000 231218',
b'\xf1\x00MX5HMFC AT KOR LHD 1.00 1.07 99211-P6000 231218',
b'\xf1\x00MX5HMFC AT USA LHD 1.00 1.06 99211-R6000 231218',
b'\xf1\x00MX5HMFC AT USA LHD 1.00 1.09 99211-R6200 250519',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00MX5_ RDR ----- 1.00 1.01 99110-P6000 ',
b'\xf1\x00MX5_ RDR ----- 1.00 1.01 99110-R6000 ',
],
},
CAR.HYUNDAI_SONATA_2024: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L1800 230512',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DN8_ RDR ----- 1.00 1.00 99110-L1800 ',
],
},
CAR.HYUNDAI_SONATA_HEV_2024: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DN8HMFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
b'\xf1\x00DN8HMFC AT USA LHD 1.00 1.01 99211-L1800 230512',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DN8_ RDR ----- 1.00 1.00 99110-L1800 ',
],
},
CAR.HYUNDAI_IONIQ_5_PE: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NE__ RDR ----- 1.00 1.00 99110-PI000 ',
b'\xf1\x00NE__ RDR ----- 1.00 1.01 99110-GI500 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NE MFC AT USA LHD 1.00 1.01 99211-PI000 240905',
b'\xf1\x00NE MFC AT EUR LHD 1.00 1.03 99211-GI500 240809',
b'\xf1\x00NE MFC AT USA LHD 1.00 1.00 99211-PI010 250407',
b'\xf1\x00NE MFC AT EUR LHD 1.00 1.00 99211-GI510 250513',
],
},
CAR.HYUNDAI_IONIQ_5_N: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NE1N RDR ----- 1.00 1.00 99110-NI000 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NE1NMFC AT KOR LHD 1.00 1.04 99211-NI000 231219',
b'\xf1\x00NE1NMFC AT KOR LHD 1.00 1.00 99211-NI010 240712',
b'\xf1\x00NE1NMFC AT USA LHD 1.00 1.04 99211-NI000 231219',
],
},
CAR.HYUNDAI_IONIQ_9: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00MEev RDR ----- 1.00 1.00 99110-GO000 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00ME MFC AT KOR LHD 1.00 1.00 99211-GO000 241007',
b'\xf1\x00ME MFC AT KOR LHD 1.00 1.01 99211-GO000 250103',
],
},
CAR.HYUNDAI_TUCSON_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N7050 C5A',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NX4__ 1.00 1.03 99110N7100 ',
],
},
CAR.HYUNDAI_TUCSON_HEV_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N7030 C55',
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N7030 C55',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NX4__ 1.00 1.02 99110N7000 ',
b'\xf1\x00NX4__ 1.00 1.02 99110N7100 ',
b'\xf1\x00NX4__ 1.00 1.03 99110N7100 ',
],
},
CAR.HYUNDAI_TUCSON_PHEV_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N7030 C55',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NX4__ 1.00 1.02 99110N7100 ',
],
},
CAR.HYUNDAI_SANTA_CRUZ_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N7030 C55',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NX4__ 1.00 1.00 99110K5500 ',
],
},
CAR.KIA_K4_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00CL4 MFC AT CAN LHD 1.00 1.02 99210-GG000 240708',
b'\xf1\x00CL4 MFC AT USA LHD 1.00 1.02 99210-GG000 240708',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CL4_ RDR ----- 1.00 1.01 99110-GG000 ',
b'\xf1\x00CL4_ RDR ----- 1.00 1.01 99110-GG100 ',
],
},
CAR.KIA_K5_2025: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DL3 MFC AT USA LHD 1.00 1.04 99210-L2500 240117',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DL3_ RDR ----- 1.00 1.01 99110-L2500 ',
],
},
CAR.KIA_SPORTAGE_2026: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NQ51.011.021.012551000HKP_NQ524_50509099211P1110',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NQ5__ 1.00 1.04 99110P1100 ',
],
},
CAR.KIA_SORENTO_2024: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00MQ4 MFC AT AUS RHD 1.01 1.04 99210-P2550 231127',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00MQ4_ RDR ----- 1.00 1.01 99110-P2500 ',
],
},
CAR.KIA_SORENTO_HEV_4TH_GEN_LFA2: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.00 99210-P2600 250617',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00MQ4_ RDR ----- 1.00 1.01 99110-P2500 ',
],
},
CAR.KIA_EV6_2025: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CV__ RDR ----- 1.00 1.00 99110-XG500 ',
b'\xf1\x00CV__ RDR ----- 1.00 1.01 99110-CV500 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00CV MFC AT KOR LHD 1.00 1.01 99210-CV500 240405',
b'\xf1\x00CV MFC AT USA LHD 1.00 1.02 99210-XG500 241223',
],
},
CAR.KIA_EV9: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00MV__ RDR ----- 1.00 1.02 99110-DO000 ',
b'\xf1\x00MV__ RDR ----- 1.00 1.03 99110-DO000 ',
b'\xf1\x00MV__ RDR ----- 1.00 1.04 99110-DO000 ',
b'\xf1\x00MV__ RDR ----- 1.00 1.02 99110-DO700 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00MV MFC AT KOR LHD 1.00 1.01 99211-DO000 230419',
b'\xf1\x00MV MFC AT USA LHD 1.00 1.02 99211-DO000 230616',
b'\xf1\x00MV MFC AT EUR LHD 1.00 1.02 99211-DO000 230616',
b'\xf1\x00MV MFC AT CAN LHD 1.00 1.00 99211-DO100 240403',
b'\xf1\x00MV MFC AT USA LHD 1.00 1.01 99211-XA000 241023',
b'\xf1\x00MV MFC AT CAN LHD 1.00 1.01 99211-DO100 241023',
],
},
CAR.GENESIS_GV70_ELECTRIFIED_2ND_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JK MFC AT USA LHD 1.00 1.03 99211-DS600 241125',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00JK__ RDR ----- 1.00 1.01 99110-DS500 ',
],
},
CAR.GENESIS_GV80_2025: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00JX__ RDR ----- 1.00 1.03 99110-T6500 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JX MFC AT USA LHD 1.00 1.03 99211-T6510 240124',
],
},
CAR.GENESIS_GV70_1ST_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JK1 MFC AT CAN LHD 1.00 1.02 99211-IY000 230627',
@@ -1,6 +1,7 @@
import copy
import numpy as np
from opendbc.car import CanBusBase, CanData
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.crc import CRC16_XMODEM
from opendbc.car.hyundai.values import HyundaiFlags
@@ -219,6 +220,102 @@ def create_lfahda_cluster(packer, CAN, enabled, base_values=None, lfa_icon=None)
return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
def create_ccnc(packer, CAN, openpilot_longitudinal, enabled, hud, left_blinker, right_blinker, msg_161, msg_162, msg_1b5,
is_metric, out, main_cruise_enabled, lfa_icon):
for fault in ("FAULT_LSS", "FAULT_HDA", "FAULT_DAS", "FAULT_LFA", "FAULT_DAW", "FAULT_ESS"):
msg_162[fault] = 0
if msg_161["ALERTS_2"] == 5:
msg_161.update({"ALERTS_2": 0, "SOUNDS_2": 0})
if msg_161["ALERTS_3"] == 17:
msg_161["ALERTS_3"] = 0
if msg_161["ALERTS_5"] in (2, 5):
msg_161["ALERTS_5"] = 0
if msg_161["SOUNDS_4"] == 2 and msg_161["LFA_ICON"] in (3, 0):
msg_161["SOUNDS_4"] = 0
lane_change_speed_min = 8.9408
any_blinker = left_blinker or right_blinker
curvature = {i: (31 if i == -1 else 13 - abs(i + 15)) if i < 0 else 15 + i for i in range(-15, 16)}
msg_161.update({
"DAW_ICON": 0,
"LKA_ICON": 0,
"LFA_ICON": 2 if lfa_icon else 0,
"CENTERLINE": 1 if lfa_icon else 0,
"LANELINE_CURVATURE": curvature.get(max(-15, min(int(out.steeringAngleDeg / 4.5), 15)), 14) if lfa_icon and not any_blinker else 15,
"LANELINE_LEFT": 0 if not lfa_icon else 1 if not hud.leftLaneVisible else 4 if hud.leftLaneDepart else 6 if any_blinker else 2,
"LANELINE_RIGHT": 0 if not lfa_icon else 1 if not hud.rightLaneVisible else 4 if hud.rightLaneDepart else 6 if any_blinker else 2,
"LCA_LEFT_ICON": 0 if not lfa_icon or out.vEgo < lane_change_speed_min else 1 if out.leftBlindspot else 2 if any_blinker else 4,
"LCA_RIGHT_ICON": 0 if not lfa_icon or out.vEgo < lane_change_speed_min else 1 if out.rightBlindspot else 2 if any_blinker else 4,
"LCA_LEFT_ARROW": 2 if left_blinker else 0,
"LCA_RIGHT_ARROW": 2 if right_blinker else 0,
})
if lfa_icon and any_blinker:
left_lane_raw = msg_1b5["Info_LftLnPosVal"]
right_lane_raw = msg_1b5["Info_RtLnPosVal"]
scale_per_m = 15 / 1.7
left_lane = abs(int(round(15 + (left_lane_raw - 1.7) * scale_per_m)))
right_lane = abs(int(round(15 + (right_lane_raw - 1.7) * scale_per_m)))
if msg_1b5["Info_LftLnQualSta"] not in (2, 3):
left_lane = 0
if msg_1b5["Info_RtLnQualSta"] not in (2, 3):
right_lane = 0
if left_lane_raw == -2.0248375:
left_lane = 30 - right_lane
if right_lane_raw == 2.0248375:
right_lane = 30 - left_lane
if left_lane_raw == right_lane_raw == 0:
left_lane = right_lane = 15
elif left_lane_raw == 0:
left_lane = 30 - right_lane
elif right_lane_raw == 0:
right_lane = 30 - left_lane
total = left_lane + right_lane
if total == 0:
left_lane = right_lane = 15
else:
left_lane = round((left_lane / total) * 30)
right_lane = 30 - left_lane
msg_161["LANELINE_LEFT_POSITION"] = left_lane
msg_161["LANELINE_RIGHT_POSITION"] = right_lane
if hud.leftLaneDepart or hud.rightLaneDepart:
msg_162["VIBRATE"] = 1
if openpilot_longitudinal:
if msg_161["ALERTS_3"] in (1, 2, 3, 4, 7, 8, 9, 10):
msg_161["ALERTS_3"] = 0
if msg_161["ALERTS_5"] == 4:
msg_161["ALERTS_5"] = 0
if msg_161["SOUNDS_3"] == 5:
msg_161["SOUNDS_3"] = 0
cruise_speed = round(out.vCruiseCluster * (1 if is_metric else CV.KPH_TO_MPH))
msg_161.update({
"SETSPEED": 3 if enabled else 1,
"SETSPEED_HUD": 0 if not main_cruise_enabled else 2 if enabled else 1,
"SETSPEED_SPEED": 255 if not main_cruise_enabled else (40 if is_metric else 25) if cruise_speed > (145 if is_metric else 90) else cruise_speed,
"DISTANCE": hud.leadDistanceBars,
"DISTANCE_SPACING": 0 if not main_cruise_enabled else 1 if enabled else 3,
"DISTANCE_LEAD": 0 if not main_cruise_enabled else 2 if enabled and hud.leadVisible else 1 if hud.leadVisible else 0,
"DISTANCE_CAR": 0 if not main_cruise_enabled else 2 if enabled else 1,
"SLA_ICON": 0,
"NAV_ICON": 0,
"TARGET": 0,
})
msg_162["LEAD"] = 0 if not main_cruise_enabled else 2 if enabled else 1
msg_162["LEAD_DISTANCE"] = msg_1b5["Longitudinal_Distance"]
return [packer.make_can_msg(msg, CAN.ECAN, values) for msg, values in (("CCNC_0x161", msg_161), ("CCNC_0x162", msg_162))]
def create_blindspot_status_messages(packer, CAN, rear_values, front_corner_values,
left_blindspot=False, right_blindspot=False,
left_blinker=False, right_blinker=False):
@@ -463,7 +560,7 @@ def create_ioniq_6_cluster_lane_change_messages(CAN, frame, side=None):
def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control,
main_mode_acc=1, jerk_lower=None, jerk_upper=None, direct_accel=False,
lead_distance=None, lead_rel_speed=None, lead_visible=None):
lead_distance=None, lead_rel_speed=None, lead_visible=None, cruise_info=None):
jerk = 5
jn = jerk / 50
if not enabled or gas_override:
@@ -506,6 +603,8 @@ def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_ov
"SET_ME_TMP_64": 0x64,
"DISTANCE_SETTING": hud_control.leadDistanceBars,
}
if cruise_info:
values.update({s: cruise_info[s] for s in ("ACC_ObjDist", "ACC_ObjRelSpd")})
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
@@ -603,3 +702,22 @@ def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
elif len(d) == 32:
crc ^= 0x9F5B
return crc
# Ioniq 5/6 / HKG LKA-steering: ADAS_DRV broadcasts ACCELERATOR_BRAKE_ALT (0x100) on bus 0.
# The front radar uses this as its "host alive" heartbeat. When we disable ADAS_DRV the
# radar stops publishing real object tracks. Spoof this message ourselves with valid CRC
# and current pedal state so the radar keeps tracking.
# Length is 24 bytes on Ioniq 6 (DBC declares 32 for ICE Hyundais, but EV firmware uses 24).
# Byte template captured from a real ADAS broadcast; bytes 6-23 appear static / config.
_ACCEL_BRAKE_ALT_TEMPLATE = bytes.fromhex("000000020000fcff000000000020000055ff000068000000")
def create_accelerator_brake_alt_spoof(bus: int, counter: int, brake_pressed: bool, accelerator_pressed: bool) -> CanData:
d = bytearray(_ACCEL_BRAKE_ALT_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)
d[22] = (d[22] & ~0x01) | (0x01 if accelerator_pressed else 0x00) # ACCELERATOR_PEDAL_PRESSED (bit 176)
crc = hkg_can_fd_checksum(0x100, None, d)
d[0] = crc & 0xFF
d[1] = (crc >> 8) & 0xFF
return CanData(0x100, bytes(d), bus)
+18 -10
View File
@@ -1,12 +1,15 @@
import time
from opendbc.car import Bus, get_safety_config, structs, uds
from opendbc.car import get_safety_config, structs, uds
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, CAR, DBC, CarControllerParams, \
from opendbc.car.hyundai.values import HyundaiFlags, CAR, CarControllerParams, \
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, \
CANFD_SECURITYACCESS_CAR, \
CANFD_RADAR_LIVE_LONGITUDINAL_CAR, \
RADAR_LIVE_LONGITUDINAL_CAR, \
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \
HyundaiStarPilotSafetyFlags, \
hyundai_cancel_button_enables_cruise
from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR
from opendbc.car.hyundai.radar_interface import get_radar_track_config
from opendbc.car.interfaces import CarInterfaceBase, ACCEL_MIN
from opendbc.car.disable_ecu import disable_ecu, ecu_log
from opendbc.car.hyundai.carcontroller import CarController
@@ -70,6 +73,9 @@ class CarInterface(CarInterfaceBase):
# this needs to be figured out for cars without an ADAS ECU
# Cars in CANFD_SECURITYACCESS_CAR are known to have ADAS ECUs that work with SecurityAccess
ret.alphaLongitudinalAvailable = False
if lka_steering and ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
# Angle-steering LKA platforms still need stock longitudinal validation.
ret.alphaLongitudinalAvailable = False
ret.enableBsm = 0x1ba in fingerprint[CAN.ECAN]
@@ -115,6 +121,8 @@ class CarInterface(CarInterfaceBase):
if ret.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_ANGLE_STEERING.value
if ret.flags & HyundaiFlags.CCNC and not ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CCNC.value
else:
# Shared configuration for non CAN-FD cars
@@ -138,9 +146,9 @@ class CarInterface(CarInterfaceBase):
if ret.flags & HyundaiFlags.CAMERA_SCC:
ret.safetyConfigs[0].safetyParam |= HyundaiSafetyFlags.CAMERA_SCC.value
# These cars have the LFA button on the steering wheel
# These cars expose an LKAS/LFA steering-wheel button that StarPilot can customize.
if 0x391 in fingerprint[0] or ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
ret.flags |= HyundaiFlags.HAS_LDA_BUTTON.value
ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CAN_CANFD_BLENDED.value
if hyundai_cancel_button_enables_cruise(candidate):
@@ -168,13 +176,13 @@ class CarInterface(CarInterfaceBase):
# Common longitudinal control setup
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or Bus.radar not in DBC[ret.carFingerprint]
radar_config = get_radar_track_config(ret.carFingerprint)
radar_tracks_available = radar_config is not None and radar_config.start_addr in fingerprint[radar_config.bus]
ret.radarUnavailable = not radar_tracks_available
if ret.flags & HyundaiFlags.NON_SCC:
ret.alphaLongitudinalAvailable = False
ret.openpilotLongitudinalControl = alpha_long and ret.alphaLongitudinalAvailable
# When longitudinal is enabled, we disable the ADAS ECU which stops radar messages
# Force radarUnavailable to prevent CAN Error from missing radar messages
if ret.openpilotLongitudinalControl:
if ret.openpilotLongitudinalControl and not (candidate in RADAR_LIVE_LONGITUDINAL_CAR and radar_tracks_available):
ret.radarUnavailable = True
ret.pcmCruise = not ret.openpilotLongitudinalControl
apply_platform_longitudinal_params(ret)
@@ -226,7 +234,7 @@ class CarInterface(CarInterfaceBase):
params = Params()
if communication_control is None:
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
if CP.carFingerprint in CANFD_RADAR_LIVE_LONGITUDINAL_CAR:
# Don't use 0x80 suppress bit so we can read the ECU response.
# Use ENABLE_RX_DISABLE_TX (0x01) so the ECU can still receive from rear radars for BSM
# while blocking SCC TX.
@@ -1,30 +1,58 @@
import math
from dataclasses import dataclass
from opendbc.can import CANParser
from opendbc.car import Bus, structs
from opendbc.car.interfaces import RadarInterfaceBase
from opendbc.car.hyundai.values import CAR, DBC
from opendbc.car.hyundai.values import CAR, DBC, HYUNDAI_MANDO_FRONT_RADAR_DBC, HYUNDAI_MRR30_RADAR_DBC, \
HYUNDAI_MRR35_RADAR_DBC
from openpilot.common.swaglog import cloudlog
RADAR_START_ADDR = 0x500
RADAR_MSG_COUNT = 32
MRR30_RADAR_START_ADDR = 0x210
MRR30_RADAR_MSG_COUNT = 16
MRR35_RADAR_START_ADDR = 0x3A5
MRR35_RADAR_MSG_COUNT = 32
@dataclass(frozen=True)
class RadarTrackConfig:
start_addr: int
msg_count: int
radar_type: str
bus: int = 1
frequency: int = 50
RADAR_TRACK_CONFIGS = {
HYUNDAI_MANDO_FRONT_RADAR_DBC: RadarTrackConfig(RADAR_START_ADDR, RADAR_MSG_COUNT, "mando"),
HYUNDAI_MRR30_RADAR_DBC: RadarTrackConfig(MRR30_RADAR_START_ADDR, MRR30_RADAR_MSG_COUNT, "mrr30"),
HYUNDAI_MRR35_RADAR_DBC: RadarTrackConfig(MRR35_RADAR_START_ADDR, MRR35_RADAR_MSG_COUNT, "mrr35", bus=0, frequency=20),
}
# POC for parsing corner radars: https://github.com/commaai/openpilot/pull/24221/
def get_radar_can_parser(CP):
if Bus.radar not in DBC[CP.carFingerprint]:
def get_radar_track_config(car_fingerprint) -> RadarTrackConfig | None:
radar_dbc = DBC[car_fingerprint].get(Bus.radar)
return RADAR_TRACK_CONFIGS.get(radar_dbc)
def get_radar_can_parser(CP, radar_config):
if radar_config is None:
return None
messages = [(f"RADAR_TRACK_{addr:x}", 50) for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT)]
return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, 1)
messages = [(f"RADAR_TRACK_{addr:x}", radar_config.frequency) for addr in range(radar_config.start_addr, radar_config.start_addr + radar_config.msg_count)]
return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, radar_config.bus)
class RadarInterface(RadarInterfaceBase):
def __init__(self, CP):
super().__init__(CP)
self.radar_config = get_radar_track_config(CP.carFingerprint)
self.updated_messages = set()
self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1
self.trigger_msg = (self.radar_config.start_addr + self.radar_config.msg_count - 1) if self.radar_config is not None else RADAR_START_ADDR
self.track_id = 0
self.radar_off_can = CP.radarUnavailable
@@ -33,7 +61,16 @@ class RadarInterface(RadarInterfaceBase):
self.ioniq_6_radar_probe = CP.carFingerprint == CAR.HYUNDAI_IONIQ_6 and CP.openpilotLongitudinalControl and self.radar_off_can
self.ioniq_6_radar_probe_logged = False
self.ioniq_6_radar_probe_updates = 0
self.rcp = get_radar_can_parser(CP)
self.rcp = get_radar_can_parser(CP, self.radar_config)
# Precompute (addr, "RADAR_TRACK_xxx") pairs once. _update runs on the
# CAN-driven card loop (core 4, shared with controlsd/selfdrived), so avoid
# rebuilding 32 f-strings per radar frame.
self.track_addrs: list[tuple[int, str]] = []
if self.radar_config is not None:
self.track_addrs = [(addr, f"RADAR_TRACK_{addr:x}")
for addr in range(self.radar_config.start_addr,
self.radar_config.start_addr + self.radar_config.msg_count)]
def update(self, can_strings):
if self.ioniq_6_radar_probe and self.rcp is not None and not self.ioniq_6_radar_probe_logged:
@@ -73,8 +110,56 @@ class RadarInterface(RadarInterfaceBase):
if not self.rcp.can_valid:
ret.errors.canError = True
for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT):
msg = self.rcp.vl[f"RADAR_TRACK_{addr:x}"]
if self.radar_config is None:
return ret
radar_type = self.radar_config.radar_type
vl = self.rcp.vl
for addr, track_name in self.track_addrs:
msg = vl[track_name]
if radar_type == "mrr30":
for i in ("1", "2"):
track_key = addr * 2 + int(i) - 1
if track_key not in self.pts:
self.pts[track_key] = structs.RadarData.RadarPoint()
self.pts[track_key].trackId = self.track_id
self.track_id += 1
valid = msg[f"{i}_STATE"] in (3, 4)
if valid:
pt = self.pts[track_key]
pt.measured = True
pt.dRel = msg[f"{i}_LONG_DIST"]
pt.yRel = msg[f"{i}_LAT_DIST"]
pt.vRel = msg[f"{i}_REL_SPEED"]
pt.aRel = float("nan")
pt.yvRel = float("nan")
else:
del self.pts[track_key]
continue
if radar_type == "mrr35":
# Most of the 32 channels are empty each frame. Only allocate a point
# when the channel is valid; drop it otherwise. Avoids the per-frame
# alloc-then-delete churn on the ~27 idle channels.
if msg["STATE"] in (3, 4):
pt = self.pts.get(addr)
if pt is None:
pt = structs.RadarData.RadarPoint()
pt.trackId = self.track_id
self.track_id += 1
self.pts[addr] = pt
pt.measured = True
pt.dRel = msg["LONG_DIST"]
pt.yRel = msg["LAT_DIST"]
pt.vRel = msg["REL_SPEED"]
pt.aRel = msg["REL_ACCEL"]
pt.yvRel = float("nan")
elif addr in self.pts:
del self.pts[addr]
continue
if addr not in self.pts:
self.pts[addr] = structs.RadarData.RadarPoint()
@@ -14,11 +14,12 @@ from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, dec
from opendbc.car.hyundai.interface import CarInterface
from opendbc.car.hyundai import hyundaican, hyundaicanfd
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR
from opendbc.car.hyundai.radar_interface import MRR30_RADAR_START_ADDR, MRR35_RADAR_START_ADDR, RADAR_START_ADDR, get_radar_track_config
from opendbc.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \
HYBRID_CAR, EV_CAR, FW_QUERY_CONFIG, LEGACY_SAFETY_MODE_CAR, CANFD_FUZZY_WHITELIST, \
UNSUPPORTED_LONGITUDINAL_CAR, PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
CarControllerParams, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, Buttons
CarControllerParams, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
HyundaiStarPilotSafetyFlags, Buttons
LongCtrlState = CarControl.Actuators.LongControlState
from opendbc.car.hyundai.fingerprints import FW_VERSIONS
@@ -32,7 +33,12 @@ NO_DATES_PLATFORMS = {
CAR.KIA_SPORTAGE_5TH_GEN,
CAR.KIA_SPORTAGE_HEV_2026,
CAR.HYUNDAI_SANTA_CRUZ_1ST_GEN,
CAR.HYUNDAI_SANTA_CRUZ_2025,
CAR.HYUNDAI_TUCSON_4TH_GEN,
CAR.HYUNDAI_TUCSON_2025,
CAR.HYUNDAI_TUCSON_HEV_2025,
CAR.HYUNDAI_TUCSON_PHEV_2025,
CAR.KIA_SPORTAGE_2026,
# CAN
CAR.HYUNDAI_ELANTRA,
CAR.HYUNDAI_ELANTRA_GT_I30,
@@ -65,6 +71,37 @@ HYUNDAI_NON_SCC_CARS = (
)
HYUNDAI_NON_SCC_FW_CARS = tuple(car_model for car_model in HYUNDAI_NON_SCC_CARS if car_model in FW_VERSIONS)
CCNC_NON_HDA2_CARS = (
CAR.HYUNDAI_KONA_2ND_GEN,
CAR.HYUNDAI_KONA_HEV_2ND_GEN,
CAR.HYUNDAI_KONA_EV_2ND_GEN,
CAR.HYUNDAI_SANTA_FE_HEV_5TH_GEN,
CAR.HYUNDAI_SONATA_2024,
CAR.HYUNDAI_SONATA_HEV_2024,
CAR.HYUNDAI_IONIQ_5_N,
CAR.HYUNDAI_TUCSON_2025,
CAR.HYUNDAI_TUCSON_HEV_2025,
CAR.HYUNDAI_TUCSON_PHEV_2025,
CAR.HYUNDAI_SANTA_CRUZ_2025,
CAR.KIA_K4_2025,
CAR.KIA_K5_2025,
CAR.KIA_SPORTAGE_2026,
CAR.KIA_SORENTO_2024,
)
ANGLE_STEERING_CARS = (
CAR.HYUNDAI_SANTA_FE_HEV_5TH_GEN,
CAR.HYUNDAI_IONIQ_5_PE,
CAR.HYUNDAI_IONIQ_9,
CAR.KIA_SPORTAGE_2026,
CAR.KIA_SPORTAGE_HEV_2026,
CAR.KIA_SORENTO_HEV_4TH_GEN_LFA2,
CAR.KIA_EV6_2025,
CAR.KIA_EV9,
CAR.GENESIS_GV70_ELECTRIFIED_2ND_GEN,
CAR.GENESIS_GV80_2025,
)
def get_test_toggles() -> SimpleNamespace:
return SimpleNamespace(always_on_lateral_lkas=False, force_torque_controller=False, nnff=False, nnff_lite=False)
@@ -83,12 +120,62 @@ class TestHyundaiFingerprint:
assert bool(CP.flags & HyundaiFlags.CANFD_LKA_STEERING) == lka_steering
# radar available
for radar in (True, False):
fingerprint = gen_empty_fingerprint()
if radar:
fingerprint[1][RADAR_START_ADDR] = 8
CP = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False, None)
assert CP.radarUnavailable != radar
for candidate in (CAR.HYUNDAI_SONATA, CAR.GENESIS_G90):
assert get_radar_track_config(candidate).start_addr == RADAR_START_ADDR
for radar in (True, False):
fingerprint = gen_empty_fingerprint()
if radar:
fingerprint[1][RADAR_START_ADDR] = 8
CP = CarInterface.get_params(candidate, fingerprint, [], False, False, False, None)
assert CP.radarUnavailable != radar
fingerprint = gen_empty_fingerprint()
fingerprint[1][RADAR_START_ADDR] = 8
CP = CarInterface.get_params(CAR.GENESIS_G90, fingerprint, [], True, False, False, None)
assert CP.openpilotLongitudinalControl
assert not CP.radarUnavailable
for candidate, radar_addr in (
(CAR.HYUNDAI_IONIQ_5, MRR30_RADAR_START_ADDR),
(CAR.HYUNDAI_IONIQ_5_N, MRR30_RADAR_START_ADDR),
(CAR.KIA_EV6_2025, MRR30_RADAR_START_ADDR),
(CAR.HYUNDAI_KONA_EV_2ND_GEN, MRR35_RADAR_START_ADDR),
(CAR.HYUNDAI_IONIQ_6, MRR35_RADAR_START_ADDR),
(CAR.HYUNDAI_IONIQ_9, MRR35_RADAR_START_ADDR),
):
radar_config = get_radar_track_config(candidate)
assert radar_config.start_addr == radar_addr
for radar in (True, False):
fingerprint = gen_empty_fingerprint()
if radar:
fingerprint[radar_config.bus][radar_addr] = 8
CP = CarInterface.get_params(candidate, fingerprint, [], False, False, False, None)
assert CP.radarUnavailable != radar
assert get_radar_track_config(CAR.HYUNDAI_IONIQ_6).start_addr == MRR35_RADAR_START_ADDR
fingerprint = gen_empty_fingerprint()
fingerprint[1][MRR35_RADAR_START_ADDR] = 24
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fingerprint, [], False, False, False, None)
assert not CP.openpilotLongitudinalControl
assert CP.radarUnavailable
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, gen_empty_fingerprint(), [], True, False, False, None)
assert CP.openpilotLongitudinalControl
assert CP.radarUnavailable
fingerprint = gen_empty_fingerprint()
fingerprint[get_radar_track_config(CAR.HYUNDAI_IONIQ_6).bus][MRR35_RADAR_START_ADDR] = 24
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fingerprint, [], True, False, False, None)
assert CP.openpilotLongitudinalControl
assert not CP.radarUnavailable
assert get_radar_track_config(CAR.HYUNDAI_IONIQ_6).frequency == 20
fingerprint = gen_empty_fingerprint()
fingerprint[CanBus(None, fingerprint).CAM][0x50] = 32
fingerprint[get_radar_track_config(CAR.HYUNDAI_IONIQ_5).bus][MRR30_RADAR_START_ADDR] = 32
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_5, fingerprint, [], True, False, False, None)
assert CP.openpilotLongitudinalControl
assert not CP.radarUnavailable
for candidate in HYUNDAI_NON_SCC_CARS:
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], True, False, False, None)
@@ -106,12 +193,42 @@ class TestHyundaiFingerprint:
CP = CarInterface.get_params(CAR.KIA_SPORTAGE_HEV_2026, fingerprint, [], False, False, False, None)
assert CP.flags & HyundaiFlags.SEND_LFA
@pytest.mark.parametrize("candidate", CCNC_NON_HDA2_CARS)
def test_ccnc_non_hda2_platforms_set_ccnc_safety(self, candidate):
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, False, False, None)
assert CP.flags & HyundaiFlags.CCNC
assert CP.flags & HyundaiFlags.CANFD_CAMERA_SCC
assert not (CP.flags & HyundaiFlags.CANFD_LKA_STEERING)
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CCNC
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CAMERA_SCC
@pytest.mark.parametrize("candidate", ANGLE_STEERING_CARS)
def test_angle_steering_platforms_use_angle_control(self, candidate):
CP = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, False, False, None)
assert CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING
assert CP.steerControlType == CarParams.SteerControlType.angle
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CANFD_ANGLE_STEERING
def test_ccnc_hda2_lka_layout_does_not_set_ccnc_safety_param(self):
fingerprint = gen_empty_fingerprint()
cam_can = CanBus(None, fingerprint).CAM
fingerprint[cam_can] = {0x50: 16}
CP = CarInterface.get_params(CAR.KIA_K4_2025, fingerprint, [], False, False, False, None)
assert CP.flags & HyundaiFlags.CCNC
assert CP.flags & HyundaiFlags.CANFD_LKA_STEERING
assert not (CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CCNC)
def test_ioniq_6_hda1_layout_stays_non_lka(self):
fingerprint = gen_empty_fingerprint()
fingerprint[1] = {0x100: 8, 0x110: 8}
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, fingerprint, [], False, False, False, None)
assert not (CP.flags & HyundaiFlags.CCNC)
assert not (CP.flags & HyundaiFlags.CANFD_LKA_STEERING)
assert bool(CP.flags & HyundaiFlags.CANFD_CAMERA_SCC)
@@ -121,6 +238,19 @@ class TestHyundaiFingerprint:
assert palisade_2023.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CAN_CANFD_BLENDED
assert palisade_2023.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CANCEL_BTN_ENABLE
def test_hyundai_lkas_button_sets_starpilot_safety_flag(self):
fingerprint = gen_empty_fingerprint()
fingerprint[0][0x391] = 8
sonata = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False, None)
assert sonata.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON
sonata_without_lda = CarInterface.get_params(CAR.HYUNDAI_SONATA, gen_empty_fingerprint(), [], False, False, False, None)
assert not (sonata_without_lda.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON)
palisade_2023 = CarInterface.get_params(CAR.HYUNDAI_PALISADE_2023, gen_empty_fingerprint(), [], True, False, False, None)
assert palisade_2023.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON
def test_non_scc_flag_quirks(self):
elantra_hev = CarInterface.get_params(CAR.HYUNDAI_ELANTRA_HEV_2022_NON_SCC, gen_empty_fingerprint(), [], True, False, False, None)
assert elantra_hev.flags & HyundaiFlags.HYBRID
@@ -604,6 +734,124 @@ class TestHyundaiFingerprint:
assert parser.vl["SCC_CONTROL"]["ObjValid"] == 1
assert parser.vl["SCC_CONTROL"]["OBJ_STATUS"] == 0
def test_canfd_acc_control_preserves_stock_ccnc_object_fields(self):
CP = CarParams.new_message()
CP.carFingerprint = CAR.HYUNDAI_SONATA_2024
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CCNC)
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
can_bus = CanBus(CP)
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("SCC_CONTROL", 0)], can_bus.ECAN)
msg = hyundaicanfd.create_acc_control(packer, can_bus, enabled=True, accel_last=0.0, accel=0.1, stopping=False,
gas_override=False, set_speed=42, hud_control=SimpleNamespace(leadDistanceBars=3),
direct_accel=True, lead_distance=27.5, lead_rel_speed=-1.2, lead_visible=True,
cruise_info={"ACC_ObjDist": 13.5, "ACC_ObjRelSpd": -0.4})
parser.update([(1, [msg])])
assert parser.can_valid
assert parser.vl["SCC_CONTROL"]["ACC_ObjDist"] == pytest.approx(13.5)
assert parser.vl["SCC_CONTROL"]["ACC_ObjRelSpd"] == pytest.approx(-0.4)
def test_ccnc_hud_helper_clears_faults_and_generates_ui_fields(self):
CP = CarParams.new_message()
CP.carFingerprint = CAR.HYUNDAI_SONATA_2024
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CCNC)
CP.openpilotLongitudinalControl = True
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
can_bus = CanBus(CP)
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("CCNC_0x161", 0), ("CCNC_0x162", 0)], can_bus.ECAN)
msg_161 = {
"ALERTS_2": 5,
"ALERTS_3": 17,
"ALERTS_5": 5,
"SOUNDS_3": 5,
"SOUNDS_4": 2,
"LFA_ICON": 3,
}
msg_162 = {fault: 1 for fault in ("FAULT_LSS", "FAULT_HDA", "FAULT_DAS", "FAULT_LFA", "FAULT_DAW", "FAULT_ESS")}
msg_162["VIBRATE"] = 0
msg_1b5 = {
"Info_LftLnPosVal": 1.4,
"Info_RtLnPosVal": 1.9,
"Info_LftLnQualSta": 3,
"Info_RtLnQualSta": 3,
"Longitudinal_Distance": 42.0,
}
hud = SimpleNamespace(leftLaneVisible=True, rightLaneVisible=True, leftLaneDepart=True, rightLaneDepart=False,
leadDistanceBars=3, leadVisible=True)
out = SimpleNamespace(steeringAngleDeg=22.5, vEgo=15.0, leftBlindspot=True, rightBlindspot=False,
vCruiseCluster=88.0)
msgs = hyundaicanfd.create_ccnc(packer, can_bus, openpilot_longitudinal=True, enabled=True, hud=hud,
left_blinker=False, right_blinker=False, msg_161=msg_161, msg_162=msg_162,
msg_1b5=msg_1b5, is_metric=False, out=out, main_cruise_enabled=True, lfa_icon=2)
parser.update([(1, msgs)])
assert parser.can_valid
assert parser.vl["CCNC_0x161"]["DAW_ICON"] == 0
assert parser.vl["CCNC_0x161"]["LKA_ICON"] == 0
assert parser.vl["CCNC_0x161"]["LFA_ICON"] == 2
assert parser.vl["CCNC_0x161"]["CENTERLINE"] == 1
assert parser.vl["CCNC_0x161"]["LANELINE_CURVATURE"] == 20
assert parser.vl["CCNC_0x161"]["LANELINE_LEFT"] == 4
assert parser.vl["CCNC_0x161"]["LANELINE_RIGHT"] == 2
assert parser.vl["CCNC_0x161"]["LCA_LEFT_ICON"] == 1
assert parser.vl["CCNC_0x161"]["LCA_RIGHT_ICON"] == 4
assert parser.vl["CCNC_0x161"]["ALERTS_2"] == 0
assert parser.vl["CCNC_0x161"]["ALERTS_3"] == 0
assert parser.vl["CCNC_0x161"]["ALERTS_5"] == 0
assert parser.vl["CCNC_0x161"]["SOUNDS_3"] == 0
assert parser.vl["CCNC_0x161"]["SOUNDS_4"] == 0
assert parser.vl["CCNC_0x161"]["SETSPEED"] == 3
assert parser.vl["CCNC_0x161"]["SETSPEED_HUD"] == 2
assert parser.vl["CCNC_0x161"]["SETSPEED_SPEED"] == 55
assert parser.vl["CCNC_0x161"]["DISTANCE"] == 3
assert parser.vl["CCNC_0x161"]["DISTANCE_LEAD"] == 2
assert all(parser.vl["CCNC_0x162"][fault] == 0 for fault in ("FAULT_LSS", "FAULT_HDA", "FAULT_DAS", "FAULT_LFA", "FAULT_DAW", "FAULT_ESS"))
assert parser.vl["CCNC_0x162"]["VIBRATE"] == 1
assert parser.vl["CCNC_0x162"]["LEAD"] == 2
assert parser.vl["CCNC_0x162"]["LEAD_DISTANCE"] == pytest.approx(42.0)
def test_ccnc_hud_helper_generates_lane_position_animation_and_lca_arrows(self):
CP = CarParams.new_message()
CP.carFingerprint = CAR.HYUNDAI_SONATA_2024
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CCNC)
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
can_bus = CanBus(CP)
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("CCNC_0x161", 0), ("CCNC_0x162", 0)], can_bus.ECAN)
hud = SimpleNamespace(leftLaneVisible=True, rightLaneVisible=True, leftLaneDepart=False, rightLaneDepart=False,
leadDistanceBars=1, leadVisible=False)
out = SimpleNamespace(steeringAngleDeg=0.0, vEgo=15.0, leftBlindspot=False, rightBlindspot=False,
vCruiseCluster=55.0)
msg_1b5 = {
"Info_LftLnPosVal": 1.4,
"Info_RtLnPosVal": 1.9,
"Info_LftLnQualSta": 3,
"Info_RtLnQualSta": 3,
"Longitudinal_Distance": 0.0,
}
msgs = hyundaicanfd.create_ccnc(packer, can_bus, openpilot_longitudinal=False, enabled=True, hud=hud,
left_blinker=True, right_blinker=False,
msg_161={"ALERTS_2": 0, "ALERTS_3": 0, "ALERTS_5": 0, "SOUNDS_4": 0, "LFA_ICON": 2},
msg_162={fault: 0 for fault in ("FAULT_LSS", "FAULT_HDA", "FAULT_DAS", "FAULT_LFA", "FAULT_DAW", "FAULT_ESS")},
msg_1b5=msg_1b5, is_metric=True, out=out, main_cruise_enabled=True, lfa_icon=2)
parser.update([(1, msgs)])
assert parser.can_valid
assert parser.vl["CCNC_0x161"]["LANELINE_CURVATURE"] == 15
assert parser.vl["CCNC_0x161"]["LANELINE_LEFT"] == 6
assert parser.vl["CCNC_0x161"]["LANELINE_RIGHT"] == 6
assert parser.vl["CCNC_0x161"]["LCA_LEFT_ICON"] == 2
assert parser.vl["CCNC_0x161"]["LCA_LEFT_ARROW"] == 2
assert parser.vl["CCNC_0x161"]["LCA_RIGHT_ARROW"] == 0
assert parser.vl["CCNC_0x161"]["LANELINE_LEFT_POSITION"] == 12
assert parser.vl["CCNC_0x161"]["LANELINE_RIGHT_POSITION"] == 18
def test_canfd_scc_lead_state_prefers_openpilot_lead_distance(self):
CP = CarParams.new_message()
CP.carFingerprint = CAR.KIA_EV6
@@ -1196,7 +1444,7 @@ class TestHyundaiFingerprint:
# Hyundai places the ECU part number in their FW versions, assert all parsable
# Some examples of valid formats: b"56310-L0010", b"56310L0010", b"56310/M6300"
if car_model != CAR.KIA_SPORTAGE_HEV_2026:
if car_model not in (CAR.KIA_SPORTAGE_2026, CAR.KIA_SPORTAGE_HEV_2026):
assert all(b"-" in code for code, _ in codes), \
f"FW does not have part number: {fw}"
+167 -9
View File
@@ -18,6 +18,9 @@ SPORTAGE_HEV_2026_LOW_SPEED_JERK_SPEED = 11.0
SPORTAGE_HEV_2026_LOW_SPEED_JERK_WIDTH = 5.0
SPORTAGE_HEV_2026_MAX_ANGLE_RATE = 6.5
SPORTAGE_HEV_2026_STEER_ANGLE_MAX = 220.0
HYUNDAI_MANDO_FRONT_RADAR_DBC = "hyundai_kia_mando_front_radar_generated"
HYUNDAI_MRR30_RADAR_DBC = "hyundai_mrr30_radar_generated"
HYUNDAI_MRR35_RADAR_DBC = "hyundai_mrr35_radar_generated"
class CarControllerParams:
@@ -121,6 +124,7 @@ class HyundaiSafetyFlags(IntFlag):
NON_SCC = 4096
CAN_CANFD_BLENDED = 8192
CANCEL_BTN_ENABLE = 16384
CCNC = 32768
class HyundaiStarPilotSafetyFlags(IntFlag):
@@ -184,8 +188,6 @@ class HyundaiFlags(IntFlag):
MIN_STEER_32_MPH = 2 ** 23
HAS_LDA_BUTTON = 2 ** 24
FCEV = 2 ** 25
ALT_LIMITS_2 = 2 ** 26
@@ -203,6 +205,9 @@ class HyundaiFlags(IntFlag):
NON_SCC_NO_FCA = 2 ** 30
NON_SCC_RADAR_FCA = 2 ** 31
# Connected Car Navigation Cockpit CAN-FD platforms.
CCNC = 2 ** 24
@dataclass
class HyundaiCarDocs(CarDocs):
@@ -222,7 +227,7 @@ class HyundaiPlatformConfig(PlatformConfig):
def init(self):
if self.flags & HyundaiFlags.MANDO_RADAR:
self.dbc_dict = {Bus.pt: "hyundai_kia_generic", Bus.radar: 'hyundai_kia_mando_front_radar_generated'}
self.dbc_dict = {Bus.pt: "hyundai_kia_generic", Bus.radar: HYUNDAI_MANDO_FRONT_RADAR_DBC}
if self.flags & HyundaiFlags.MIN_STEER_32_MPH:
self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS)
@@ -234,9 +239,12 @@ class HyundaiPlatformConfig(PlatformConfig):
@dataclass
class HyundaiCanFDPlatformConfig(PlatformConfig):
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_canfd_generated"})
radar_dbc: str | None = None
def init(self):
self.flags |= HyundaiFlags.CANFD
if self.radar_dbc is not None:
self.dbc_dict = {Bus.pt: "hyundai_canfd_generated", Bus.radar: self.radar_dbc}
@dataclass
@@ -342,6 +350,16 @@ class CAR(Platforms):
CarSpecs(mass=1491, wheelbase=2.6, steerRatio=13.42, tireStiffnessFactor=0.385),
flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.ALT_LIMITS_2,
)
HYUNDAI_KONA_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Kona (without HDA II) 2024-25", car_parts=CarParts.common([CarHarness.hyundai_l]))],
CarSpecs(mass=1590, wheelbase=2.66, steerRatio=13.6, tireStiffnessFactor=0.385),
flags=HyundaiFlags.CCNC,
)
HYUNDAI_KONA_HEV_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Hybrid (without HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_l]))],
CarSpecs(mass=1590, wheelbase=2.66, steerRatio=13.6, tireStiffnessFactor=0.385),
flags=HyundaiFlags.CCNC,
)
HYUNDAI_KONA_EV = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Electric 2018-21", car_parts=CarParts.common([CarHarness.hyundai_g]))],
CarSpecs(mass=1685, wheelbase=2.6, steerRatio=13.42, tireStiffnessFactor=0.385),
@@ -353,10 +371,14 @@ class CAR(Platforms):
flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
)
HYUNDAI_KONA_EV_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Electric (with HDA II, Korea only) 2023", video="https://www.youtube.com/watch?v=U2fOCmcQ8hw",
car_parts=CarParts.common([CarHarness.hyundai_r]))],
[
HyundaiCarDocs("Hyundai Kona Electric (with HDA II, Korea only) 2023", video="https://www.youtube.com/watch?v=U2fOCmcQ8hw",
car_parts=CarParts.common([CarHarness.hyundai_r])),
HyundaiCarDocs("Hyundai Kona Electric (without HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_a])),
],
CarSpecs(mass=1740, wheelbase=2.66, steerRatio=13.6, tireStiffnessFactor=0.385),
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE | HyundaiFlags.CCNC,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
)
HYUNDAI_KONA_HEV = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Hybrid 2020", car_parts=CarParts.common([CarHarness.hyundai_i]))], # TODO: check packages,
@@ -390,12 +412,27 @@ class CAR(Platforms):
HYUNDAI_SANTA_FE.specs,
flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
)
HYUNDAI_SANTA_FE_HEV_5TH_GEN = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Hyundai Santa Fe Hybrid (with HDA II & LFA2) 2024-25", "Highway Driving Assist II & Lane Follow Assist 2",
car_parts=CarParts.common([CarHarness.hyundai_p])),
HyundaiCarDocs("Hyundai Santa Fe Hybrid (without HDA II, LFA2) 2025-26", "Lane Follow Assist 2",
car_parts=CarParts.common([CarHarness.hyundai_l])),
],
CarSpecs(mass=2035, wheelbase=2.81, steerRatio=13.72),
flags=HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.CCNC,
)
HYUNDAI_SONATA = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Sonata 2020-23", "All", video="https://www.youtube.com/watch?v=ix63r9kE3Fw",
car_parts=CarParts.common([CarHarness.hyundai_a]))],
CarSpecs(mass=1513, wheelbase=2.84, steerRatio=13.27 * 1.15, tireStiffnessFactor=0.65), # 15% higher at the center seems reasonable
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8,
)
HYUNDAI_SONATA_2024 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Sonata (without HDA II) 2024-25", car_parts=CarParts.common([CarHarness.hyundai_a]))],
CarSpecs(mass=1556, wheelbase=2.84, steerRatio=12.81),
flags=HyundaiFlags.CCNC,
)
HYUNDAI_SONATA_LF = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarHarness.hyundai_e]))],
CarSpecs(mass=1536, wheelbase=2.804, steerRatio=13.27 * 1.15), # 15% higher at the center seems reasonable
@@ -441,6 +478,11 @@ class CAR(Platforms):
HYUNDAI_SONATA.specs,
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
)
HYUNDAI_SONATA_HEV_2024 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Sonata Hybrid (without HDA II) 2024-25", car_parts=CarParts.common([CarHarness.hyundai_a]))],
CarSpecs(mass=1616, wheelbase=2.84, steerRatio=13.27),
flags=HyundaiFlags.CCNC,
)
HYUNDAI_IONIQ_5 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_q])),
@@ -449,11 +491,37 @@ class CAR(Platforms):
],
CarSpecs(mass=1948, wheelbase=2.97, steerRatio=14.26, tireStiffnessFactor=0.65),
flags=HyundaiFlags.EV,
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
)
HYUNDAI_IONIQ_5_PE = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Hyundai Ioniq 5 PE (with HDA II & LFA2) 2025-26", "Highway Driving Assist II & Lane Follow Assist 2",
car_parts=CarParts.common([CarHarness.hyundai_q]))
],
HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
)
HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", car_parts=CarParts.common([CarHarness.hyundai_s]))],
CarSpecs(mass=2205, wheelbase=3.00, steerRatio=14.26, tireStiffnessFactor=1.3),
flags=HyundaiFlags.EV | HyundaiFlags.CCNC,
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
)
HYUNDAI_IONIQ_6 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))],
HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
)
HYUNDAI_IONIQ_9 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Hyundai Ioniq 9 (with HDA II & LFA2) 2025-26", "Highway Driving Assist II & Lane Follow Assist 2",
car_parts=CarParts.common([CarHarness.hyundai_m]))
],
CarSpecs(mass=2700, wheelbase=3.13, steerRatio=16.02),
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
)
HYUNDAI_TUCSON_4TH_GEN = HyundaiCanFDPlatformConfig(
[
@@ -464,11 +532,31 @@ class CAR(Platforms):
],
CarSpecs(mass=1630, wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385),
)
HYUNDAI_TUCSON_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Tucson (without HDA II) 2025-26", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(mass=1630, wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385),
flags=HyundaiFlags.CCNC,
)
HYUNDAI_TUCSON_HEV_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Tucson Hybrid (without HDA II) 2025-26", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(mass=1630, wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385),
flags=HyundaiFlags.CCNC,
)
HYUNDAI_TUCSON_PHEV_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Tucson Plug-in Hybrid (without HDA II) 2025", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(mass=1630, wheelbase=2.756, steerRatio=13.7, tireStiffnessFactor=0.385),
flags=HyundaiFlags.CCNC,
)
HYUNDAI_SANTA_CRUZ_1ST_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Santa Cruz 2022-24", car_parts=CarParts.common([CarHarness.hyundai_n]))],
# weight from Limited trim - the only supported trim, steering ratio according to Hyundai News https://www.hyundainews.com/assets/documents/original/48035-2022SantaCruzProductGuideSpecsv2081521.pdf
CarSpecs(mass=1870, wheelbase=3, steerRatio=14.2),
)
HYUNDAI_SANTA_CRUZ_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Santa Cruz (without HDA II) 2025", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(mass=1920, wheelbase=3, steerRatio=14.2),
flags=HyundaiFlags.CCNC,
)
HYUNDAI_CUSTIN_1ST_GEN = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Custin 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
CarSpecs(mass=1690, wheelbase=3.055, steerRatio=17), # mass: from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0, steerRatio: from learner
@@ -483,11 +571,24 @@ class CAR(Platforms):
],
CarSpecs(mass=2878 * CV.LB_TO_KG, wheelbase=2.8, steerRatio=13.75, tireStiffnessFactor=0.5)
)
KIA_K4_2025 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia K4 (without HDA II) 2025", car_parts=CarParts.common([CarHarness.hyundai_a])),
HyundaiCarDocs("Kia K4 (with HDA II) 2025", car_parts=CarParts.common([CarHarness.hyundai_r])),
],
CarSpecs(mass=2987 * CV.LB_TO_KG, wheelbase=2.72, steerRatio=13.4),
flags=HyundaiFlags.CCNC,
)
KIA_K5_2021 = HyundaiPlatformConfig(
[HyundaiCarDocs("Kia K5 2021-24", car_parts=CarParts.common([CarHarness.hyundai_a]))],
CarSpecs(mass=3381 * CV.LB_TO_KG, wheelbase=2.85, steerRatio=13.27, tireStiffnessFactor=0.5), # 2021 Kia K5 Steering Ratio (all trims)
flags=HyundaiFlags.CHECKSUM_CRC8,
)
KIA_K5_2025 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Kia K5 (without HDA II) 2025", car_parts=CarParts.common([CarHarness.hyundai_m]))],
CarSpecs(mass=3230 * CV.LB_TO_KG, wheelbase=2.85, steerRatio=13.27),
flags=HyundaiFlags.CCNC,
)
KIA_K5_HEV_2020 = HyundaiPlatformConfig(
[HyundaiCarDocs("Kia K5 Hybrid 2020-22", car_parts=CarParts.common([CarHarness.hyundai_a]))],
KIA_K5_2021.specs,
@@ -580,6 +681,13 @@ class CAR(Platforms):
# weight from SX and above trims, average of FWD and AWD version, steering ratio according to Kia News https://www.kiamedia.com/us/en/models/sportage/2023/specifications
CarSpecs(mass=1725, wheelbase=2.756, steerRatio=13.6),
)
KIA_SPORTAGE_2026 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia Sportage (without HDA II) 2026", car_parts=CarParts.common([CarHarness.hyundai_n])),
],
CarSpecs(mass=1735, wheelbase=2.756, steerRatio=13.7),
flags=HyundaiFlags.CANFD_ANGLE_STEERING | HyundaiFlags.CCNC,
)
KIA_SPORTAGE_HEV_2026 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Kia Sportage Hybrid 2026", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(mass=1812, wheelbase=2.756, steerRatio=13.7),
@@ -599,6 +707,11 @@ class CAR(Platforms):
CarSpecs(mass=3957 * CV.LB_TO_KG, wheelbase=2.81, steerRatio=13.5), # average of the platforms
flags=HyundaiFlags.RADAR_SCC,
)
KIA_SORENTO_2024 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Kia Sorento (without HDA II) 2024-25", car_parts=CarParts.common([CarHarness.hyundai_a]))],
CarSpecs(mass=3957 * CV.LB_TO_KG, wheelbase=2.81, steerRatio=13.5),
flags=HyundaiFlags.CCNC,
)
KIA_SORENTO_HEV_4TH_GEN = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia Sorento Hybrid 2021-23", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
@@ -607,6 +720,13 @@ class CAR(Platforms):
CarSpecs(mass=4395 * CV.LB_TO_KG, wheelbase=2.81, steerRatio=13.5), # average of the platforms
flags=HyundaiFlags.RADAR_SCC,
)
KIA_SORENTO_HEV_4TH_GEN_LFA2 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia Sorento Hybrid 2026", "All", car_parts=CarParts.common([CarHarness.hyundai_q])),
],
CarSpecs(mass=1970, wheelbase=2.814, steerRatio=13.27, tireStiffnessFactor=0.65),
flags=HyundaiFlags.CANFD_ANGLE_STEERING,
)
KIA_STINGER = HyundaiPlatformConfig(
[HyundaiCarDocs("Kia Stinger 2018-20", video="https://www.youtube.com/watch?v=MJ94qoofYw0",
car_parts=CarParts.common([CarHarness.hyundai_c]))],
@@ -630,6 +750,22 @@ class CAR(Platforms):
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
flags=HyundaiFlags.EV,
)
KIA_EV6_2025 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia EV6 (with HDA I) 2025", "Highway Driving Assist I", car_parts=CarParts.common([CarHarness.hyundai_p]))
],
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR30_RADAR_DBC,
)
KIA_EV9 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia EV9 2025-26", car_parts=CarParts.common([CarHarness.hyundai_r]))
],
CarSpecs(mass=2664, wheelbase=3.1, steerRatio=16),
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
)
KIA_CARNIVAL_4TH_GEN = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia Carnival 2022-24", car_parts=CarParts.common([CarHarness.hyundai_a])),
@@ -680,6 +816,14 @@ class CAR(Platforms):
CarSpecs(mass=2260, wheelbase=2.87, steerRatio=17.1),
flags=HyundaiFlags.EV,
)
GENESIS_GV70_ELECTRIFIED_2ND_GEN = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Genesis GV70 Electrified 2026", "All", car_parts=CarParts.common([CarHarness.hyundai_m])),
],
GENESIS_GV70_ELECTRIFIED_1ST_GEN.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
)
GENESIS_G80 = HyundaiPlatformConfig(
[HyundaiCarDocs("Genesis G80 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
CarSpecs(mass=2060, wheelbase=3.01, steerRatio=16.5),
@@ -692,12 +836,24 @@ class CAR(Platforms):
GENESIS_G90 = HyundaiPlatformConfig(
[HyundaiCarDocs("Genesis G90 2017-20", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
CarSpecs(mass=2200, wheelbase=3.15, steerRatio=12.069),
flags=HyundaiFlags.MANDO_RADAR,
)
GENESIS_GV80 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Genesis GV80 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_m]))],
CarSpecs(mass=2258, wheelbase=2.95, steerRatio=14.14),
flags=HyundaiFlags.RADAR_SCC,
)
GENESIS_GV80_2025 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Genesis GV80 (3.5T Prestige Trim, with HDA II & LFA2) 2025", "Highway Driving Assist II & Lane Follow Assist 2",
car_parts=CarParts.common([CarHarness.hyundai_q])),
HyundaiCarDocs("Genesis GV80 Coupe (with HDA II & LFA2) 2025", "Highway Driving Assist II & Lane Follow Assist 2",
car_parts=CarParts.common([CarHarness.hyundai_q])),
],
GENESIS_GV80.specs,
flags=HyundaiFlags.CANFD_ANGLE_STEERING,
radar_dbc=HYUNDAI_MRR35_RADAR_DBC,
)
# Hyundai non-SCC extensions
HYUNDAI_BAYON_1ST_GEN_NON_SCC = HyundaiNonSccPlatformConfig(
@@ -857,7 +1013,7 @@ PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z]
# We've seen both ICE and hybrid for these platforms, and they have hybrid descriptors (e.g. MQ4 vs MQ4H)
CANFD_FUZZY_WHITELIST = {CAR.KIA_SORENTO_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN, CAR.KIA_K8_HEV_1ST_GEN,
# TODO: the hybrid variant is not out yet
CAR.KIA_CARNIVAL_4TH_GEN}
CAR.KIA_CARNIVAL_4TH_GEN, CAR.KIA_SORENTO_HEV_4TH_GEN_LFA2}
# List of ECUs expected to have platform codes, camera and radar should exist on all cars
# TODO: use abs, it has the platform code and part number on many platforms
@@ -951,9 +1107,11 @@ CAN_GEARS = {
CANFD_CAR = CAR.with_flags(HyundaiFlags.CANFD)
CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
# Cars with CANFD_NO_RADAR_DISABLE that now work with SecurityAccess handshake
CANFD_SECURITYACCESS_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN}
# 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}
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
CANFD_RADAR_LIVE_LONGITUDINAL_CAR = {CAR.HYUNDAI_IONIQ_5, CAR.HYUNDAI_IONIQ_6}
RADAR_LIVE_LONGITUDINAL_CAR = CANFD_RADAR_LIVE_LONGITUDINAL_CAR | {CAR.GENESIS_G90}
CAMERA_SCC_CAR = CAR.with_flags(HyundaiFlags.CAMERA_SCC)
+1 -1
View File
@@ -233,7 +233,7 @@ class CarInterfaceBase(ABC):
not CP.openpilotLongitudinalControl:
fp_ret.pcmCruiseSpeed = False
if CP.flags & HyundaiFlags.HAS_LDA_BUTTON:
if 0x391 in fingerprint[0] or CP.flags & HyundaiFlags.CAN_CANFD_BLENDED:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
if starpilot_toggles.always_on_lateral_lkas:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
+22
View File
@@ -22,9 +22,21 @@ non_tested_cars = [
MOCK.MOCK,
GM.CADILLAC_ATS,
GM.CADILLAC_ESCALADE_ASCM,
GM.CADILLAC_XT5,
GM.HOLDEN_ASTRA,
GM.CHEVROLET_MALIBU,
HYUNDAI.GENESIS_G90,
HYUNDAI.GENESIS_GV70_ELECTRIFIED_2ND_GEN,
HYUNDAI.GENESIS_GV80_2025,
HYUNDAI.HYUNDAI_IONIQ_5_PE,
HYUNDAI.HYUNDAI_IONIQ_5_N,
HYUNDAI.HYUNDAI_SANTA_FE_HEV_5TH_GEN,
HYUNDAI.HYUNDAI_TUCSON_PHEV_2025,
HYUNDAI.KIA_EV6_2025,
HYUNDAI.KIA_EV9,
HYUNDAI.KIA_SPORTAGE_2026,
HYUNDAI.KIA_SORENTO_2024,
HYUNDAI.KIA_SORENTO_HEV_4TH_GEN_LFA2,
VOLKSWAGEN.VOLKSWAGEN_CRAFTER_MK2, # need a route from an ACC-equipped Crafter
SUBARU.SUBARU_FORESTER_HYBRID,
VOLKSWAGEN.PORSCHE_MACAN_MK1,
@@ -143,6 +155,7 @@ routes = [
CarTestRoute("66eaa6c3b6b2afc6/00000009--3a5199aabe", HYUNDAI.GENESIS_G80_2ND_GEN_FL), # LKA steering
CarTestRoute("0bbe367c98fa1538/2023-09-16--00-16-49", HYUNDAI.HYUNDAI_CUSTIN_1ST_GEN),
CarTestRoute("f0709d2bc6ca451f/2022-10-15--08-13-54", HYUNDAI.HYUNDAI_SANTA_CRUZ_1ST_GEN),
CarTestRoute("6e7904b03a4aafc2/00000010--31034184b6", HYUNDAI.HYUNDAI_SANTA_CRUZ_2025),
CarTestRoute("4dbd55df87507948/2022-03-01--09-45-38", HYUNDAI.HYUNDAI_SANTA_FE),
CarTestRoute("bf43d9df2b660eb0/2021-09-23--14-16-37", HYUNDAI.HYUNDAI_SANTA_FE_2022),
CarTestRoute("37398f32561a23ad/2021-11-18--00-11-35", HYUNDAI.HYUNDAI_SANTA_FE_HEV_2022),
@@ -156,11 +169,14 @@ routes = [
CarTestRoute("6a42c1197b2a8179/2023-09-21--10-23-44", HYUNDAI.KIA_OPTIMA_H_G4_FL),
CarTestRoute("c75a59efa0ecd502/2021-03-11--20-52-55", HYUNDAI.KIA_SELTOS),
CarTestRoute("5b7c365c50084530/2020-04-15--16-13-24", HYUNDAI.HYUNDAI_SONATA),
CarTestRoute("4267ea8a353cdb36/00000262--8a427003c7", HYUNDAI.HYUNDAI_SONATA_2024, segment=34),
CarTestRoute("b2a38c712dcf90bd/2020-05-18--18-12-48", HYUNDAI.HYUNDAI_SONATA_LF),
CarTestRoute("c344fd2492c7a9d2/2023-12-11--09-03-23", HYUNDAI.HYUNDAI_STARIA_4TH_GEN),
CarTestRoute("fb3fd42f0baaa2f8/2022-03-30--15-25-05", HYUNDAI.HYUNDAI_TUCSON),
CarTestRoute("db68bbe12250812c/2022-12-05--00-54-12", HYUNDAI.HYUNDAI_TUCSON_4TH_GEN), # 2023
CarTestRoute("36e10531feea61a4/2022-07-25--13-37-42", HYUNDAI.HYUNDAI_TUCSON_4TH_GEN), # hybrid
CarTestRoute("a01ca5d4f394c812/00000000--e98b7e4414", HYUNDAI.HYUNDAI_TUCSON_2025),
CarTestRoute("22f9090014364a87/00000002--4cc739c0b2", HYUNDAI.HYUNDAI_TUCSON_HEV_2025),
CarTestRoute("5875672fc1d4bf57/2020-07-23--21-33-28", HYUNDAI.KIA_SORENTO),
CarTestRoute("1d0d000db3370fd0/2023-01-04--22-28-42", HYUNDAI.KIA_SORENTO_4TH_GEN, segment=5),
CarTestRoute("fc19648042eb6896/2023-08-16--11-43-27", HYUNDAI.KIA_SORENTO_HEV_4TH_GEN, segment=14),
@@ -168,6 +184,7 @@ routes = [
CarTestRoute("9c917ba0d42ffe78/2020-04-17--12-43-19", HYUNDAI.HYUNDAI_PALISADE),
CarTestRoute("05a8f0197fdac372/2022-10-19--14-14-09", HYUNDAI.HYUNDAI_IONIQ_5), # LKA steering
CarTestRoute("eb4eae1476647463/2023-08-26--18-07-04", HYUNDAI.HYUNDAI_IONIQ_6, segment=6), # LKA steering
CarTestRoute("71e4e67d29034771/0000001b--b7b4774ec4", HYUNDAI.HYUNDAI_IONIQ_9),
CarTestRoute("3f29334d6134fcd4/2022-03-30--22-00-50", HYUNDAI.HYUNDAI_IONIQ_PHEV_2019),
CarTestRoute("fa8db5869167f821/2021-06-10--22-50-10", HYUNDAI.HYUNDAI_IONIQ_PHEV),
CarTestRoute("e1107f9d04dfb1e2/2023-09-05--22-32-12", HYUNDAI.HYUNDAI_IONIQ_PHEV), # openpilot longitudinal enabled
@@ -178,11 +195,13 @@ routes = [
CarTestRoute("ab59fe909f626921/2021-10-18--18-34-28", HYUNDAI.HYUNDAI_IONIQ_HEV_2022),
CarTestRoute("22d955b2cd499c22/2020-08-10--19-58-21", HYUNDAI.HYUNDAI_KONA),
CarTestRoute("0099bdb24d82951b/00000005--c38d940b04", HYUNDAI.HYUNDAI_KONA_2022),
CarTestRoute("32025f26789d8fab/00000022--a499e8ffa3", HYUNDAI.HYUNDAI_KONA_2ND_GEN),
CarTestRoute("efc48acf44b1e64d/2021-05-28--21-05-04", HYUNDAI.HYUNDAI_KONA_EV),
CarTestRoute("f90d3cd06caeb6fa/2023-09-06--17-15-47", HYUNDAI.HYUNDAI_KONA_EV), # openpilot longitudinal enabled
CarTestRoute("ff973b941a69366f/2022-07-28--22-01-19", HYUNDAI.HYUNDAI_KONA_EV_2022, segment=11),
CarTestRoute("1618132d68afc876/2023-08-27--09-32-14", HYUNDAI.HYUNDAI_KONA_EV_2ND_GEN, segment=13),
CarTestRoute("49f3c13141b6bc87/2021-07-28--08-05-13", HYUNDAI.HYUNDAI_KONA_HEV),
CarTestRoute("97ca61196eb73e0d/00000052--4555329470", HYUNDAI.HYUNDAI_KONA_HEV_2ND_GEN),
CarTestRoute("a74afe0cf708748f/0000000e--a2885a9a71", HYUNDAI.HYUNDAI_NEXO_1ST_GEN),
CarTestRoute("a74afe0cf708748f/0000000c--b476a8fd00", HYUNDAI.HYUNDAI_NEXO_1ST_GEN), # openpilot longitudinal enabled
CarTestRoute("5dddcbca6eb66c62/2020-07-26--13-24-19", HYUNDAI.KIA_STINGER),
@@ -191,7 +210,9 @@ routes = [
CarTestRoute("d545129f3ca90f28/2022-10-19--09-22-54", HYUNDAI.KIA_EV6), # LKA steering
CarTestRoute("68d6a96e703c00c9/2022-09-10--16-09-39", HYUNDAI.KIA_EV6), # LFA steering
CarTestRoute("9b25e8c1484a1b67/2023-04-13--10-41-45", HYUNDAI.KIA_EV6),
CarTestRoute("baf39eeaba1217ca/00000002--b36e3fa031", HYUNDAI.KIA_K4_2025),
CarTestRoute("007d5e4ad9f86d13/2021-09-30--15-09-23", HYUNDAI.KIA_K5_2021),
CarTestRoute("c4a804b067623789/0000007c--163f831540", HYUNDAI.KIA_K5_2025),
CarTestRoute("c58dfc9fc16590e0/2023-01-14--13-51-48", HYUNDAI.KIA_K5_HEV_2020),
CarTestRoute("78ad5150de133637/2023-09-13--16-15-57", HYUNDAI.KIA_K8_HEV_1ST_GEN),
CarTestRoute("50c6c9b85fd1ff03/2020-10-26--17-56-06", HYUNDAI.KIA_NIRO_EV),
@@ -210,6 +231,7 @@ routes = [
CarTestRoute("82e9cdd3f43bf83e/2021-05-15--02-42-51", HYUNDAI.HYUNDAI_ELANTRA_2021),
CarTestRoute("715ac05b594e9c59/2021-06-20--16-21-07", HYUNDAI.HYUNDAI_ELANTRA_HEV_2021),
CarTestRoute("7120aa90bbc3add7/2021-08-02--07-12-31", HYUNDAI.HYUNDAI_SONATA_HYBRID),
CarTestRoute("bc40c72b728178f2/00000006--ee76ae8c42", HYUNDAI.HYUNDAI_SONATA_HEV_2024),
CarTestRoute("715ac05b594e9c59/2021-10-27--23-24-56", HYUNDAI.GENESIS_G70_2020),
CarTestRoute("6b0d44d22df18134/2023-05-06--10-36-55", HYUNDAI.GENESIS_GV80),
@@ -64,13 +64,25 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"VOLKSWAGEN_PASSAT_NMS" = [2.5, 2.5, 0.1]
"VOLKSWAGEN_SHARAN_MK2" = [2.5, 2.5, 0.1]
"HYUNDAI_SANTA_CRUZ_1ST_GEN" = [2.7, 2.7, 0.1]
"HYUNDAI_SANTA_CRUZ_2025" = [2.5, 2.5, 0.1]
"HYUNDAI_SANTA_FE_HEV_5TH_GEN" = [nan, 2.5, nan]
"HYUNDAI_SONATA_2024" = [2.5, 2.5, 0.1]
"HYUNDAI_SONATA_HEV_2024" = [2.5, 2.5, 0.1]
"HYUNDAI_KONA_2ND_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_KONA_HEV_2ND_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_TUCSON_2025" = [2.5, 2.5, 0.1]
"HYUNDAI_TUCSON_HEV_2025" = [2.5, 2.5, 0.1]
"HYUNDAI_TUCSON_PHEV_2025" = [2.5, 2.5, 0.1]
"KIA_SPORTAGE_5TH_GEN" = [2.6, 2.6, 0.1]
"KIA_SPORTAGE_2026" = [nan, 2.5, nan]
"KIA_SPORTAGE_HEV_2026" = [nan, 2.5, nan]
"GENESIS_GV70_1ST_GEN" = [2.42, 2.42, 0.1]
"GENESIS_GV60_EV_1ST_GEN" = [2.5, 2.5, 0.1]
"GMC_YUKON" = [1.2, 2.5, 0.26]
"KIA_SORENTO_4TH_GEN" = [2.5, 2.5, 0.1]
"KIA_SORENTO_2024" = [2.5, 2.5, 0.1]
"KIA_SORENTO_HEV_4TH_GEN" = [2.5, 2.5, 0.1]
"KIA_SORENTO_HEV_4TH_GEN_LFA2" = [nan, 2.5, nan]
"KIA_NIRO_HEV_2ND_GEN" = [2.42, 2.5, 0.12]
"KIA_NIRO_EV_2ND_GEN" = [2.05, 2.5, 0.14]
"GENESIS_GV80" = [2.5, 2.5, 0.1]
@@ -78,15 +90,24 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"GMC_ACADIA" = [1.6, 1.6, 0.2]
"LEXUS_IS_TSS2" = [2.0, 2.0, 0.1]
"HYUNDAI_KONA_EV_2ND_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_IONIQ_5_PE" = [nan, 2.5, nan]
"HYUNDAI_IONIQ_5_N" = [2.5, 2.5, 0.1]
"HYUNDAI_IONIQ_6" = [3.0, 3.0, 0.09]
"HYUNDAI_IONIQ_9" = [nan, 2.5, nan]
"HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1]
"HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1]
"KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1]
"KIA_K4_2025" = [2.5, 2.5, 0.1]
"KIA_K5_2025" = [2.5, 2.5, 0.1]
"KIA_EV6_2025" = [nan, 2.5, nan]
"KIA_EV9" = [nan, 2.5, nan]
"HYUNDAI_CUSTIN_1ST_GEN" = [2.5, 2.5, 0.1]
"LEXUS_GS_F" = [2.5, 2.5, 0.08]
"HYUNDAI_STARIA_4TH_GEN" = [1.8, 2.0, 0.15]
"GENESIS_GV70_ELECTRIFIED_1ST_GEN" = [1.9, 1.9, 0.09]
"GENESIS_GV70_ELECTRIFIED_2ND_GEN" = [nan, 2.5, nan]
"GENESIS_G80_2ND_GEN_FL" = [2.5819356441497803, 2.5, 0.11244568973779678]
"GENESIS_GV80_2025" = [nan, 2.5, nan]
# Note that some Rivians achieve significantly less lateral acceleration than this
"RIVIAN_R1_GEN1" = [2.8, 2.5, 0.07]
"HYUNDAI_NEXO_1ST_GEN" = [2.5, 2.5, 0.1]
@@ -109,10 +109,12 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"SUBARU_ASCENT" = "SUBARU_FORESTER"
"CADILLAC_CT6_CC" = "CHEVROLET_VOLT"
"CADILLAC_XT5" = "GMC_ACADIA"
"CADILLAC_XT5_CC" = "GMC_ACADIA"
"BUICK_BABYENCLAVE" = "GMC_ACADIA"
"CHEVROLET_EQUINOX_CC" = "CHEVROLET_EQUINOX"
"GMC_YUKON_CC" = "CHEVROLET_SILVERADO"
"CHEVROLET_TRAILBLAZER_CC" = "CHEVROLET_TRAILBLAZER"
"CHEVROLET_SILVERADO_CC" = "CHEVROLET_SILVERADO"
"CHEVROLET_TRAX" = "CHEVROLET_VOLT"
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
import os
if __name__ == "__main__":
dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
hyundai_path = os.path.dirname(os.path.realpath(__file__))
with open(os.path.join(hyundai_path, dbc_name), "w", encoding="utf-8") as f:
f.write("""
VERSION ""
NS_ :
NS_DESC_
CM_
BA_DEF_
BA_
VAL_
CAT_DEF_
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_
ENVVAR_DATA_
SGTYPE_
SGTYPE_VAL_
BA_DEF_SGTYPE_
BA_SGTYPE_
SIG_TYPE_REF_
VAL_TABLE_
SIG_GROUP_
SIG_VALTYPE_
SIGTYPE_VALTYPE_
BO_TX_BU_
BA_DEF_REL_
BA_REL_
BA_DEF_DEF_REL_
BU_SG_REL_
BU_EV_REL_
BU_BO_REL_
SG_MUL_VAL_
BS_:
BU_: XXX
""")
for a in range(0x210, 0x210 + 16):
f.write(f"""
BO_ {a} RADAR_TRACK_{a:x}: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
""")
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
import os
if __name__ == "__main__":
dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
hyundai_path = os.path.dirname(os.path.realpath(__file__))
with open(os.path.join(hyundai_path, dbc_name), "w", encoding="utf-8") as f:
f.write("""
VERSION ""
NS_ :
NS_DESC_
CM_
BA_DEF_
BA_
VAL_
CAT_DEF_
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_
ENVVAR_DATA_
SGTYPE_
SGTYPE_VAL_
BA_DEF_SGTYPE_
BA_SGTYPE_
SIG_TYPE_REF_
VAL_TABLE_
SIG_GROUP_
SIG_VALTYPE_
SIGTYPE_VALTYPE_
BO_TX_BU_
BA_DEF_REL_
BA_REL_
BA_DEF_DEF_REL_
BU_SG_REL_
BU_EV_REL_
BU_BO_REL_
SG_MUL_VAL_
BS_:
BU_: XXX
""")
for a in range(0x3A5, 0x3A5 + 32):
f.write(f"""
BO_ {a} RADAR_TRACK_{a:x}: 24 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_1 : 25|2@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_3 : 28|2@0+ (1,0) [0|3] "" XXX
SG_ COUNTER_3 : 31|2@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_2 : 38|7@0- (1,0) [0|127] "" XXX
SG_ COUNTER_256 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_6 : 51|4@0+ (1,0) [0|15] "" XXX
SG_ STATE : 54|3@0+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_8 : 62|7@0- (1,0) [0|127] "" XXX
SG_ LONG_DIST : 63|12@1+ (0.05,0) [0|8191] "m" XXX
SG_ LAT_DIST : 76|12@1- (0.05,0) [0|127] "" XXX
SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ NEW_SIGNAL_4 : 103|2@0+ (1,0) [0|3] "" XXX
SG_ LAT_DIST_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ REL_ACCEL : 118|10@1- (0.02,0) [0|1023] "" XXX
SG_ NEW_SIGNAL_18 : 129|2@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_5 : 133|4@0+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_10 : 138|5@1+ (1,0) [0|31] "" XXX
SG_ NEW_SIGNAL_11 : 149|6@0+ (1,0) [0|63] "" XXX
SG_ NEW_SIGNAL_7 : 152|10@1+ (1,0) [0|1023] "" XXX
SG_ NEW_SIGNAL_9 : 162|9@1- (1,0) [0|511] "" XXX
SG_ NEW_SIGNAL_13 : 175|4@0+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_12 : 179|4@0+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_14 : 181|2@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_15 : 183|2@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_16 : 185|2@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_17 : 187|2@0+ (1,0) [0|3] "" XXX
""")
@@ -0,0 +1,424 @@
CM_ "AUTOGENERATED FILE, DO NOT EDIT";
CM_ "hyundai_mrr30_radar.dbc starts here";
VERSION ""
NS_ :
NS_DESC_
CM_
BA_DEF_
BA_
VAL_
CAT_DEF_
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_
ENVVAR_DATA_
SGTYPE_
SGTYPE_VAL_
BA_DEF_SGTYPE_
BA_SGTYPE_
SIG_TYPE_REF_
VAL_TABLE_
SIG_GROUP_
SIG_VALTYPE_
SIGTYPE_VALTYPE_
BO_TX_BU_
BA_DEF_REL_
BA_REL_
BA_DEF_DEF_REL_
BU_SG_REL_
BU_EV_REL_
BU_BO_REL_
SG_MUL_VAL_
BS_:
BU_: XXX
BO_ 528 RADAR_TRACK_210: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 529 RADAR_TRACK_211: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 530 RADAR_TRACK_212: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 531 RADAR_TRACK_213: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 532 RADAR_TRACK_214: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 533 RADAR_TRACK_215: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 534 RADAR_TRACK_216: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 535 RADAR_TRACK_217: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 536 RADAR_TRACK_218: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 537 RADAR_TRACK_219: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 538 RADAR_TRACK_21a: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 539 RADAR_TRACK_21b: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 540 RADAR_TRACK_21c: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 541 RADAR_TRACK_21d: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 542 RADAR_TRACK_21e: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
BO_ 543 RADAR_TRACK_21f: 32 RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ 1_COUNTER_255 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ 1_STATE_ALT : 51|4@0+ (1,0) [0|15] "" XXX
SG_ 1_STATE : 55|4@0+ (1,0) [0|15] "" XXX
SG_ 1_NEW_SIGNAL_3 : 63|8@0- (1,0) [0|255] "" XXX
SG_ 1_LONG_DIST : 64|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 1_LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
SG_ 1_REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
SG_ 1_NEW_SIGNAL_1 : 102|2@1+ (1,0) [0|3] "" XXX
SG_ 1_LAT_ACCEL : 104|13@1- (1,0) [0|8191] "" XXX
SG_ 1_REL_ACCEL : 118|10@1- (1,0) [0|1023] "" XXX
SG_ 2_COUNTER_255 : 175|8@0+ (1,0) [0|255] "" XXX
SG_ 2_STATE_ALT : 179|4@0+ (1,0) [0|15] "" XXX
SG_ 2_STATE : 183|4@0+ (1,0) [0|15] "" XXX
SG_ 2_NEW_SIGNAL_3 : 191|8@0- (1,0) [0|255] "" XXX
SG_ 2_LONG_DIST : 192|12@1+ (0.05,0) [0|4095] "" XXX
SG_ 2_LAT_DIST : 204|12@1- (0.05,0) [0|4095] "" XXX
SG_ 2_REL_SPEED : 216|14@1- (0.01,0) [0|65535] "" XXX
SG_ 2_NEW_SIGNAL_1 : 230|2@1+ (1,0) [0|3] "" XXX
SG_ 2_LAT_ACCEL : 232|13@1- (1,0) [0|8191] "" XXX
SG_ 2_REL_ACCEL : 246|10@1- (1,0) [0|1023] "" XXX
File diff suppressed because it is too large Load Diff
@@ -24,6 +24,9 @@
#define HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(e_can, longitudinal) \
{0x1A0, e_can, 32, .check_relay = (longitudinal)}, /* SCC_CONTROL */ \
#define HYUNDAI_CANFD_MRR35_RADAR_TRACK_START 0x3A5
#define HYUNDAI_CANFD_MRR35_RADAR_TRACK_END 0x3C4
#define HYUNDAI_CANFD_BLINDSPOT_DASH_TX_MSGS(e_can) \
{0x1BA, e_can, 24, .check_relay = false}, /* BLINDSPOTS_REAR_CORNERS */ \
{0x1E5, e_can, 16, .check_relay = false}, /* BLINDSPOTS_FRONT_CORNER_1 */ \
@@ -56,6 +59,7 @@
static bool hyundai_canfd_alt_buttons = false;
static bool hyundai_canfd_lka_steering_alt = false;
static bool hyundai_canfd_angle_steering = false;
static bool hyundai_ccnc = false;
static unsigned int hyundai_canfd_get_lka_addr(void) {
return hyundai_canfd_lka_steering_alt ? 0x110U : 0x50U;
@@ -80,6 +84,15 @@ static void hyundai_canfd_rx_all_hook(const CANPacket_t *msg) {
SAFETY_UNUSED(msg);
}
static bool hyundai_canfd_fwd_hook(int bus_num, int addr) {
const bool mrr35_radar_track = (addr >= HYUNDAI_CANFD_MRR35_RADAR_TRACK_START) && (addr <= HYUNDAI_CANFD_MRR35_RADAR_TRACK_END);
// On LKA-steering long-control cars using live MRR35 radar tracks, openpilot parses
// the tracks directly from bus 0. Forwarding them to bus 2 creates a returned TX copy
// of every object frame on the logged CAN stream without adding planner data.
return hyundai_longitudinal && hyundai_canfd_lka_steering && (bus_num == 0) && mrr35_radar_track;
}
static void hyundai_canfd_rx_hook(const CANPacket_t *msg) {
const unsigned pt_bus = hyundai_canfd_lka_steering ? 1U : 0U;
@@ -289,6 +302,7 @@ static safety_config hyundai_canfd_init(uint16_t param) {
const uint16_t HYUNDAI_PARAM_CANFD_LKA_STEERING_ALT = 128;
const uint16_t HYUNDAI_PARAM_CANFD_ALT_BUTTONS = 32;
const uint16_t HYUNDAI_PARAM_CANFD_ANGLE_STEERING = 1024;
const uint16_t HYUNDAI_PARAM_CCNC = 32768U;
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
@@ -304,6 +318,7 @@ static safety_config hyundai_canfd_init(uint16_t param) {
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(1, true)
HYUNDAI_CANFD_BLINDSPOT_DASH_TX_MSGS(1)
{0x51, 0, 32, .check_relay = false}, // ADRV_0x51
{0x100, 0, 24, .check_relay = false}, // Ioniq 5/6: ACCELERATOR_BRAKE_ALT radar heartbeat spoof
{0x730, 1, 8, .check_relay = false}, // tester present for ADAS ECU disable
{0x160, 1, 16, .check_relay = false}, // ADRV_0x160
{0x1EA, 1, 32, .check_relay = false}, // ADRV_0x1ea
@@ -335,12 +350,22 @@ static safety_config hyundai_canfd_init(uint16_t param) {
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, (longitudinal)) \
{0x160, 0, 16, .check_relay = (longitudinal)}, /* ADRV_0x160 */ \
#define HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_CCNC_TX_MSGS(longitudinal) \
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2) \
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0) \
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, (longitudinal)) \
{0x161, 0, 32, .check_relay = true}, /* CCNC_0x161 */ \
{0x162, 0, 32, .check_relay = true}, /* CCNC_0x162 */ \
{0x7C4, 2, 8, .check_relay = true}, /* camera support frame */ \
{0xEA, 2, 24, .check_relay = true}, /* MDPS support frame */ \
hyundai_common_init(param);
gen_crc_lookup_table_16(0x1021, hyundai_canfd_crc_lut);
hyundai_canfd_alt_buttons = GET_FLAG(param, HYUNDAI_PARAM_CANFD_ALT_BUTTONS);
hyundai_canfd_lka_steering_alt = GET_FLAG(param, HYUNDAI_PARAM_CANFD_LKA_STEERING_ALT);
hyundai_canfd_angle_steering = GET_FLAG(param, HYUNDAI_PARAM_CANFD_ANGLE_STEERING);
hyundai_ccnc = GET_FLAG(param, HYUNDAI_PARAM_CCNC);
safety_config ret;
if (hyundai_longitudinal) {
@@ -367,6 +392,10 @@ static safety_config hyundai_canfd_init(uint16_t param) {
HYUNDAI_CANFD_BLINDSPOT_DASH_TX_MSGS(0)
};
static CanMsg hyundai_canfd_lfa_steering_camera_scc_ccnc_tx_msgs[] = {
HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_CCNC_TX_MSGS(true)
};
if (hyundai_canfd_alt_buttons) {
SET_RX_CHECKS(hyundai_canfd_alt_buttons_long_rx_checks, ret);
} else {
@@ -374,7 +403,11 @@ static safety_config hyundai_canfd_init(uint16_t param) {
}
if (hyundai_camera_scc) {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
if (hyundai_ccnc) {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_ccnc_tx_msgs, ret);
} else {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
}
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LFA_STEERING_LONG_TX_MSGS, ret);
}
@@ -435,7 +468,15 @@ static safety_config hyundai_canfd_init(uint16_t param) {
HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_TX_MSGS(false)
};
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
static CanMsg hyundai_canfd_lfa_steering_camera_scc_ccnc_tx_msgs[] = {
HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_CCNC_TX_MSGS(false)
};
if (hyundai_ccnc) {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_ccnc_tx_msgs, ret);
} else {
SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
}
if (hyundai_canfd_alt_buttons) {
SET_RX_CHECKS(hyundai_canfd_alt_buttons_rx_checks, ret);
@@ -456,4 +497,5 @@ const safety_hooks hyundai_canfd_hooks = {
.get_counter = hyundai_canfd_get_counter,
.get_checksum = hyundai_canfd_get_checksum,
.compute_checksum = hyundai_common_canfd_compute_checksum,
.fwd = hyundai_canfd_fwd_hook,
};
@@ -26,6 +26,8 @@ ALL_GAS_EV_HYBRID_COMBOS = [
{"GAS_MSG": ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL"), "SCC_BUS": 2, "SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS | HyundaiSafetyFlags.CAMERA_SCC},
]
MRR35_RADAR_TRACK_ADDRS = list(range(0x3A5, 0x3C5))
def _set_value(msg: bytearray, sig, ival: int) -> None:
i = sig.lsb // 8
@@ -422,6 +424,37 @@ class TestHyundaiCanfdLFASteeringAltButtons(TestHyundaiCanfdLFASteeringAltButton
pass
class TestHyundaiCanfdCCNCSupportFrames(common.SafetyTestBase):
TX_MSGS = [[0x161, 0], [0x162, 0], [0x7C4, 2], [0xEA, 2]]
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
def _set_hooks(self, param):
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, param)
self.safety.init_tests()
def test_ccnc_support_frames_require_ccnc_flag(self):
support_msgs = (
self.packer.make_can_msg_safety("CCNC_0x161", 0, {}),
self.packer.make_can_msg_safety("CCNC_0x162", 0, {}),
common.make_msg(2, 0x7C4, 8),
common.make_msg(2, 0xEA, 24),
)
for longitudinal in (False, True):
base_param = HyundaiSafetyFlags.CAMERA_SCC | (HyundaiSafetyFlags.LONG if longitudinal else 0)
self._set_hooks(base_param)
for msg in support_msgs:
self.assertFalse(self._tx(msg))
self._set_hooks(base_param | HyundaiSafetyFlags.CCNC)
for msg in support_msgs:
self.assertTrue(self._tx(msg))
class TestHyundaiCanfdLKASteeringEV(TestHyundaiCanfdBase):
TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]]
@@ -485,6 +518,7 @@ class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanf
[0x1a0, 1], [0x1ea, 1], [0x200, 1], [0x345, 1], [0x1da, 1]]
RELAY_MALFUNCTION_ADDRS = {0: (0x50, 0x2a4), 1: (0x1a0,)} # LKAS, CAM_0x2A4, SCC_CONTROL
FWD_BLACKLISTED_ADDRS = {0: MRR35_RADAR_TRACK_ADDRS, 2: [0x50, 0x2a4]}
DISABLED_ECU_UDS_MSG = (0x730, 1)
DISABLED_ECU_ACTUATION_MSG = (0x1a0, 1)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,2 +1,2 @@
extern const uint8_t gitversion[19];
const uint8_t gitversion[19] = "DEV-da88d20b-DEBUG";
const uint8_t gitversion[19] = "DEV-b12fdf18-DEBUG";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
DEV-da88d20b-DEBUG
DEV-b12fdf18-DEBUG
+105 -4
View File
@@ -27,18 +27,20 @@ env_var_truthy() {
usage() {
cat <<'EOF'
Usage:
./onroad [jobs] (--c3 | --c4 | --raybig | --all | --replay-only) [--prefix name] <route-or-replay-args...>
./onroad [jobs] (--c3 | --c4 | --raybig | --all | --replay-only) [-nav] [--prefix name] <route-or-replay-args...>
Examples:
./onroad --c3 f08912a233c1584f/2022-08-11--18-02-41/1
./onroad --c4 f08912a233c1584f/2022-08-11--18-02-41/1 --start 30
./onroad --all f08912a233c1584f/2022-08-11--18-02-41/1
./onroad --c3 <route>
./onroad --c4 <route> --start 30
./onroad --c4 -nav <route>
./onroad --all <route>
./onroad --replay-only --demo --no-vipc --no-loop
Notes:
- This is host/dev only. It uses the isolated host worktree and does not touch the device path.
- A private comma connect route still requires tools/lib/auth.py before replay can download it.
- Use multiple UI flags together if you want more than one desktop UI at once.
- -nav injects a fake navigation demo stream and blocks replay from publishing navInstruction/navRoute.
EOF
}
@@ -53,7 +55,9 @@ REPLAY_ARGS=()
UI_TARGETS=()
LEGACY_UI_SELECTION=""
REPLAY_ONLY=0
NAV_DEMO=0
REPLAY_PID=""
NAV_PID=""
UI_PIDS=()
parse_args() {
@@ -83,6 +87,10 @@ parse_args() {
REPLAY_ONLY=1
shift
;;
-nav|--nav)
NAV_DEMO=1
shift
;;
--ui)
if [[ $# -lt 2 ]]; then
echo "Missing value for --ui" >&2
@@ -194,6 +202,9 @@ cleanup() {
if [[ -n "${REPLAY_PID}" ]]; then
kill "${REPLAY_PID}" >/dev/null 2>&1 || true
fi
if [[ -n "${NAV_PID}" ]]; then
kill "${NAV_PID}" >/dev/null 2>&1 || true
fi
for pid in "${UI_PIDS[@]-}"; do
if [[ -n "${pid}" ]]; then
@@ -203,6 +214,9 @@ cleanup() {
if [[ -n "${REPLAY_PID}" ]]; then
wait "${REPLAY_PID}" >/dev/null 2>&1 || true
fi
if [[ -n "${NAV_PID}" ]]; then
wait "${NAV_PID}" >/dev/null 2>&1 || true
fi
if [[ -n "${OPENPILOT_PREFIX:-}" && "${OPENPILOT_PREFIX}" == desktop-onroad-* ]]; then
echo "Cleaning up temporary prefix environment (${OPENPILOT_PREFIX})..."
@@ -214,6 +228,68 @@ cleanup() {
exit "${exit_code}"
}
append_blocked_service_names() {
local existing="$1"
local required="$2"
local combined="${existing}"
if [[ -n "${combined}" ]]; then
combined+=",${required}"
else
combined="${required}"
fi
local deduped=()
local seen=","
local part=""
local parts=()
IFS=',' read -r -a parts <<< "${combined}"
for part in "${parts[@]-}"; do
part="${part// /}"
if [[ -z "${part}" ]]; then
continue
fi
if [[ "${seen}" != *",${part},"* ]]; then
deduped+=("${part}")
seen+="${part},"
fi
done
local joined=""
for part in "${deduped[@]-}"; do
if [[ -n "${joined}" ]]; then
joined+=","
fi
joined+="${part}"
done
printf '%s' "${joined}"
}
ensure_nav_demo_replay_blocklist() {
local nav_services="navInstruction,navRoute"
local idx=0
for ((idx=0; idx<${#REPLAY_ARGS[@]}; idx++)); do
case "${REPLAY_ARGS[$idx]}" in
-b|--block)
if (( idx + 1 >= ${#REPLAY_ARGS[@]} )); then
echo "Missing value for ${REPLAY_ARGS[$idx]}" >&2
exit 1
fi
REPLAY_ARGS[$((idx + 1))]="$(append_blocked_service_names "${REPLAY_ARGS[$((idx + 1))]}" "${nav_services}")"
return
;;
--block=*)
REPLAY_ARGS[$idx]="--block=$(append_blocked_service_names "${REPLAY_ARGS[$idx]#*=}" "${nav_services}")"
return
;;
esac
done
REPLAY_ARGS=(-b "${nav_services}" "${REPLAY_ARGS[@]}")
}
prepare_env() {
source .venv/bin/activate
@@ -238,6 +314,7 @@ prepare_env() {
export SP_C4_FAKE_WIFI=0
export SP_RAYBIG_FAKE_WIFI=0
export SP_ALLOW_DESKTOP_FAKE_WIFI=0
export SP_ONROAD_NAV_DEMO="${NAV_DEMO}"
if [[ "$(uname -s)" == "Darwin" ]] || env_var_truthy "${ZMQ:-0}"; then
export OPENPILOT_ZMQ_NAMESPACE="${PREFIX_ARG:-${OPENPILOT_ZMQ_NAMESPACE:-desktop-onroad-$$}}"
@@ -250,6 +327,8 @@ prepare_env() {
seed_params() {
"${ROOT_DIR}/.venv/bin/python3" - <<'PY'
import os
from openpilot.common.params import Params
from openpilot.system.version import terms_version, training_version
@@ -260,6 +339,8 @@ params.put_bool("OpenpilotEnabledToggle", True)
params.put_bool("IsDriverViewEnabled", False)
params.put_bool("ForceOnroad", False)
params.put_bool("ForceOffroad", False)
if os.getenv("SP_ONROAD_NAV_DEMO", "").lower() in {"1", "true", "yes", "on"}:
params.put_bool("NavigationUI", True)
PY
}
@@ -302,6 +383,18 @@ launch_replay() {
fi
}
launch_nav_demo() {
echo "Starting fake nav demo publisher..."
"${ROOT_DIR}/.venv/bin/python3" "${ROOT_DIR}/tools/replay/fake_nav_demo.py" &
NAV_PID=$!
sleep 0.5
if ! kill -0 "${NAV_PID}" >/dev/null 2>&1; then
wait "${NAV_PID}"
return 1
fi
}
launch_c3_ui() {
local os_ext="linux"
if [[ "$(uname -s)" == "Darwin" ]]; then
@@ -339,6 +432,10 @@ else
dedupe_ui_targets
fi
if [[ "${NAV_DEMO}" == "1" ]]; then
ensure_nav_demo_replay_blocklist
fi
if [[ ${#REPLAY_ARGS[@]} -eq 0 ]]; then
usage >&2
exit 1
@@ -378,6 +475,10 @@ seed_starpilot_theme
echo "Starting replay: ${REPLAY_ARGS[*]}"
launch_replay
if [[ "${NAV_DEMO}" == "1" ]]; then
launch_nav_demo
fi
if [[ ${#UI_TARGETS[@]} -eq 0 ]]; then
echo "Replay is running without UI windows. Press Ctrl-C to stop."
wait "${REPLAY_PID}"
+145 -22
View File
@@ -3,6 +3,7 @@ import argparse
import codecs
import os
import pickle
import json
import re
import shutil
import subprocess
@@ -10,11 +11,18 @@ import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))
from openpilot.selfdrive.modeld.constants import ModelConstants
from openpilot.starpilot.common.model_versions import uses_combined_driving_artifacts
DEFAULT_INPUT_ROOT = Path("/data/openpilot/uncompiledmodels")
DEFAULT_OUTPUT_ROOT = Path("/data/openpilot/compiledmodels")
COMPILE_SCRIPT = REPO_ROOT / "tinygrad_repo/examples/openpilot/compile3.py"
COMBINED_COMPILE_SCRIPT = REPO_ROOT / "selfdrive/modeld/compile_modeld.py"
MODEL_VERSIONS_CACHE = Path("/data/models/.model_versions.json")
DM_MODEL_KEY = "dm"
DM_MODEL_NAME = "dmonitoring_model"
DM_TARGET_ALIASES = {DM_MODEL_KEY, "dmonitoring", DM_MODEL_NAME}
@@ -26,7 +34,33 @@ COMPONENT_ALIASES = {
"driving_policy": ("driving_policy", "policy"),
"driving_vision": ("driving_vision", "vision"),
}
REQUIRED_COMPONENTS = {"driving_policy", "driving_vision"}
MEDMODEL_INPUT_SIZE = (512, 256)
DEFAULT_CAMERA_RESOLUTIONS = (
(1928, 1208),
(1344, 760),
)
def build_compile_env(*, combined: bool = False) -> dict[str, str]:
env = os.environ.copy()
existing_pythonpath = env.get("PYTHONPATH", "")
env["PYTHONPATH"] = f"{REPO_ROOT}:{existing_pythonpath}" if existing_pythonpath else str(REPO_ROOT)
numeric_defaults = {
"DEBUG": "0",
"FLOAT16": "1",
"IMAGE": "2",
"JIT_BATCH_SIZE": "0",
"NOLOCALS": "1",
}
for key, default in numeric_defaults.items():
value = env.get(key)
try:
int(str(value), 0)
except (TypeError, ValueError):
env[key] = default
return env
def parse_args() -> argparse.Namespace:
@@ -37,6 +71,7 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("--dm", action="store_true", help="Compile the driver monitoring model into dmonitoring_model_tinygrad.pkl.")
parser.add_argument("--input-dir", type=Path, default=DEFAULT_INPUT_ROOT, help="Directory containing staged ONNX files. Flat root files like driving_policy.onnx are preferred.")
parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT_ROOT, help="Directory for compiled tinygrad pkls and metadata.")
parser.add_argument("--version", help="Model version. v16+ uses the combined driving_tinygrad artifact path. If omitted, split-policy staged models default to the combined build.")
parser.add_argument("--list", action="store_true", help="List detected staged models and exit.")
parser.add_argument("--force", action="store_true", help="Legacy no-op. Compiled outputs are always cleared before a build.")
@@ -66,14 +101,6 @@ def detect_component(path: Path) -> str | None:
return None
def normalize_model_files(model_files: dict[str, Path]) -> dict[str, Path]:
normalized = dict(model_files)
on_policy_path = normalized.pop("driving_on_policy", None)
if on_policy_path is not None and "driving_policy" not in normalized and "driving_off_policy" in normalized:
normalized["driving_policy"] = on_policy_path
return normalized
def find_staged_dm(input_root: Path) -> Path | None:
if not input_root.is_dir():
return None
@@ -107,7 +134,6 @@ def find_staged_models(input_root: Path) -> dict[str, dict[str, Path]]:
component = detect_component(onnx_file)
if component:
model_files[component] = onnx_file
model_files = normalize_model_files(model_files)
if model_files:
found[child.name] = model_files
@@ -137,7 +163,7 @@ def find_staged_models(input_root: Path) -> dict[str, dict[str, Path]]:
flat_root_files[component] = onnx_file
if flat_root_files:
found["_root"] = normalize_model_files(flat_root_files)
found["_root"] = flat_root_files
return found
@@ -156,7 +182,7 @@ def resolve_model_files(input_root: Path, model_key: str) -> dict[str, Path]:
component = detect_component(onnx_file)
if component:
prefixed_files[component] = onnx_file
return normalize_model_files(prefixed_files)
return prefixed_files
def get_metadata_value_by_name(model, name: str):
@@ -190,17 +216,94 @@ def write_metadata(onnx_path: Path, output_path: Path) -> None:
def compile_component(onnx_path: Path, output_path: Path) -> None:
env = os.environ.copy()
existing_pythonpath = env.get("PYTHONPATH", "")
env["PYTHONPATH"] = f"{REPO_ROOT}:{existing_pythonpath}" if existing_pythonpath else str(REPO_ROOT)
subprocess.run(
[sys.executable, str(COMPILE_SCRIPT), str(onnx_path), str(output_path)],
cwd=REPO_ROOT,
env=env,
env=build_compile_env(combined=False),
check=True,
)
def compile_combined_model(component_paths: dict[str, Path], output_path: Path) -> None:
vision_path = component_paths["driving_vision"]
off_policy_path = component_paths["driving_off_policy"]
on_policy_path = component_paths.get("driving_on_policy") or component_paths.get("driving_policy")
if on_policy_path is None:
raise ValueError("Combined compile requires driving_on_policy.onnx (or driving_policy.onnx) alongside driving_off_policy.onnx")
frame_skip = ModelConstants.MODEL_RUN_FREQ // ModelConstants.MODEL_CONTEXT_FREQ
camera_resolutions = [f"{width}x{height}" for width, height in DEFAULT_CAMERA_RESOLUTIONS]
subprocess.run(
[
sys.executable,
str(COMBINED_COMPILE_SCRIPT),
"--model-size",
f"{MEDMODEL_INPUT_SIZE[0]}x{MEDMODEL_INPUT_SIZE[1]}",
"--camera-resolutions",
*camera_resolutions,
"--vision-onnx",
str(vision_path),
"--off-policy-onnx",
str(off_policy_path),
"--on-policy-onnx",
str(on_policy_path),
"--output",
str(output_path),
"--frame-skip",
str(frame_skip),
],
cwd=REPO_ROOT,
env=build_compile_env(combined=True),
check=True,
)
def infer_model_version(model_key: str, explicit_version: str | None) -> str:
if explicit_version:
return explicit_version.strip()
if MODEL_VERSIONS_CACHE.is_file():
try:
version_map = json.loads(MODEL_VERSIONS_CACHE.read_text())
version = version_map.get(model_key)
if isinstance(version, str) and version.strip():
return version.strip()
except Exception:
pass
return ""
def should_use_combined_artifacts(model_version: str, model_files: dict[str, Path]) -> bool:
if uses_combined_driving_artifacts(model_version):
return True
if model_version.strip():
return False
has_vision = "driving_vision" in model_files
has_off_policy = "driving_off_policy" in model_files
has_on_policy = "driving_on_policy" in model_files or "driving_policy" in model_files
return has_vision and has_off_policy and has_on_policy
def resolve_split_component_inputs(model_files: dict[str, Path]) -> dict[str, Path]:
resolved: dict[str, Path] = {}
vision_path = model_files.get("driving_vision")
if vision_path is not None:
resolved["driving_vision"] = vision_path
policy_path = model_files.get("driving_policy") or model_files.get("driving_on_policy")
if policy_path is not None:
resolved["driving_policy"] = policy_path
off_policy_path = model_files.get("driving_off_policy")
if off_policy_path is not None:
resolved["driving_off_policy"] = off_policy_path
return resolved
def clear_existing_outputs(output_dir: Path) -> list[Path]:
removed = []
for existing in sorted(output_dir.iterdir()):
@@ -277,18 +380,38 @@ def main() -> int:
f"or optionally {args.input_dir / model_key}/*.onnx"
)
missing = sorted(REQUIRED_COMPONENTS - set(files))
if missing:
raise SystemExit(f"Missing required ONNX files for {model_key}: {', '.join(missing)}")
model_version = infer_model_version(model_key, args.version)
use_combined_artifacts = should_use_combined_artifacts(model_version, files)
args.output_dir.mkdir(parents=True, exist_ok=True)
print(f"Compiling {model_key} from {args.input_dir} -> {args.output_dir}")
mode_label = "combined" if use_combined_artifacts else "split"
version_label = model_version or ("auto-combined" if use_combined_artifacts else "legacy-default")
print(f"Compiling {model_key} ({version_label}, {mode_label}) from {args.input_dir} -> {args.output_dir}")
removed = clear_existing_outputs(args.output_dir)
if removed:
print(f" cleared {len(removed)} existing output entries")
for component, onnx_path in sorted(files.items()):
if use_combined_artifacts:
required_components = {"driving_vision", "driving_off_policy"}
if not (files.get("driving_on_policy") or files.get("driving_policy")):
required_components.add("driving_on_policy")
missing = sorted(component for component in required_components if component not in files)
if missing:
raise SystemExit(f"Missing required ONNX files for combined compile of {model_key}: {', '.join(missing)}")
output_pkl = args.output_dir / f"{model_key}_driving_tinygrad.pkl"
compile_combined_model(files, output_pkl)
print(f" saved {output_pkl.name}")
print("Done.")
return 0
split_components = resolve_split_component_inputs(files)
missing = sorted(component for component in ("driving_policy", "driving_vision") if component not in split_components)
if missing:
raise SystemExit(f"Missing required ONNX files for {model_key}: {', '.join(missing)}")
for component, onnx_path in sorted(split_components.items()):
output_pkl = args.output_dir / f"{model_key}_{component}_tinygrad.pkl"
output_metadata = args.output_dir / f"{model_key}_{component}_metadata.pkl"
+102
View File
@@ -1,5 +1,10 @@
import json
import numpy as np
from cereal import log
from openpilot.common.constants import CV
from openpilot.common.params import Params
from openpilot.common.realtime import DT_MDL
LaneChangeState = log.LaneChangeState
@@ -7,6 +12,8 @@ LaneChangeDirection = log.LaneChangeDirection
LANE_CHANGE_SPEED_MIN = 20 * CV.MPH_TO_MS
LANE_CHANGE_TIME_MAX = 10.
NAV_TURN_DISTANCE_SPEED_BREAKPOINTS = [0.0, 5.0, 10.0]
NAV_TURN_DISTANCE_BREAKPOINTS = [20.0, 25.0, 30.0]
DESIRES = {
LaneChangeDirection.none: {
@@ -40,6 +47,8 @@ TURN_DESIRES = {
class DesireHelper:
def __init__(self):
self.params = Params()
self.params_memory = Params(memory=True)
self.lane_change_state = LaneChangeState.off
self.lane_change_direction = LaneChangeDirection.none
self.lane_change_timer = 0.0
@@ -51,6 +60,95 @@ class DesireHelper:
self.lane_change_completed = False
self.lane_change_wait_timer = 0.0
self.nav_desires_allowed = False
self._nav_param_counter = -1
self._nav_instruction_state_raw: object = None
self._nav_instruction_state: dict[str, object] = {}
def _update_nav_params(self):
self._nav_param_counter += 1
if self._nav_param_counter % 60 == 0:
self.nav_desires_allowed = self.params.get_bool("NavDesiresAllowed")
raw = self.params_memory.get("NavInstructionState") or {}
if raw == self._nav_instruction_state_raw:
return
self._nav_instruction_state_raw = raw
if not raw:
self._nav_instruction_state = {}
return
if isinstance(raw, dict):
self._nav_instruction_state = raw
return
if isinstance(raw, str):
try:
parsed = json.loads(raw)
self._nav_instruction_state = parsed if isinstance(parsed, dict) else {}
return
except Exception:
pass
self._nav_instruction_state = {}
@staticmethod
def _nav_keep_direction_is_clear(carstate, lane_change_direction):
return not (
(lane_change_direction == LaneChangeDirection.left and carstate.leftBlindspot) or
(lane_change_direction == LaneChangeDirection.right and carstate.rightBlindspot)
)
@staticmethod
def _nav_torque_applied(carstate, lane_change_direction):
return carstate.steeringPressed and (
(lane_change_direction == LaneChangeDirection.left and carstate.steeringTorque > 0) or
(lane_change_direction == LaneChangeDirection.right and carstate.steeringTorque < 0)
)
@staticmethod
def _nav_turn_is_imminent(carstate, maneuver_distance):
try:
distance = float(maneuver_distance)
except (TypeError, ValueError):
return False
return distance <= float(np.interp(carstate.vEgo, NAV_TURN_DISTANCE_SPEED_BREAKPOINTS, NAV_TURN_DISTANCE_BREAKPOINTS))
def _navigation_desire(self, carstate, lateral_active, starpilotPlan, starpilot_toggles):
self._update_nav_params()
if not self.nav_desires_allowed or not lateral_active or not bool(self._nav_instruction_state.get("valid", False)):
return log.Desire.none
modifier = str(self._nav_instruction_state.get("maneuverModifier", ""))
if modifier == "":
return log.Desire.none
maneuver_distance = self._nav_instruction_state.get("maneuverDistance", 0.0)
if modifier == "slightLeft":
lane_change_direction = LaneChangeDirection.left
desired_lane_width = starpilotPlan.laneWidthLeft
nudgeless_allowed = starpilot_toggles.nudgeless and desired_lane_width >= starpilot_toggles.lane_detection_width
if not carstate.rightBlinker and self._nav_keep_direction_is_clear(carstate, lane_change_direction):
if self._nav_torque_applied(carstate, lane_change_direction) or nudgeless_allowed:
return log.Desire.keepLeft
elif modifier == "slightRight":
lane_change_direction = LaneChangeDirection.right
desired_lane_width = starpilotPlan.laneWidthRight
nudgeless_allowed = starpilot_toggles.nudgeless and desired_lane_width >= starpilot_toggles.lane_detection_width
if not carstate.leftBlinker and self._nav_keep_direction_is_clear(carstate, lane_change_direction):
if self._nav_torque_applied(carstate, lane_change_direction) or nudgeless_allowed:
return log.Desire.keepRight
elif modifier in ("left", "sharpLeft"):
if not carstate.rightBlinker and not carstate.leftBlindspot and carstate.vEgo < starpilot_toggles.minimum_lane_change_speed and not carstate.standstill and self._nav_turn_is_imminent(carstate, maneuver_distance):
return log.Desire.turnLeft
elif modifier in ("right", "sharpRight"):
if not carstate.leftBlinker and not carstate.rightBlindspot and carstate.vEgo < starpilot_toggles.minimum_lane_change_speed and not carstate.standstill and self._nav_turn_is_imminent(carstate, maneuver_distance):
return log.Desire.turnRight
return log.Desire.none
@staticmethod
def get_lane_change_direction(CS):
@@ -155,3 +253,7 @@ class DesireHelper:
self.lane_change_completed = False
self.lane_change_wait_timer = 0.0
nav_desire = self._navigation_desire(carstate, lateral_active, starpilotPlan, starpilot_toggles)
if nav_desire != log.Desire.none and self.lane_change_state == LaneChangeState.off:
self.desire = nav_desire
+62 -34
View File
@@ -244,10 +244,10 @@ VOLT_STANDARD_CENTER_TAPER_LAT_WIDTH = 0.018
VOLT_STANDARD_CENTER_TAPER_SPEED = 20.0
VOLT_STANDARD_CENTER_TAPER_SPEED_WIDTH = 2.5
SONATA_HYBRID_BASE_LAT_ACCEL_FACTOR_MULT = 1.04
SONATA_HYBRID_FF_REDUCTION_LEFT = 0.07
SONATA_HYBRID_FF_REDUCTION_RIGHT = 0.22
SONATA_HYBRID_FF_ONSET = 0.22
SONATA_HYBRID_BASE_LAT_ACCEL_FACTOR_MULT = 1.05
SONATA_HYBRID_FF_REDUCTION_LEFT = 0.09
SONATA_HYBRID_FF_REDUCTION_RIGHT = 0.24
SONATA_HYBRID_FF_ONSET = 0.18
SONATA_HYBRID_FF_ONSET_WIDTH = 0.08
SONATA_HYBRID_FF_CUTOFF = 1.35
SONATA_HYBRID_FF_CUTOFF_WIDTH = 0.40
@@ -257,15 +257,15 @@ SONATA_HYBRID_TURN_IN_BOOST_LEFT = 0.12
SONATA_HYBRID_TURN_IN_BOOST_RIGHT = 0.00
SONATA_HYBRID_UNWIND_TAPER_LEFT = 0.18
SONATA_HYBRID_UNWIND_TAPER_RIGHT = 0.10
SONATA_HYBRID_CENTER_TAPER_MAX = 0.05
SONATA_HYBRID_CENTER_TAPER_LAT = 0.14
SONATA_HYBRID_CENTER_TAPER_MAX = 0.07
SONATA_HYBRID_CENTER_TAPER_LAT = 0.16
SONATA_HYBRID_CENTER_TAPER_LAT_WIDTH = 0.025
SONATA_HYBRID_CENTER_TAPER_SPEED = 22.0
SONATA_HYBRID_CENTER_TAPER_SPEED_WIDTH = 2.5
SONATA_HYBRID_LOW_SPEED_CENTER_TAPER_MAX = 0.12
SONATA_HYBRID_LOW_SPEED_CENTER_TAPER_LAT = 0.09
SONATA_HYBRID_LOW_SPEED_CENTER_TAPER_MAX = 0.14
SONATA_HYBRID_LOW_SPEED_CENTER_TAPER_LAT = 0.10
SONATA_HYBRID_LOW_SPEED_CENTER_TAPER_LAT_WIDTH = 0.02
SONATA_HYBRID_LOW_SPEED_CENTER_TAPER_SPEED_MAX = 6.0
SONATA_HYBRID_LOW_SPEED_CENTER_TAPER_SPEED_MAX = 7.5
SONATA_HYBRID_LOW_SPEED_CENTER_TAPER_SPEED_WIDTH = 1.0
ELANTRA_NON_SCC_FF_ADJUST_LEFT = 0.02
@@ -281,21 +281,21 @@ ELANTRA_NON_SCC_TURN_IN_BOOST_RIGHT = 0.12
ELANTRA_NON_SCC_UNWIND_TAPER_LEFT = 0.22
ELANTRA_NON_SCC_UNWIND_TAPER_RIGHT = 0.12
KIA_FORTE_BASE_LAT_ACCEL_FACTOR_MULT = 1.08
KIA_FORTE_FF_REDUCTION_LEFT = 0.08
KIA_FORTE_FF_REDUCTION_RIGHT = 0.20
KIA_FORTE_BASE_LAT_ACCEL_FACTOR_MULT = 1.10
KIA_FORTE_FF_REDUCTION_LEFT = 0.10
KIA_FORTE_FF_REDUCTION_RIGHT = 0.24
KIA_FORTE_FF_ONSET = 0.16
KIA_FORTE_FF_ONSET_WIDTH = 0.06
KIA_FORTE_FF_CUTOFF = 1.20
KIA_FORTE_FF_CUTOFF_WIDTH = 0.36
KIA_FORTE_TRANSITION_SPEED = 9.0
KIA_FORTE_PHASE_SCALE = 0.10
KIA_FORTE_TURN_IN_BOOST_LEFT = 0.06
KIA_FORTE_TURN_IN_BOOST_LEFT = 0.10
KIA_FORTE_TURN_IN_BOOST_RIGHT = 0.00
KIA_FORTE_UNWIND_TAPER_LEFT = 0.18
KIA_FORTE_UNWIND_TAPER_RIGHT = 0.08
KIA_FORTE_CENTER_TAPER_MAX = 0.11
KIA_FORTE_CENTER_TAPER_LAT = 0.14
KIA_FORTE_UNWIND_TAPER_LEFT = 0.26
KIA_FORTE_UNWIND_TAPER_RIGHT = 0.04
KIA_FORTE_CENTER_TAPER_MAX = 0.14
KIA_FORTE_CENTER_TAPER_LAT = 0.16
KIA_FORTE_CENTER_TAPER_LAT_WIDTH = 0.03
KIA_FORTE_CENTER_TAPER_SPEED = 24.0
KIA_FORTE_CENTER_TAPER_SPEED_WIDTH = 2.5
@@ -325,27 +325,32 @@ GENESIS_G90_TURN_IN_FRICTION_BOOST_RIGHT = 0.14
GENESIS_G90_UNWIND_FRICTION_REDUCTION_LEFT = 0.04
GENESIS_G90_UNWIND_FRICTION_REDUCTION_RIGHT = 0.30
IONIQ_5_BASE_LAT_ACCEL_FACTOR_MULT = 1.18
IONIQ_5_BASE_LAT_ACCEL_FACTOR_MULT = 1.22
IONIQ_5_FF_ONSET = 0.10
IONIQ_5_FF_ONSET_WIDTH = 0.05
IONIQ_5_FF_CUTOFF = 1.20
IONIQ_5_FF_CUTOFF_WIDTH = 0.30
IONIQ_5_TRANSITION_SPEED = 11.0
IONIQ_5_PHASE_SCALE = 0.10
IONIQ_5_FF_REDUCTION_LEFT = 0.10
IONIQ_5_FF_REDUCTION_LEFT = 0.14
IONIQ_5_FF_REDUCTION_RIGHT = 0.18
IONIQ_5_TURN_IN_BOOST_LEFT = 0.04
IONIQ_5_TURN_IN_BOOST_RIGHT = 0.00
IONIQ_5_UNWIND_TAPER_LEFT = 0.40
IONIQ_5_UNWIND_TAPER_RIGHT = 0.70
IONIQ_5_UNWIND_TAPER_LEFT = 0.52
IONIQ_5_UNWIND_TAPER_RIGHT = 0.82
IONIQ_5_TURN_IN_THRESHOLD_REDUCTION_LEFT = 0.05
IONIQ_5_TURN_IN_THRESHOLD_REDUCTION_RIGHT = 0.00
IONIQ_5_UNWIND_THRESHOLD_INCREASE_LEFT = 0.18
IONIQ_5_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.32
IONIQ_5_UNWIND_THRESHOLD_INCREASE_LEFT = 0.24
IONIQ_5_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.38
IONIQ_5_TURN_IN_FRICTION_BOOST_LEFT = 0.02
IONIQ_5_TURN_IN_FRICTION_BOOST_RIGHT = 0.00
IONIQ_5_UNWIND_FRICTION_REDUCTION_LEFT = 0.15
IONIQ_5_UNWIND_FRICTION_REDUCTION_RIGHT = 0.26
IONIQ_5_UNWIND_FRICTION_REDUCTION_LEFT = 0.22
IONIQ_5_UNWIND_FRICTION_REDUCTION_RIGHT = 0.32
IONIQ_5_CENTER_TAPER_MAX = 0.08
IONIQ_5_CENTER_TAPER_LAT = 0.16
IONIQ_5_CENTER_TAPER_LAT_WIDTH = 0.03
IONIQ_5_CENTER_TAPER_SPEED = 20.0
IONIQ_5_CENTER_TAPER_SPEED_WIDTH = 2.5
IONIQ_EV_OLD_BASE_LAT_ACCEL_FACTOR_MULT = 1.16
IONIQ_EV_OLD_FF_REDUCTION_LEFT = 0.16
@@ -439,7 +444,7 @@ IONIQ_6_OUTPUT_DIRECTIONAL_TAPER_BLEND = 0.97
KIA_EV6_LATERAL_TESTING_GROUND_ID = testing_ground.id_6
KIA_EV6_LATERAL_TESTING_GROUND_VARIANT = "C"
KIA_EV6_FF_GAIN_LEFT = 0.07
KIA_EV6_FF_GAIN_RIGHT = 0.10
KIA_EV6_FF_GAIN_RIGHT = 0.075
KIA_EV6_FF_ONSET = 0.08
KIA_EV6_FF_ONSET_WIDTH = 0.04
KIA_EV6_FF_CUTOFF = 0.60
@@ -447,20 +452,25 @@ KIA_EV6_FF_CUTOFF_WIDTH = 0.14
KIA_EV6_TRANSITION_SPEED = 11.0
KIA_EV6_PHASE_SCALE = 0.09
KIA_EV6_TURN_IN_BOOST_LEFT = 0.14
KIA_EV6_TURN_IN_BOOST_RIGHT = 0.22
KIA_EV6_UNWIND_TAPER_LEFT = 0.26
KIA_EV6_UNWIND_TAPER_RIGHT = 0.34
KIA_EV6_TURN_IN_BOOST_RIGHT = 0.16
KIA_EV6_UNWIND_TAPER_LEFT = 0.40
KIA_EV6_UNWIND_TAPER_RIGHT = 0.36
KIA_EV6_FRICTION_MULT = 1.01
KIA_EV6_FRICTION_LAT_RISE = 0.18
KIA_EV6_FRICTION_JERK_RISE = 0.22
KIA_EV6_TURN_IN_THRESHOLD_REDUCTION_LEFT = 0.10
KIA_EV6_TURN_IN_THRESHOLD_REDUCTION_RIGHT = 0.14
KIA_EV6_UNWIND_THRESHOLD_INCREASE_LEFT = 0.14
KIA_EV6_UNWIND_THRESHOLD_INCREASE_LEFT = 0.22
KIA_EV6_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.18
KIA_EV6_TURN_IN_FRICTION_BOOST_LEFT = 0.03
KIA_EV6_TURN_IN_FRICTION_BOOST_RIGHT = 0.05
KIA_EV6_UNWIND_FRICTION_REDUCTION_LEFT = 0.12
KIA_EV6_UNWIND_FRICTION_REDUCTION_RIGHT = 0.15
KIA_EV6_UNWIND_FRICTION_REDUCTION_LEFT = 0.22
KIA_EV6_UNWIND_FRICTION_REDUCTION_RIGHT = 0.16
KIA_EV6_CENTER_TAPER_MAX = 0.08
KIA_EV6_CENTER_TAPER_LAT = 0.16
KIA_EV6_CENTER_TAPER_LAT_WIDTH = 0.035
KIA_EV6_CENTER_TAPER_SPEED = 18.0
KIA_EV6_CENTER_TAPER_SPEED_WIDTH = 3.0
VOLT_PLEXY_LATERAL_TESTING_GROUND_ID = testing_ground.id_7
VOLT_PLEXY_FF_GAIN_LEFT = 0.12
@@ -1211,6 +1221,13 @@ def get_ioniq_5_friction_scale(v_ego: float, desired_lateral_accel: float, desir
return min(max(friction_scale, 0.86), 1.04)
def get_ioniq_5_center_taper_scale(desired_lateral_accel: float, v_ego: float) -> float:
speed_weight = _ioniq_5_sigmoid((v_ego - IONIQ_5_CENTER_TAPER_SPEED) / IONIQ_5_CENTER_TAPER_SPEED_WIDTH)
center_weight = _ioniq_5_sigmoid((IONIQ_5_CENTER_TAPER_LAT - abs(desired_lateral_accel)) / IONIQ_5_CENTER_TAPER_LAT_WIDTH)
reduction = IONIQ_5_CENTER_TAPER_MAX * speed_weight * center_weight
return 1.0 - reduction
def _ioniq_ev_old_sigmoid(x: float) -> float:
return _sigmoid(x)
@@ -1454,6 +1471,13 @@ def get_kia_ev6_friction_scale(v_ego: float, desired_lateral_accel: float, desir
return min(max(friction_scale, 0.90), 1.10)
def get_kia_ev6_center_taper_scale(desired_lateral_accel: float, v_ego: float) -> float:
speed_weight = _kia_ev6_sigmoid((v_ego - KIA_EV6_CENTER_TAPER_SPEED) / KIA_EV6_CENTER_TAPER_SPEED_WIDTH)
center_weight = _kia_ev6_sigmoid((KIA_EV6_CENTER_TAPER_LAT - abs(desired_lateral_accel)) / KIA_EV6_CENTER_TAPER_LAT_WIDTH)
reduction = KIA_EV6_CENTER_TAPER_MAX * speed_weight * center_weight
return 1.0 - reduction
def volt_plexy_lateral_testing_ground_active() -> bool:
return testing_ground.use(VOLT_PLEXY_LATERAL_TESTING_GROUND_ID)
@@ -1687,11 +1711,13 @@ class LatControlTorque(LatControl):
kia_forte_active = self.is_kia_forte
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()
ioniq_5_center_taper = get_ioniq_5_center_taper_scale(setpoint, CS.vEgo) if ioniq_5_active else 1.0
volt_standard_center_taper = get_volt_standard_center_taper_scale(setpoint, CS.vEgo) if volt_standard_test_active else 1.0
ioniq_ev_old_center_taper = get_ioniq_ev_old_center_taper_scale(setpoint, CS.vEgo) if ioniq_ev_old_active else 1.0
ioniq_6_center_taper = get_ioniq_6_center_taper_scale(setpoint, CS.vEgo) if ioniq_6_active else 1.0
sonata_hybrid_center_taper = get_sonata_hybrid_center_taper_scale(setpoint, CS.vEgo) if sonata_hybrid_active else 1.0
kia_forte_center_taper = get_kia_forte_center_taper_scale(setpoint, CS.vEgo) if kia_forte_active else 1.0
kia_ev6_center_taper = get_kia_ev6_center_taper_scale(setpoint, CS.vEgo) if kia_ev6_test_active else 1.0
civic_bosch_modified_a_center_taper = get_civic_bosch_modified_a_center_taper_scale(setpoint, CS.vEgo) if (
self.is_civic_bosch_modified and civic_bosch_modified_a_lateral_testing_ground_active()
) else 1.0
@@ -1714,9 +1740,10 @@ class LatControlTorque(LatControl):
friction_threshold = get_genesis_g90_friction_threshold(CS.vEgo, setpoint, desired_lateral_jerk)
friction_scale = get_genesis_g90_friction_scale(CS.vEgo, setpoint, desired_lateral_jerk)
elif ioniq_5_active:
ff *= get_ioniq_5_ff_scale(setpoint, desired_lateral_jerk, CS.vEgo)
ff *= get_ioniq_5_ff_scale(setpoint, desired_lateral_jerk, CS.vEgo) * ioniq_5_center_taper
friction_threshold = get_ioniq_5_friction_threshold(CS.vEgo, setpoint, desired_lateral_jerk)
friction_scale = get_ioniq_5_friction_scale(CS.vEgo, setpoint, desired_lateral_jerk)
friction_scale = 1.0 + ((friction_scale - 1.0) * ioniq_5_center_taper)
elif ioniq_ev_old_active:
ff *= get_ioniq_ev_old_ff_scale(setpoint, desired_lateral_jerk, CS.vEgo) * ioniq_ev_old_center_taper
friction_scale = 1.0 + ((friction_scale - 1.0) * ioniq_ev_old_center_taper)
@@ -1732,9 +1759,10 @@ class LatControlTorque(LatControl):
elif kia_forte_active:
ff *= get_kia_forte_ff_scale(setpoint, desired_lateral_jerk, CS.vEgo) * kia_forte_center_taper
elif kia_ev6_test_active:
ff *= get_kia_ev6_ff_scale(setpoint, desired_lateral_jerk, CS.vEgo)
ff *= get_kia_ev6_ff_scale(setpoint, desired_lateral_jerk, CS.vEgo) * kia_ev6_center_taper
friction_threshold = get_kia_ev6_friction_threshold(CS.vEgo, setpoint, desired_lateral_jerk)
friction_scale = get_kia_ev6_friction_scale(CS.vEgo, setpoint, desired_lateral_jerk)
friction_scale = 1.0 + ((friction_scale - 1.0) * kia_ev6_center_taper)
elif volt_plexy_test_active:
ff *= get_volt_plexy_ff_scale(setpoint, desired_lateral_jerk, CS.vEgo)
friction_threshold = get_volt_plexy_friction_threshold(CS.vEgo, setpoint, desired_lateral_jerk)
@@ -8,6 +8,7 @@ from openpilot.common.constants import CV
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.realtime import DT_MDL
from openpilot.selfdrive.modeld.constants import ModelConstants
from openpilot.starpilot.common.model_versions import is_tinygrad_model_version
from openpilot.selfdrive.controls.lib.longcontrol import LongCtrlState
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import desired_follow_distance
@@ -434,7 +435,7 @@ class LongitudinalPlanner:
@property
def mlsim(self):
return self.generation in ("v8", "v10", "v11", "v12", "v13", "v14", "v15")
return is_tinygrad_model_version(self.generation)
def get_mpc_mode(self) -> str:
if not self.mlsim:
+28 -3
View File
@@ -43,6 +43,7 @@ from openpilot.selfdrive.controls.lib.latcontrol_torque import (
get_ioniq_5_ff_scale,
get_ioniq_5_friction_scale,
get_ioniq_5_friction_threshold,
get_ioniq_5_center_taper_scale,
get_ioniq_ev_old_center_taper_scale,
get_ioniq_ev_old_ff_scale,
get_ioniq_6_center_taper_scale,
@@ -53,6 +54,7 @@ from openpilot.selfdrive.controls.lib.latcontrol_torque import (
get_ioniq_6_friction_threshold,
get_kia_forte_center_taper_scale,
get_kia_forte_ff_scale,
get_kia_ev6_center_taper_scale,
get_kia_ev6_ff_scale,
get_kia_ev6_friction_scale,
get_kia_ev6_friction_threshold,
@@ -338,6 +340,10 @@ class TestLatControl:
assert unwind_left_scale < 1.0
assert unwind_right_scale < unwind_left_scale
def test_ioniq_5_center_taper_curve(self):
assert get_ioniq_5_center_taper_scale(0.0, 25.0) < get_ioniq_5_center_taper_scale(0.0, 10.0)
assert get_ioniq_5_center_taper_scale(0.0, 25.0) < get_ioniq_5_center_taper_scale(0.20, 25.0) <= 1.0
def test_ioniq_ev_old_ff_scale_curve(self):
assert get_ioniq_ev_old_ff_scale(0.0, 0.0, 20.0) == 1.0
assert get_ioniq_ev_old_ff_scale(0.35, 0.0, 20.0) > get_ioniq_ev_old_ff_scale(-0.35, 0.0, 20.0)
@@ -420,7 +426,7 @@ class TestLatControl:
right_turn_in = get_kia_ev6_friction_threshold(6.0, -0.5, -0.8)
left_unwind = get_kia_ev6_friction_threshold(6.0, 0.5, -0.8)
right_unwind = get_kia_ev6_friction_threshold(6.0, -0.5, 0.8)
assert right_turn_in < left_turn_in < base < left_unwind < right_unwind
assert right_turn_in < left_turn_in < base < right_unwind < left_unwind
def test_kia_ev6_friction_scale_curve(self):
base = get_kia_ev6_friction_scale(25.0, 0.5, 0.8)
@@ -493,7 +499,7 @@ class TestLatControl:
_, _, lac_log = controller.update(True, CS, VM, params, False, 0.0025, False, 0.2, None, None, starpilot_toggles)
assert lac_log.active
assert controller.torque_params.latAccelFactor == pytest.approx(CP.lateralTuning.torque.latAccelFactor * 1.18)
assert controller.torque_params.latAccelFactor == pytest.approx(CP.lateralTuning.torque.latAccelFactor * 1.22)
def test_ioniq_6_default_update_path(self):
controller, VM, CS, params, starpilot_toggles = self._build_torque_controller(HYUNDAI.HYUNDAI_IONIQ_6)
@@ -521,7 +527,7 @@ class TestLatControl:
_, _, lac_log = controller.update(True, CS, VM, params, False, 0.0025, False, 0.2, None, None, starpilot_toggles)
assert lac_log.active
assert controller.torque_params.latAccelFactor == pytest.approx(CP.lateralTuning.torque.latAccelFactor * 1.08)
assert controller.torque_params.latAccelFactor == pytest.approx(CP.lateralTuning.torque.latAccelFactor * 1.10)
def test_ioniq_6_update_path_does_not_post_taper_output(self, monkeypatch):
base_controller, VM, CS, params, starpilot_toggles = self._build_torque_controller(HYUNDAI.HYUNDAI_IONIQ_6)
@@ -688,6 +694,25 @@ class TestLatControl:
assert lac_log.active
def test_kia_ev6_ff_scale_curve(self):
assert get_kia_ev6_ff_scale(0.0, 0.0, 20.0) == 1.0
steady_left = get_kia_ev6_ff_scale(0.45, 0.0, 25.0)
steady_right = get_kia_ev6_ff_scale(-0.45, 0.0, 25.0)
turn_in_left = get_kia_ev6_ff_scale(0.45, 0.7, 10.0)
turn_in_right = get_kia_ev6_ff_scale(-0.45, -0.7, 10.0)
unwind_left = get_kia_ev6_ff_scale(0.45, -0.7, 10.0)
unwind_right = get_kia_ev6_ff_scale(-0.45, 0.7, 10.0)
assert steady_left > 1.0
assert steady_right > steady_left
assert turn_in_left > steady_left
assert turn_in_right > steady_right
assert unwind_left < steady_left
assert unwind_right < steady_right
def test_kia_ev6_center_taper_curve(self):
assert get_kia_ev6_center_taper_scale(0.0, 25.0) < get_kia_ev6_center_taper_scale(0.0, 10.0)
assert get_kia_ev6_center_taper_scale(0.0, 25.0) < get_kia_ev6_center_taper_scale(0.20, 25.0) <= 1.0
def test_volt_plexy_testing_ground_update_path(self, monkeypatch):
controller, VM, CS, params, starpilot_toggles = self._build_torque_controller(GM.CHEVROLET_VOLT_CC)
monkeypatch.setattr(latcontrol_torque, "volt_plexy_lateral_testing_ground_active", lambda: True)
@@ -0,0 +1,130 @@
from types import SimpleNamespace
from cereal import log
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper, LaneChangeDirection, LaneChangeState
def make_car_state(**overrides):
defaults = {
"vEgo": 20.0,
"leftBlinker": False,
"rightBlinker": False,
"leftBlindspot": False,
"rightBlindspot": False,
"steeringPressed": False,
"steeringTorque": 0.0,
"standstill": False,
}
defaults.update(overrides)
return SimpleNamespace(**defaults)
def make_toggles(**overrides):
defaults = {
"lane_changes": True,
"lane_change_delay": 0.0,
"lane_detection_width": 3.0,
"minimum_lane_change_speed": 10.0,
"nudgeless": True,
"one_lane_change": False,
"use_turn_desires": False,
}
defaults.update(overrides)
return SimpleNamespace(**defaults)
def make_plan(**overrides):
defaults = {
"laneWidthLeft": 4.0,
"laneWidthRight": 4.0,
}
defaults.update(overrides)
return SimpleNamespace(**defaults)
def test_nav_desires_keep_left_when_route_requests_it():
helper = DesireHelper()
helper.nav_desires_allowed = True
helper._update_nav_params = lambda: None
helper._nav_instruction_state = {"valid": True, "maneuverModifier": "slightLeft"}
helper.update(
make_car_state(vEgo=20.0),
True,
0.0,
make_plan(laneWidthLeft=4.2),
make_toggles(nudgeless=True),
)
assert helper.desire == log.Desire.keepLeft
def test_nav_desires_turn_right_below_lane_change_speed():
helper = DesireHelper()
helper.nav_desires_allowed = True
helper._update_nav_params = lambda: None
helper._nav_instruction_state = {"valid": True, "maneuverModifier": "right", "maneuverDistance": 10.0}
helper.update(
make_car_state(vEgo=5.0),
True,
0.0,
make_plan(),
make_toggles(minimum_lane_change_speed=10.0),
)
assert helper.desire == log.Desire.turnRight
def test_nav_desires_turn_right_waits_until_turn_is_close():
helper = DesireHelper()
helper.nav_desires_allowed = True
helper._update_nav_params = lambda: None
helper._nav_instruction_state = {"valid": True, "maneuverModifier": "right", "maneuverDistance": 300.0}
helper.update(
make_car_state(vEgo=5.0),
True,
0.0,
make_plan(),
make_toggles(minimum_lane_change_speed=10.0),
)
assert helper.desire == log.Desire.none
def test_nav_desires_do_not_override_lane_change_state_machine():
helper = DesireHelper()
helper.nav_desires_allowed = True
helper._update_nav_params = lambda: None
helper._nav_instruction_state = {"valid": True, "maneuverModifier": "slightRight"}
helper.lane_change_state = LaneChangeState.laneChangeStarting
helper.lane_change_direction = LaneChangeDirection.left
helper.lane_change_ll_prob = 0.5
helper.update(
make_car_state(vEgo=25.0, leftBlinker=True),
True,
0.5,
make_plan(),
make_toggles(),
)
assert helper.desire == log.Desire.laneChangeLeft
def test_nav_desires_disabled_leave_desire_unchanged():
helper = DesireHelper()
helper.nav_desires_allowed = False
helper._update_nav_params = lambda: None
helper._nav_instruction_state = {"valid": True, "maneuverModifier": "left"}
helper.update(
make_car_state(vEgo=5.0),
True,
0.0,
make_plan(),
make_toggles(minimum_lane_change_speed=10.0),
)
assert helper.desire == log.Desire.none
@@ -6,8 +6,12 @@ from types import SimpleNamespace
class FakeParams:
def __init__(self, values=None):
self.values = dict(values or {})
def get(self, *args, **kwargs):
return None
key = args[0] if args else None
return self.values.get(key)
def get_float(self, *args, **kwargs):
return 0.0
@@ -16,10 +20,10 @@ class FakeParams:
pass
def make_vcruise(*, red_light=False, raw_model_stopped=False, forcing_stop=False):
def make_vcruise(*, red_light=False, raw_model_stopped=False, forcing_stop=False, nav_state=None):
planner = SimpleNamespace(
params=FakeParams(),
params_memory=FakeParams(),
params_memory=FakeParams({"NavInstructionState": nav_state or {}}),
lead_one=SimpleNamespace(status=False, dRel=float("inf"), vLead=0.0),
starpilot_cem=SimpleNamespace(stop_light_detected=red_light),
tracking_lead=False,
@@ -35,10 +39,11 @@ def make_vcruise(*, red_light=False, raw_model_stopped=False, forcing_stop=False
return planner, vcruise
def make_sm(*, standstill=True):
def make_sm(*, standstill=True, min_steer_speed=0.0):
return {
"carControl": SimpleNamespace(longActive=True),
"carState": SimpleNamespace(standstill=standstill, gasPressed=False, vCruiseCluster=0.0, vEgoCluster=0.0),
"carParams": SimpleNamespace(minSteerSpeed=min_steer_speed),
"starpilotCarState": SimpleNamespace(accelPressed=False, dashboardStopSign=0, dashboardSpeedLimit=0),
}
@@ -48,6 +53,7 @@ def make_toggles():
force_stops=True,
force_standstill=False,
curve_speed_controller=False,
nav_longitudinal_allowed=False,
speed_limit_controller=False,
show_speed_limits=False,
force_stop_distance_offset=0,
@@ -133,3 +139,164 @@ def test_force_stop_stays_committed_while_moving_even_if_scene_opens():
assert result == pytest.approx(0.0)
assert vcruise.force_stop_timer >= 0.5
assert vcruise.forcing_stop
def test_nav_turn_speed_control_default_off():
_, vcruise = make_vcruise(nav_state={
"valid": True,
"maneuverType": "turn",
"maneuverModifier": "right",
"maneuverDistance": 30.0,
"nextManeuverType": "",
"nextManeuverModifier": "",
"nextManeuverDistance": 0.0,
})
result = vcruise.update(
controls_enabled=True,
now=0.0,
time_validated=True,
v_cruise=20.0,
v_ego=20.0,
sm=make_sm(standstill=False),
starpilot_toggles=make_toggles(),
)
assert result == pytest.approx(20.0)
assert vcruise.nav_turn_target == pytest.approx(0.0)
def test_nav_turn_speed_control_slows_for_imminent_turn():
_, vcruise = make_vcruise(nav_state={
"valid": True,
"maneuverType": "turn",
"maneuverModifier": "right",
"maneuverDistance": 30.0,
"nextManeuverType": "",
"nextManeuverModifier": "",
"nextManeuverDistance": 0.0,
})
toggles = make_toggles()
toggles.nav_longitudinal_allowed = True
result = vcruise.update(
controls_enabled=True,
now=0.0,
time_validated=True,
v_cruise=20.0,
v_ego=20.0,
sm=make_sm(standstill=False),
starpilot_toggles=toggles,
)
assert result < 20.0
assert result == pytest.approx(vcruise.nav_turn_target)
assert result > 0.0
def test_nav_turn_speed_control_ignores_distant_turn():
_, vcruise = make_vcruise(nav_state={
"valid": True,
"maneuverType": "turn",
"maneuverModifier": "right",
"maneuverDistance": 400.0,
"nextManeuverType": "",
"nextManeuverModifier": "",
"nextManeuverDistance": 0.0,
})
toggles = make_toggles()
toggles.nav_longitudinal_allowed = True
result = vcruise.update(
controls_enabled=True,
now=0.0,
time_validated=True,
v_cruise=20.0,
v_ego=20.0,
sm=make_sm(standstill=False),
starpilot_toggles=toggles,
)
assert result == pytest.approx(20.0)
assert vcruise.nav_turn_target == pytest.approx(0.0)
def test_nav_turn_speed_control_ignores_off_ramp():
_, vcruise = make_vcruise(nav_state={
"valid": True,
"maneuverType": "off ramp",
"maneuverModifier": "slightRight",
"maneuverDistance": 40.0,
"nextManeuverType": "",
"nextManeuverModifier": "",
"nextManeuverDistance": 0.0,
})
toggles = make_toggles()
toggles.nav_longitudinal_allowed = True
result = vcruise.update(
controls_enabled=True,
now=0.0,
time_validated=True,
v_cruise=30.0,
v_ego=30.0,
sm=make_sm(standstill=False),
starpilot_toggles=toggles,
)
assert result == pytest.approx(30.0)
assert vcruise.nav_turn_target == pytest.approx(0.0)
def test_nav_turn_speed_control_respects_car_min_steer_speed():
_, vcruise = make_vcruise(nav_state={
"valid": True,
"maneuverType": "turn",
"maneuverModifier": "uturn",
"maneuverDistance": 8.0,
"nextManeuverType": "",
"nextManeuverModifier": "",
"nextManeuverDistance": 0.0,
})
toggles = make_toggles()
toggles.nav_longitudinal_allowed = True
result = vcruise.update(
controls_enabled=True,
now=0.0,
time_validated=True,
v_cruise=20.0,
v_ego=20.0,
sm=make_sm(standstill=False, min_steer_speed=7.0 * CV.MPH_TO_MS),
starpilot_toggles=toggles,
)
assert result == pytest.approx(vcruise.nav_turn_target)
assert vcruise.nav_turn_target >= 7.0 * CV.MPH_TO_MS
def test_nav_turn_speed_control_does_not_floor_steer_to_zero_cars():
_, vcruise = make_vcruise(nav_state={
"valid": True,
"maneuverType": "turn",
"maneuverModifier": "uturn",
"maneuverDistance": 8.0,
"nextManeuverType": "",
"nextManeuverModifier": "",
"nextManeuverDistance": 0.0,
})
toggles = make_toggles()
toggles.nav_longitudinal_allowed = True
result = vcruise.update(
controls_enabled=True,
now=0.0,
time_validated=True,
v_cruise=20.0,
v_ego=20.0,
sm=make_sm(standstill=False, min_steer_speed=0.0),
starpilot_toggles=toggles,
)
assert result == pytest.approx(vcruise.nav_turn_target)
assert vcruise.nav_turn_target == pytest.approx(5.0 * CV.MPH_TO_MS)
-1
View File
@@ -283,7 +283,6 @@ def main():
filter_initialized = False
critcal_services = ["accelerometer", "gyroscope", "cameraOdometry"]
observation_input_invalid = defaultdict(int)
input_invalid_limit = {s: round(INPUT_INVALID_LIMIT * (SERVICE_LIST[s].frequency / 20.)) for s in critcal_services}
input_invalid_threshold = {s: input_invalid_limit[s] - 0.5 for s in critcal_services}
input_invalid_decay = {s: calculate_invalid_input_decay(input_invalid_limit[s], INPUT_INVALID_RECOVERY, SERVICE_LIST[s].frequency) for s in critcal_services}
+342 -342
View File
@@ -45,326 +45,326 @@ const static double MAHA_THRESH_31 = 3.8414588206941227;
* *
* This file is part of 'ekf' *
******************************************************************************/
void err_fun(double *nom_x, double *delta_x, double *out_3568804456057098654) {
out_3568804456057098654[0] = delta_x[0] + nom_x[0];
out_3568804456057098654[1] = delta_x[1] + nom_x[1];
out_3568804456057098654[2] = delta_x[2] + nom_x[2];
out_3568804456057098654[3] = delta_x[3] + nom_x[3];
out_3568804456057098654[4] = delta_x[4] + nom_x[4];
out_3568804456057098654[5] = delta_x[5] + nom_x[5];
out_3568804456057098654[6] = delta_x[6] + nom_x[6];
out_3568804456057098654[7] = delta_x[7] + nom_x[7];
out_3568804456057098654[8] = delta_x[8] + nom_x[8];
void err_fun(double *nom_x, double *delta_x, double *out_1972702472511725479) {
out_1972702472511725479[0] = delta_x[0] + nom_x[0];
out_1972702472511725479[1] = delta_x[1] + nom_x[1];
out_1972702472511725479[2] = delta_x[2] + nom_x[2];
out_1972702472511725479[3] = delta_x[3] + nom_x[3];
out_1972702472511725479[4] = delta_x[4] + nom_x[4];
out_1972702472511725479[5] = delta_x[5] + nom_x[5];
out_1972702472511725479[6] = delta_x[6] + nom_x[6];
out_1972702472511725479[7] = delta_x[7] + nom_x[7];
out_1972702472511725479[8] = delta_x[8] + nom_x[8];
}
void inv_err_fun(double *nom_x, double *true_x, double *out_1840397183166108031) {
out_1840397183166108031[0] = -nom_x[0] + true_x[0];
out_1840397183166108031[1] = -nom_x[1] + true_x[1];
out_1840397183166108031[2] = -nom_x[2] + true_x[2];
out_1840397183166108031[3] = -nom_x[3] + true_x[3];
out_1840397183166108031[4] = -nom_x[4] + true_x[4];
out_1840397183166108031[5] = -nom_x[5] + true_x[5];
out_1840397183166108031[6] = -nom_x[6] + true_x[6];
out_1840397183166108031[7] = -nom_x[7] + true_x[7];
out_1840397183166108031[8] = -nom_x[8] + true_x[8];
void inv_err_fun(double *nom_x, double *true_x, double *out_3741555659818717473) {
out_3741555659818717473[0] = -nom_x[0] + true_x[0];
out_3741555659818717473[1] = -nom_x[1] + true_x[1];
out_3741555659818717473[2] = -nom_x[2] + true_x[2];
out_3741555659818717473[3] = -nom_x[3] + true_x[3];
out_3741555659818717473[4] = -nom_x[4] + true_x[4];
out_3741555659818717473[5] = -nom_x[5] + true_x[5];
out_3741555659818717473[6] = -nom_x[6] + true_x[6];
out_3741555659818717473[7] = -nom_x[7] + true_x[7];
out_3741555659818717473[8] = -nom_x[8] + true_x[8];
}
void H_mod_fun(double *state, double *out_8921258435077713963) {
out_8921258435077713963[0] = 1.0;
out_8921258435077713963[1] = 0.0;
out_8921258435077713963[2] = 0.0;
out_8921258435077713963[3] = 0.0;
out_8921258435077713963[4] = 0.0;
out_8921258435077713963[5] = 0.0;
out_8921258435077713963[6] = 0.0;
out_8921258435077713963[7] = 0.0;
out_8921258435077713963[8] = 0.0;
out_8921258435077713963[9] = 0.0;
out_8921258435077713963[10] = 1.0;
out_8921258435077713963[11] = 0.0;
out_8921258435077713963[12] = 0.0;
out_8921258435077713963[13] = 0.0;
out_8921258435077713963[14] = 0.0;
out_8921258435077713963[15] = 0.0;
out_8921258435077713963[16] = 0.0;
out_8921258435077713963[17] = 0.0;
out_8921258435077713963[18] = 0.0;
out_8921258435077713963[19] = 0.0;
out_8921258435077713963[20] = 1.0;
out_8921258435077713963[21] = 0.0;
out_8921258435077713963[22] = 0.0;
out_8921258435077713963[23] = 0.0;
out_8921258435077713963[24] = 0.0;
out_8921258435077713963[25] = 0.0;
out_8921258435077713963[26] = 0.0;
out_8921258435077713963[27] = 0.0;
out_8921258435077713963[28] = 0.0;
out_8921258435077713963[29] = 0.0;
out_8921258435077713963[30] = 1.0;
out_8921258435077713963[31] = 0.0;
out_8921258435077713963[32] = 0.0;
out_8921258435077713963[33] = 0.0;
out_8921258435077713963[34] = 0.0;
out_8921258435077713963[35] = 0.0;
out_8921258435077713963[36] = 0.0;
out_8921258435077713963[37] = 0.0;
out_8921258435077713963[38] = 0.0;
out_8921258435077713963[39] = 0.0;
out_8921258435077713963[40] = 1.0;
out_8921258435077713963[41] = 0.0;
out_8921258435077713963[42] = 0.0;
out_8921258435077713963[43] = 0.0;
out_8921258435077713963[44] = 0.0;
out_8921258435077713963[45] = 0.0;
out_8921258435077713963[46] = 0.0;
out_8921258435077713963[47] = 0.0;
out_8921258435077713963[48] = 0.0;
out_8921258435077713963[49] = 0.0;
out_8921258435077713963[50] = 1.0;
out_8921258435077713963[51] = 0.0;
out_8921258435077713963[52] = 0.0;
out_8921258435077713963[53] = 0.0;
out_8921258435077713963[54] = 0.0;
out_8921258435077713963[55] = 0.0;
out_8921258435077713963[56] = 0.0;
out_8921258435077713963[57] = 0.0;
out_8921258435077713963[58] = 0.0;
out_8921258435077713963[59] = 0.0;
out_8921258435077713963[60] = 1.0;
out_8921258435077713963[61] = 0.0;
out_8921258435077713963[62] = 0.0;
out_8921258435077713963[63] = 0.0;
out_8921258435077713963[64] = 0.0;
out_8921258435077713963[65] = 0.0;
out_8921258435077713963[66] = 0.0;
out_8921258435077713963[67] = 0.0;
out_8921258435077713963[68] = 0.0;
out_8921258435077713963[69] = 0.0;
out_8921258435077713963[70] = 1.0;
out_8921258435077713963[71] = 0.0;
out_8921258435077713963[72] = 0.0;
out_8921258435077713963[73] = 0.0;
out_8921258435077713963[74] = 0.0;
out_8921258435077713963[75] = 0.0;
out_8921258435077713963[76] = 0.0;
out_8921258435077713963[77] = 0.0;
out_8921258435077713963[78] = 0.0;
out_8921258435077713963[79] = 0.0;
out_8921258435077713963[80] = 1.0;
void H_mod_fun(double *state, double *out_4845788339544047954) {
out_4845788339544047954[0] = 1.0;
out_4845788339544047954[1] = 0.0;
out_4845788339544047954[2] = 0.0;
out_4845788339544047954[3] = 0.0;
out_4845788339544047954[4] = 0.0;
out_4845788339544047954[5] = 0.0;
out_4845788339544047954[6] = 0.0;
out_4845788339544047954[7] = 0.0;
out_4845788339544047954[8] = 0.0;
out_4845788339544047954[9] = 0.0;
out_4845788339544047954[10] = 1.0;
out_4845788339544047954[11] = 0.0;
out_4845788339544047954[12] = 0.0;
out_4845788339544047954[13] = 0.0;
out_4845788339544047954[14] = 0.0;
out_4845788339544047954[15] = 0.0;
out_4845788339544047954[16] = 0.0;
out_4845788339544047954[17] = 0.0;
out_4845788339544047954[18] = 0.0;
out_4845788339544047954[19] = 0.0;
out_4845788339544047954[20] = 1.0;
out_4845788339544047954[21] = 0.0;
out_4845788339544047954[22] = 0.0;
out_4845788339544047954[23] = 0.0;
out_4845788339544047954[24] = 0.0;
out_4845788339544047954[25] = 0.0;
out_4845788339544047954[26] = 0.0;
out_4845788339544047954[27] = 0.0;
out_4845788339544047954[28] = 0.0;
out_4845788339544047954[29] = 0.0;
out_4845788339544047954[30] = 1.0;
out_4845788339544047954[31] = 0.0;
out_4845788339544047954[32] = 0.0;
out_4845788339544047954[33] = 0.0;
out_4845788339544047954[34] = 0.0;
out_4845788339544047954[35] = 0.0;
out_4845788339544047954[36] = 0.0;
out_4845788339544047954[37] = 0.0;
out_4845788339544047954[38] = 0.0;
out_4845788339544047954[39] = 0.0;
out_4845788339544047954[40] = 1.0;
out_4845788339544047954[41] = 0.0;
out_4845788339544047954[42] = 0.0;
out_4845788339544047954[43] = 0.0;
out_4845788339544047954[44] = 0.0;
out_4845788339544047954[45] = 0.0;
out_4845788339544047954[46] = 0.0;
out_4845788339544047954[47] = 0.0;
out_4845788339544047954[48] = 0.0;
out_4845788339544047954[49] = 0.0;
out_4845788339544047954[50] = 1.0;
out_4845788339544047954[51] = 0.0;
out_4845788339544047954[52] = 0.0;
out_4845788339544047954[53] = 0.0;
out_4845788339544047954[54] = 0.0;
out_4845788339544047954[55] = 0.0;
out_4845788339544047954[56] = 0.0;
out_4845788339544047954[57] = 0.0;
out_4845788339544047954[58] = 0.0;
out_4845788339544047954[59] = 0.0;
out_4845788339544047954[60] = 1.0;
out_4845788339544047954[61] = 0.0;
out_4845788339544047954[62] = 0.0;
out_4845788339544047954[63] = 0.0;
out_4845788339544047954[64] = 0.0;
out_4845788339544047954[65] = 0.0;
out_4845788339544047954[66] = 0.0;
out_4845788339544047954[67] = 0.0;
out_4845788339544047954[68] = 0.0;
out_4845788339544047954[69] = 0.0;
out_4845788339544047954[70] = 1.0;
out_4845788339544047954[71] = 0.0;
out_4845788339544047954[72] = 0.0;
out_4845788339544047954[73] = 0.0;
out_4845788339544047954[74] = 0.0;
out_4845788339544047954[75] = 0.0;
out_4845788339544047954[76] = 0.0;
out_4845788339544047954[77] = 0.0;
out_4845788339544047954[78] = 0.0;
out_4845788339544047954[79] = 0.0;
out_4845788339544047954[80] = 1.0;
}
void f_fun(double *state, double dt, double *out_3277027219914288776) {
out_3277027219914288776[0] = state[0];
out_3277027219914288776[1] = state[1];
out_3277027219914288776[2] = state[2];
out_3277027219914288776[3] = state[3];
out_3277027219914288776[4] = state[4];
out_3277027219914288776[5] = dt*((-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]))*state[6] - 9.8100000000000005*state[8] + stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*state[1]) + (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*state[4])) + state[5];
out_3277027219914288776[6] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*state[4])) + state[6];
out_3277027219914288776[7] = state[7];
out_3277027219914288776[8] = state[8];
void f_fun(double *state, double dt, double *out_4185306989729419910) {
out_4185306989729419910[0] = state[0];
out_4185306989729419910[1] = state[1];
out_4185306989729419910[2] = state[2];
out_4185306989729419910[3] = state[3];
out_4185306989729419910[4] = state[4];
out_4185306989729419910[5] = dt*((-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]))*state[6] - 9.8100000000000005*state[8] + stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*state[1]) + (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*state[4])) + state[5];
out_4185306989729419910[6] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*state[4])) + state[6];
out_4185306989729419910[7] = state[7];
out_4185306989729419910[8] = state[8];
}
void F_fun(double *state, double dt, double *out_370955893725369602) {
out_370955893725369602[0] = 1;
out_370955893725369602[1] = 0;
out_370955893725369602[2] = 0;
out_370955893725369602[3] = 0;
out_370955893725369602[4] = 0;
out_370955893725369602[5] = 0;
out_370955893725369602[6] = 0;
out_370955893725369602[7] = 0;
out_370955893725369602[8] = 0;
out_370955893725369602[9] = 0;
out_370955893725369602[10] = 1;
out_370955893725369602[11] = 0;
out_370955893725369602[12] = 0;
out_370955893725369602[13] = 0;
out_370955893725369602[14] = 0;
out_370955893725369602[15] = 0;
out_370955893725369602[16] = 0;
out_370955893725369602[17] = 0;
out_370955893725369602[18] = 0;
out_370955893725369602[19] = 0;
out_370955893725369602[20] = 1;
out_370955893725369602[21] = 0;
out_370955893725369602[22] = 0;
out_370955893725369602[23] = 0;
out_370955893725369602[24] = 0;
out_370955893725369602[25] = 0;
out_370955893725369602[26] = 0;
out_370955893725369602[27] = 0;
out_370955893725369602[28] = 0;
out_370955893725369602[29] = 0;
out_370955893725369602[30] = 1;
out_370955893725369602[31] = 0;
out_370955893725369602[32] = 0;
out_370955893725369602[33] = 0;
out_370955893725369602[34] = 0;
out_370955893725369602[35] = 0;
out_370955893725369602[36] = 0;
out_370955893725369602[37] = 0;
out_370955893725369602[38] = 0;
out_370955893725369602[39] = 0;
out_370955893725369602[40] = 1;
out_370955893725369602[41] = 0;
out_370955893725369602[42] = 0;
out_370955893725369602[43] = 0;
out_370955893725369602[44] = 0;
out_370955893725369602[45] = dt*(stiffness_front*(-state[2] - state[3] + state[7])/(mass*state[1]) + (-stiffness_front - stiffness_rear)*state[5]/(mass*state[4]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[6]/(mass*state[4]));
out_370955893725369602[46] = -dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*pow(state[1], 2));
out_370955893725369602[47] = -dt*stiffness_front*state[0]/(mass*state[1]);
out_370955893725369602[48] = -dt*stiffness_front*state[0]/(mass*state[1]);
out_370955893725369602[49] = dt*((-1 - (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*pow(state[4], 2)))*state[6] - (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*pow(state[4], 2)));
out_370955893725369602[50] = dt*(-stiffness_front*state[0] - stiffness_rear*state[0])/(mass*state[4]) + 1;
out_370955893725369602[51] = dt*(-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]));
out_370955893725369602[52] = dt*stiffness_front*state[0]/(mass*state[1]);
out_370955893725369602[53] = -9.8100000000000005*dt;
out_370955893725369602[54] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front - pow(center_to_rear, 2)*stiffness_rear)*state[6]/(rotational_inertia*state[4]));
out_370955893725369602[55] = -center_to_front*dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*pow(state[1], 2));
out_370955893725369602[56] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_370955893725369602[57] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_370955893725369602[58] = dt*(-(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*pow(state[4], 2)) - (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*pow(state[4], 2)));
out_370955893725369602[59] = dt*(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(rotational_inertia*state[4]);
out_370955893725369602[60] = dt*(-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])/(rotational_inertia*state[4]) + 1;
out_370955893725369602[61] = center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_370955893725369602[62] = 0;
out_370955893725369602[63] = 0;
out_370955893725369602[64] = 0;
out_370955893725369602[65] = 0;
out_370955893725369602[66] = 0;
out_370955893725369602[67] = 0;
out_370955893725369602[68] = 0;
out_370955893725369602[69] = 0;
out_370955893725369602[70] = 1;
out_370955893725369602[71] = 0;
out_370955893725369602[72] = 0;
out_370955893725369602[73] = 0;
out_370955893725369602[74] = 0;
out_370955893725369602[75] = 0;
out_370955893725369602[76] = 0;
out_370955893725369602[77] = 0;
out_370955893725369602[78] = 0;
out_370955893725369602[79] = 0;
out_370955893725369602[80] = 1;
void F_fun(double *state, double dt, double *out_8252178874365212967) {
out_8252178874365212967[0] = 1;
out_8252178874365212967[1] = 0;
out_8252178874365212967[2] = 0;
out_8252178874365212967[3] = 0;
out_8252178874365212967[4] = 0;
out_8252178874365212967[5] = 0;
out_8252178874365212967[6] = 0;
out_8252178874365212967[7] = 0;
out_8252178874365212967[8] = 0;
out_8252178874365212967[9] = 0;
out_8252178874365212967[10] = 1;
out_8252178874365212967[11] = 0;
out_8252178874365212967[12] = 0;
out_8252178874365212967[13] = 0;
out_8252178874365212967[14] = 0;
out_8252178874365212967[15] = 0;
out_8252178874365212967[16] = 0;
out_8252178874365212967[17] = 0;
out_8252178874365212967[18] = 0;
out_8252178874365212967[19] = 0;
out_8252178874365212967[20] = 1;
out_8252178874365212967[21] = 0;
out_8252178874365212967[22] = 0;
out_8252178874365212967[23] = 0;
out_8252178874365212967[24] = 0;
out_8252178874365212967[25] = 0;
out_8252178874365212967[26] = 0;
out_8252178874365212967[27] = 0;
out_8252178874365212967[28] = 0;
out_8252178874365212967[29] = 0;
out_8252178874365212967[30] = 1;
out_8252178874365212967[31] = 0;
out_8252178874365212967[32] = 0;
out_8252178874365212967[33] = 0;
out_8252178874365212967[34] = 0;
out_8252178874365212967[35] = 0;
out_8252178874365212967[36] = 0;
out_8252178874365212967[37] = 0;
out_8252178874365212967[38] = 0;
out_8252178874365212967[39] = 0;
out_8252178874365212967[40] = 1;
out_8252178874365212967[41] = 0;
out_8252178874365212967[42] = 0;
out_8252178874365212967[43] = 0;
out_8252178874365212967[44] = 0;
out_8252178874365212967[45] = dt*(stiffness_front*(-state[2] - state[3] + state[7])/(mass*state[1]) + (-stiffness_front - stiffness_rear)*state[5]/(mass*state[4]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[6]/(mass*state[4]));
out_8252178874365212967[46] = -dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*pow(state[1], 2));
out_8252178874365212967[47] = -dt*stiffness_front*state[0]/(mass*state[1]);
out_8252178874365212967[48] = -dt*stiffness_front*state[0]/(mass*state[1]);
out_8252178874365212967[49] = dt*((-1 - (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*pow(state[4], 2)))*state[6] - (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*pow(state[4], 2)));
out_8252178874365212967[50] = dt*(-stiffness_front*state[0] - stiffness_rear*state[0])/(mass*state[4]) + 1;
out_8252178874365212967[51] = dt*(-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]));
out_8252178874365212967[52] = dt*stiffness_front*state[0]/(mass*state[1]);
out_8252178874365212967[53] = -9.8100000000000005*dt;
out_8252178874365212967[54] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front - pow(center_to_rear, 2)*stiffness_rear)*state[6]/(rotational_inertia*state[4]));
out_8252178874365212967[55] = -center_to_front*dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*pow(state[1], 2));
out_8252178874365212967[56] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_8252178874365212967[57] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_8252178874365212967[58] = dt*(-(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*pow(state[4], 2)) - (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*pow(state[4], 2)));
out_8252178874365212967[59] = dt*(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(rotational_inertia*state[4]);
out_8252178874365212967[60] = dt*(-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])/(rotational_inertia*state[4]) + 1;
out_8252178874365212967[61] = center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
out_8252178874365212967[62] = 0;
out_8252178874365212967[63] = 0;
out_8252178874365212967[64] = 0;
out_8252178874365212967[65] = 0;
out_8252178874365212967[66] = 0;
out_8252178874365212967[67] = 0;
out_8252178874365212967[68] = 0;
out_8252178874365212967[69] = 0;
out_8252178874365212967[70] = 1;
out_8252178874365212967[71] = 0;
out_8252178874365212967[72] = 0;
out_8252178874365212967[73] = 0;
out_8252178874365212967[74] = 0;
out_8252178874365212967[75] = 0;
out_8252178874365212967[76] = 0;
out_8252178874365212967[77] = 0;
out_8252178874365212967[78] = 0;
out_8252178874365212967[79] = 0;
out_8252178874365212967[80] = 1;
}
void h_25(double *state, double *unused, double *out_8154090013633331696) {
out_8154090013633331696[0] = state[6];
void h_25(double *state, double *unused, double *out_4739826667919645243) {
out_4739826667919645243[0] = state[6];
}
void H_25(double *state, double *unused, double *out_8415923992877417251) {
out_8415923992877417251[0] = 0;
out_8415923992877417251[1] = 0;
out_8415923992877417251[2] = 0;
out_8415923992877417251[3] = 0;
out_8415923992877417251[4] = 0;
out_8415923992877417251[5] = 0;
out_8415923992877417251[6] = 1;
out_8415923992877417251[7] = 0;
out_8415923992877417251[8] = 0;
void H_25(double *state, double *unused, double *out_2698629402266667542) {
out_2698629402266667542[0] = 0;
out_2698629402266667542[1] = 0;
out_2698629402266667542[2] = 0;
out_2698629402266667542[3] = 0;
out_2698629402266667542[4] = 0;
out_2698629402266667542[5] = 0;
out_2698629402266667542[6] = 1;
out_2698629402266667542[7] = 0;
out_2698629402266667542[8] = 0;
}
void h_24(double *state, double *unused, double *out_7351280482288278166) {
out_7351280482288278166[0] = state[4];
out_7351280482288278166[1] = state[5];
void h_24(double *state, double *unused, double *out_6091047700113278923) {
out_6091047700113278923[0] = state[4];
out_6091047700113278923[1] = state[5];
}
void H_24(double *state, double *unused, double *out_8301956961654820296) {
out_8301956961654820296[0] = 0;
out_8301956961654820296[1] = 0;
out_8301956961654820296[2] = 0;
out_8301956961654820296[3] = 0;
out_8301956961654820296[4] = 1;
out_8301956961654820296[5] = 0;
out_8301956961654820296[6] = 0;
out_8301956961654820296[7] = 0;
out_8301956961654820296[8] = 0;
out_8301956961654820296[9] = 0;
out_8301956961654820296[10] = 0;
out_8301956961654820296[11] = 0;
out_8301956961654820296[12] = 0;
out_8301956961654820296[13] = 0;
out_8301956961654820296[14] = 1;
out_8301956961654820296[15] = 0;
out_8301956961654820296[16] = 0;
out_8301956961654820296[17] = 0;
void H_24(double *state, double *unused, double *out_2121692102389320721) {
out_2121692102389320721[0] = 0;
out_2121692102389320721[1] = 0;
out_2121692102389320721[2] = 0;
out_2121692102389320721[3] = 0;
out_2121692102389320721[4] = 1;
out_2121692102389320721[5] = 0;
out_2121692102389320721[6] = 0;
out_2121692102389320721[7] = 0;
out_2121692102389320721[8] = 0;
out_2121692102389320721[9] = 0;
out_2121692102389320721[10] = 0;
out_2121692102389320721[11] = 0;
out_2121692102389320721[12] = 0;
out_2121692102389320721[13] = 0;
out_2121692102389320721[14] = 1;
out_2121692102389320721[15] = 0;
out_2121692102389320721[16] = 0;
out_2121692102389320721[17] = 0;
}
void h_30(double *state, double *unused, double *out_4292406537204830044) {
out_4292406537204830044[0] = state[4];
void h_30(double *state, double *unused, double *out_7687552658275130204) {
out_7687552658275130204[0] = state[4];
}
void H_30(double *state, double *unused, double *out_1499233651385800496) {
out_1499233651385800496[0] = 0;
out_1499233651385800496[1] = 0;
out_1499233651385800496[2] = 0;
out_1499233651385800496[3] = 0;
out_1499233651385800496[4] = 1;
out_1499233651385800496[5] = 0;
out_1499233651385800496[6] = 0;
out_1499233651385800496[7] = 0;
out_1499233651385800496[8] = 0;
void H_30(double *state, double *unused, double *out_2569290455123427472) {
out_2569290455123427472[0] = 0;
out_2569290455123427472[1] = 0;
out_2569290455123427472[2] = 0;
out_2569290455123427472[3] = 0;
out_2569290455123427472[4] = 1;
out_2569290455123427472[5] = 0;
out_2569290455123427472[6] = 0;
out_2569290455123427472[7] = 0;
out_2569290455123427472[8] = 0;
}
void h_26(double *state, double *unused, double *out_7000316085453517212) {
out_7000316085453517212[0] = state[7];
void h_26(double *state, double *unused, double *out_7946639312164568029) {
out_7946639312164568029[0] = state[7];
}
void H_26(double *state, double *unused, double *out_6289316761958078141) {
out_6289316761958078141[0] = 0;
out_6289316761958078141[1] = 0;
out_6289316761958078141[2] = 0;
out_6289316761958078141[3] = 0;
out_6289316761958078141[4] = 0;
out_6289316761958078141[5] = 0;
out_6289316761958078141[6] = 0;
out_6289316761958078141[7] = 1;
out_6289316761958078141[8] = 0;
void H_26(double *state, double *unused, double *out_1042873916607388682) {
out_1042873916607388682[0] = 0;
out_1042873916607388682[1] = 0;
out_1042873916607388682[2] = 0;
out_1042873916607388682[3] = 0;
out_1042873916607388682[4] = 0;
out_1042873916607388682[5] = 0;
out_1042873916607388682[6] = 0;
out_1042873916607388682[7] = 1;
out_1042873916607388682[8] = 0;
}
void h_27(double *state, double *unused, double *out_3964284714812858416) {
out_3964284714812858416[0] = state[3];
void h_27(double *state, double *unused, double *out_3665830151724581410) {
out_3665830151724581410[0] = state[3];
}
void H_27(double *state, double *unused, double *out_3673996963186225407) {
out_3673996963186225407[0] = 0;
out_3673996963186225407[1] = 0;
out_3673996963186225407[2] = 0;
out_3673996963186225407[3] = 1;
out_3673996963186225407[4] = 0;
out_3673996963186225407[5] = 0;
out_3673996963186225407[6] = 0;
out_3673996963186225407[7] = 0;
out_3673996963186225407[8] = 0;
void H_27(double *state, double *unused, double *out_394527143323002561) {
out_394527143323002561[0] = 0;
out_394527143323002561[1] = 0;
out_394527143323002561[2] = 0;
out_394527143323002561[3] = 1;
out_394527143323002561[4] = 0;
out_394527143323002561[5] = 0;
out_394527143323002561[6] = 0;
out_394527143323002561[7] = 0;
out_394527143323002561[8] = 0;
}
void h_29(double *state, double *unused, double *out_3689090652528352527) {
out_3689090652528352527[0] = state[1];
void h_29(double *state, double *unused, double *out_8290868542951607721) {
out_8290868542951607721[0] = state[1];
}
void H_29(double *state, double *unused, double *out_989002307071408312) {
out_989002307071408312[0] = 0;
out_989002307071408312[1] = 1;
out_989002307071408312[2] = 0;
out_989002307071408312[3] = 0;
out_989002307071408312[4] = 0;
out_989002307071408312[5] = 0;
out_989002307071408312[6] = 0;
out_989002307071408312[7] = 0;
out_989002307071408312[8] = 0;
void H_29(double *state, double *unused, double *out_3079521799437819656) {
out_3079521799437819656[0] = 0;
out_3079521799437819656[1] = 1;
out_3079521799437819656[2] = 0;
out_3079521799437819656[3] = 0;
out_3079521799437819656[4] = 0;
out_3079521799437819656[5] = 0;
out_3079521799437819656[6] = 0;
out_3079521799437819656[7] = 0;
out_3079521799437819656[8] = 0;
}
void h_28(double *state, double *unused, double *out_1914000772745856672) {
out_1914000772745856672[0] = state[0];
void h_28(double *state, double *unused, double *out_6846547824895893173) {
out_6846547824895893173[0] = state[0];
}
void H_28(double *state, double *unused, double *out_6071401324140938886) {
out_6071401324140938886[0] = 1;
out_6071401324140938886[1] = 0;
out_6071401324140938886[2] = 0;
out_6071401324140938886[3] = 0;
out_6071401324140938886[4] = 0;
out_6071401324140938886[5] = 0;
out_6071401324140938886[6] = 0;
out_6071401324140938886[7] = 0;
out_6071401324140938886[8] = 0;
void H_28(double *state, double *unused, double *out_2002877217631710918) {
out_2002877217631710918[0] = 1;
out_2002877217631710918[1] = 0;
out_2002877217631710918[2] = 0;
out_2002877217631710918[3] = 0;
out_2002877217631710918[4] = 0;
out_2002877217631710918[5] = 0;
out_2002877217631710918[6] = 0;
out_2002877217631710918[7] = 0;
out_2002877217631710918[8] = 0;
}
void h_31(double *state, double *unused, double *out_8205050127743358283) {
out_8205050127743358283[0] = state[8];
void h_31(double *state, double *unused, double *out_3141445982834403942) {
out_3141445982834403942[0] = state[8];
}
void H_31(double *state, double *unused, double *out_8385278031000456823) {
out_8385278031000456823[0] = 0;
out_8385278031000456823[1] = 0;
out_8385278031000456823[2] = 0;
out_8385278031000456823[3] = 0;
out_8385278031000456823[4] = 0;
out_8385278031000456823[5] = 0;
out_8385278031000456823[6] = 0;
out_8385278031000456823[7] = 0;
out_8385278031000456823[8] = 1;
void H_31(double *state, double *unused, double *out_2729275364143627970) {
out_2729275364143627970[0] = 0;
out_2729275364143627970[1] = 0;
out_2729275364143627970[2] = 0;
out_2729275364143627970[3] = 0;
out_2729275364143627970[4] = 0;
out_2729275364143627970[5] = 0;
out_2729275364143627970[6] = 0;
out_2729275364143627970[7] = 0;
out_2729275364143627970[8] = 1;
}
#include <eigen3/Eigen/Dense>
#include <iostream>
@@ -518,68 +518,68 @@ void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, doubl
void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea) {
update<1, 3, 0>(in_x, in_P, h_31, H_31, NULL, in_z, in_R, in_ea, MAHA_THRESH_31);
}
void car_err_fun(double *nom_x, double *delta_x, double *out_3568804456057098654) {
err_fun(nom_x, delta_x, out_3568804456057098654);
void car_err_fun(double *nom_x, double *delta_x, double *out_1972702472511725479) {
err_fun(nom_x, delta_x, out_1972702472511725479);
}
void car_inv_err_fun(double *nom_x, double *true_x, double *out_1840397183166108031) {
inv_err_fun(nom_x, true_x, out_1840397183166108031);
void car_inv_err_fun(double *nom_x, double *true_x, double *out_3741555659818717473) {
inv_err_fun(nom_x, true_x, out_3741555659818717473);
}
void car_H_mod_fun(double *state, double *out_8921258435077713963) {
H_mod_fun(state, out_8921258435077713963);
void car_H_mod_fun(double *state, double *out_4845788339544047954) {
H_mod_fun(state, out_4845788339544047954);
}
void car_f_fun(double *state, double dt, double *out_3277027219914288776) {
f_fun(state, dt, out_3277027219914288776);
void car_f_fun(double *state, double dt, double *out_4185306989729419910) {
f_fun(state, dt, out_4185306989729419910);
}
void car_F_fun(double *state, double dt, double *out_370955893725369602) {
F_fun(state, dt, out_370955893725369602);
void car_F_fun(double *state, double dt, double *out_8252178874365212967) {
F_fun(state, dt, out_8252178874365212967);
}
void car_h_25(double *state, double *unused, double *out_8154090013633331696) {
h_25(state, unused, out_8154090013633331696);
void car_h_25(double *state, double *unused, double *out_4739826667919645243) {
h_25(state, unused, out_4739826667919645243);
}
void car_H_25(double *state, double *unused, double *out_8415923992877417251) {
H_25(state, unused, out_8415923992877417251);
void car_H_25(double *state, double *unused, double *out_2698629402266667542) {
H_25(state, unused, out_2698629402266667542);
}
void car_h_24(double *state, double *unused, double *out_7351280482288278166) {
h_24(state, unused, out_7351280482288278166);
void car_h_24(double *state, double *unused, double *out_6091047700113278923) {
h_24(state, unused, out_6091047700113278923);
}
void car_H_24(double *state, double *unused, double *out_8301956961654820296) {
H_24(state, unused, out_8301956961654820296);
void car_H_24(double *state, double *unused, double *out_2121692102389320721) {
H_24(state, unused, out_2121692102389320721);
}
void car_h_30(double *state, double *unused, double *out_4292406537204830044) {
h_30(state, unused, out_4292406537204830044);
void car_h_30(double *state, double *unused, double *out_7687552658275130204) {
h_30(state, unused, out_7687552658275130204);
}
void car_H_30(double *state, double *unused, double *out_1499233651385800496) {
H_30(state, unused, out_1499233651385800496);
void car_H_30(double *state, double *unused, double *out_2569290455123427472) {
H_30(state, unused, out_2569290455123427472);
}
void car_h_26(double *state, double *unused, double *out_7000316085453517212) {
h_26(state, unused, out_7000316085453517212);
void car_h_26(double *state, double *unused, double *out_7946639312164568029) {
h_26(state, unused, out_7946639312164568029);
}
void car_H_26(double *state, double *unused, double *out_6289316761958078141) {
H_26(state, unused, out_6289316761958078141);
void car_H_26(double *state, double *unused, double *out_1042873916607388682) {
H_26(state, unused, out_1042873916607388682);
}
void car_h_27(double *state, double *unused, double *out_3964284714812858416) {
h_27(state, unused, out_3964284714812858416);
void car_h_27(double *state, double *unused, double *out_3665830151724581410) {
h_27(state, unused, out_3665830151724581410);
}
void car_H_27(double *state, double *unused, double *out_3673996963186225407) {
H_27(state, unused, out_3673996963186225407);
void car_H_27(double *state, double *unused, double *out_394527143323002561) {
H_27(state, unused, out_394527143323002561);
}
void car_h_29(double *state, double *unused, double *out_3689090652528352527) {
h_29(state, unused, out_3689090652528352527);
void car_h_29(double *state, double *unused, double *out_8290868542951607721) {
h_29(state, unused, out_8290868542951607721);
}
void car_H_29(double *state, double *unused, double *out_989002307071408312) {
H_29(state, unused, out_989002307071408312);
void car_H_29(double *state, double *unused, double *out_3079521799437819656) {
H_29(state, unused, out_3079521799437819656);
}
void car_h_28(double *state, double *unused, double *out_1914000772745856672) {
h_28(state, unused, out_1914000772745856672);
void car_h_28(double *state, double *unused, double *out_6846547824895893173) {
h_28(state, unused, out_6846547824895893173);
}
void car_H_28(double *state, double *unused, double *out_6071401324140938886) {
H_28(state, unused, out_6071401324140938886);
void car_H_28(double *state, double *unused, double *out_2002877217631710918) {
H_28(state, unused, out_2002877217631710918);
}
void car_h_31(double *state, double *unused, double *out_8205050127743358283) {
h_31(state, unused, out_8205050127743358283);
void car_h_31(double *state, double *unused, double *out_3141445982834403942) {
h_31(state, unused, out_3141445982834403942);
}
void car_H_31(double *state, double *unused, double *out_8385278031000456823) {
H_31(state, unused, out_8385278031000456823);
void car_H_31(double *state, double *unused, double *out_2729275364143627970) {
H_31(state, unused, out_2729275364143627970);
}
void car_predict(double *in_x, double *in_P, double *in_Q, double dt) {
predict(in_x, in_P, in_Q, dt);
+21 -21
View File
@@ -9,27 +9,27 @@ void car_update_27(double *in_x, double *in_P, double *in_z, double *in_R, doubl
void car_update_29(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void car_err_fun(double *nom_x, double *delta_x, double *out_3568804456057098654);
void car_inv_err_fun(double *nom_x, double *true_x, double *out_1840397183166108031);
void car_H_mod_fun(double *state, double *out_8921258435077713963);
void car_f_fun(double *state, double dt, double *out_3277027219914288776);
void car_F_fun(double *state, double dt, double *out_370955893725369602);
void car_h_25(double *state, double *unused, double *out_8154090013633331696);
void car_H_25(double *state, double *unused, double *out_8415923992877417251);
void car_h_24(double *state, double *unused, double *out_7351280482288278166);
void car_H_24(double *state, double *unused, double *out_8301956961654820296);
void car_h_30(double *state, double *unused, double *out_4292406537204830044);
void car_H_30(double *state, double *unused, double *out_1499233651385800496);
void car_h_26(double *state, double *unused, double *out_7000316085453517212);
void car_H_26(double *state, double *unused, double *out_6289316761958078141);
void car_h_27(double *state, double *unused, double *out_3964284714812858416);
void car_H_27(double *state, double *unused, double *out_3673996963186225407);
void car_h_29(double *state, double *unused, double *out_3689090652528352527);
void car_H_29(double *state, double *unused, double *out_989002307071408312);
void car_h_28(double *state, double *unused, double *out_1914000772745856672);
void car_H_28(double *state, double *unused, double *out_6071401324140938886);
void car_h_31(double *state, double *unused, double *out_8205050127743358283);
void car_H_31(double *state, double *unused, double *out_8385278031000456823);
void car_err_fun(double *nom_x, double *delta_x, double *out_1972702472511725479);
void car_inv_err_fun(double *nom_x, double *true_x, double *out_3741555659818717473);
void car_H_mod_fun(double *state, double *out_4845788339544047954);
void car_f_fun(double *state, double dt, double *out_4185306989729419910);
void car_F_fun(double *state, double dt, double *out_8252178874365212967);
void car_h_25(double *state, double *unused, double *out_4739826667919645243);
void car_H_25(double *state, double *unused, double *out_2698629402266667542);
void car_h_24(double *state, double *unused, double *out_6091047700113278923);
void car_H_24(double *state, double *unused, double *out_2121692102389320721);
void car_h_30(double *state, double *unused, double *out_7687552658275130204);
void car_H_30(double *state, double *unused, double *out_2569290455123427472);
void car_h_26(double *state, double *unused, double *out_7946639312164568029);
void car_H_26(double *state, double *unused, double *out_1042873916607388682);
void car_h_27(double *state, double *unused, double *out_3665830151724581410);
void car_H_27(double *state, double *unused, double *out_394527143323002561);
void car_h_29(double *state, double *unused, double *out_8290868542951607721);
void car_H_29(double *state, double *unused, double *out_3079521799437819656);
void car_h_28(double *state, double *unused, double *out_6846547824895893173);
void car_H_28(double *state, double *unused, double *out_2002877217631710918);
void car_h_31(double *state, double *unused, double *out_3141445982834403942);
void car_H_31(double *state, double *unused, double *out_2729275364143627970);
void car_predict(double *in_x, double *in_P, double *in_Q, double dt);
void car_set_mass(double x);
void car_set_rotational_inertia(double x);
File diff suppressed because it is too large Load Diff
+13 -13
View File
@@ -5,18 +5,18 @@ void pose_update_4(double *in_x, double *in_P, double *in_z, double *in_R, doubl
void pose_update_10(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void pose_update_13(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void pose_update_14(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
void pose_err_fun(double *nom_x, double *delta_x, double *out_3667758909157266385);
void pose_inv_err_fun(double *nom_x, double *true_x, double *out_3255008687637156165);
void pose_H_mod_fun(double *state, double *out_1678148223451849404);
void pose_f_fun(double *state, double dt, double *out_4390690219844123460);
void pose_F_fun(double *state, double dt, double *out_5251920544283288288);
void pose_h_4(double *state, double *unused, double *out_2086181486544094617);
void pose_H_4(double *state, double *unused, double *out_141550502454447457);
void pose_h_10(double *state, double *unused, double *out_2304974017593414723);
void pose_H_10(double *state, double *unused, double *out_521311265061217175);
void pose_h_13(double *state, double *unused, double *out_6563098082746675966);
void pose_H_13(double *state, double *unused, double *out_3070723322877885344);
void pose_h_14(double *state, double *unused, double *out_4832039927491863335);
void pose_H_14(double *state, double *unused, double *out_3821690353885037072);
void pose_err_fun(double *nom_x, double *delta_x, double *out_867342344380239798);
void pose_inv_err_fun(double *nom_x, double *true_x, double *out_2946458972277190645);
void pose_H_mod_fun(double *state, double *out_8034808007713849348);
void pose_f_fun(double *state, double dt, double *out_5448742405462655453);
void pose_F_fun(double *state, double dt, double *out_582733379073092242);
void pose_h_4(double *state, double *unused, double *out_959952002277923346);
void pose_H_4(double *state, double *unused, double *out_1467574399937880926);
void pose_h_10(double *state, double *unused, double *out_315403293584823803);
void pose_H_10(double *state, double *unused, double *out_2334763542090568144);
void pose_h_13(double *state, double *unused, double *out_5013407308002664142);
void pose_H_13(double *state, double *unused, double *out_4679848225270213727);
void pose_h_14(double *state, double *unused, double *out_6338305732819674146);
void pose_H_14(double *state, double *unused, double *out_1615214032357491370);
void pose_predict(double *in_x, double *in_P, double *in_Q, double dt);
}
+389
View File
@@ -0,0 +1,389 @@
#!/usr/bin/env python3
import argparse
import atexit
import os
import pickle
import time
from collections import defaultdict, namedtuple
from functools import partial
import numpy as np
def _patch_tinygrad_fetch_fw():
import hashlib
import pathlib
import zstandard
from tinygrad import helpers
original_fetch_fw = getattr(helpers, "fetch_fw", None)
if original_fetch_fw is None:
return
def fetch_fw(path, name, sha256):
firmware_path = pathlib.Path(f"/lib/firmware/{path}/{name}.zst")
if firmware_path.is_file():
blob = zstandard.ZstdDecompressor().stream_reader(firmware_path.read_bytes()).read()
if hashlib.sha256(blob).hexdigest() == sha256:
return blob
return original_fetch_fw(path, name, sha256)
helpers.fetch_fw = fetch_fw
_patch_tinygrad_fetch_fw()
from tinygrad.device import Device
from tinygrad.engine.jit import TinyJit
from tinygrad.helpers import Context
from tinygrad.tensor import Tensor
NV12Frame = namedtuple("NV12Frame", ["width", "height", "stride", "y_height", "uv_height", "size"])
WARP_INPUTS = ["img_q", "big_img_q", "tfm", "big_tfm"]
POLICY_INPUTS = ["feat_q", "desire_q", "desire", "traffic_convention", "action_t"]
WARP_DEV = os.getenv("WARP_DEV")
def make_random_images(keys, shape, device=None):
return {key: Tensor.randint(shape, low=0, high=256, dtype="uint8", device=device).realize() for key in keys}
class _BlobTensorInputs(dict):
_backing_arrays: dict[str, np.ndarray]
def make_random_blob_images(keys, shape, device=None):
blob_shape = shape if isinstance(shape, tuple) else (shape,)
backing_arrays = {
key: np.random.randint(0, 256, size=blob_shape, dtype=np.uint8)
for key in keys
}
inputs = _BlobTensorInputs({
key: Tensor.from_blob(array.ctypes.data, array.shape, dtype="uint8", device=device).realize()
for key, array in backing_arrays.items()
})
# Keep the numpy storage alive for the duration of the JIT capture/replay call.
inputs._backing_arrays = backing_arrays
return inputs
def warp_perspective_tinygrad(src_flat, matrix_inverse, dst_shape, src_shape, stride_pad, border_fill_val=None):
width_dst, height_dst = dst_shape
height_src, width_src = src_shape
x = Tensor.arange(width_dst, device=WARP_DEV).reshape(1, width_dst).expand(height_dst, width_dst).reshape(-1)
y = Tensor.arange(height_dst, device=WARP_DEV).reshape(height_dst, 1).expand(height_dst, width_dst).reshape(-1)
# Inline 3x3 matmul as elementwise to avoid reduce ops and enable fusion with gather.
src_x = matrix_inverse[0, 0] * x + matrix_inverse[0, 1] * y + matrix_inverse[0, 2]
src_y = matrix_inverse[1, 0] * x + matrix_inverse[1, 1] * y + matrix_inverse[1, 2]
src_w = matrix_inverse[2, 0] * x + matrix_inverse[2, 1] * y + matrix_inverse[2, 2]
src_x = src_x / src_w
src_y = src_y / src_w
x_round = Tensor.round(src_x)
y_round = Tensor.round(src_y)
x_nn_clipped = x_round.clip(0, width_src - 1).cast("int")
y_nn_clipped = y_round.clip(0, height_src - 1).cast("int")
idx = y_nn_clipped * (width_src + stride_pad) + x_nn_clipped
sampled = src_flat[idx]
if border_fill_val is None:
return sampled
in_bounds = ((x_round >= 0) & (x_round <= width_src - 1) &
(y_round >= 0) & (y_round <= height_src - 1)).cast(sampled.dtype)
return sampled * in_bounds + Tensor(border_fill_val, dtype=sampled.dtype) * (1 - in_bounds)
def frames_to_tensor(frames):
height = (frames.shape[0] * 2) // 3
width = frames.shape[1]
return Tensor.cat(
frames[0:height:2, 0::2],
frames[1:height:2, 0::2],
frames[0:height:2, 1::2],
frames[1:height:2, 1::2],
frames[height:height + height // 4].reshape((height // 2, width // 2)),
frames[height + height // 4:height + height // 2].reshape((height // 2, width // 2)),
dim=0,
).reshape((6, height // 2, width // 2))
def make_frame_prepare(nv12: NV12Frame, model_w, model_h):
cam_w, cam_h, stride, y_height, uv_height, _ = nv12
uv_offset = stride * y_height
stride_pad = stride - cam_w
def frame_prepare_tinygrad(input_frame, matrix_inverse):
# UV_SCALE @ M_inv @ UV_SCALE_INV simplifies to elementwise scaling.
matrix_inverse_uv = matrix_inverse * Tensor([[1.0, 1.0, 0.5], [1.0, 1.0, 0.5], [2.0, 2.0, 1.0]], device=WARP_DEV)
# Deinterleave NV12 UV plane (UVUV... -> separate U, V).
uv = input_frame[uv_offset:uv_offset + uv_height * stride].reshape(uv_height, stride)
with Context(SPLIT_REDUCEOP=0):
y = warp_perspective_tinygrad(
input_frame[:cam_h * stride],
matrix_inverse,
(model_w, model_h),
(cam_h, cam_w),
stride_pad,
).realize()
u = warp_perspective_tinygrad(
uv[:cam_h // 2, :cam_w:2].flatten(),
matrix_inverse_uv,
(model_w // 2, model_h // 2),
(cam_h // 2, cam_w // 2),
0,
).realize()
v = warp_perspective_tinygrad(
uv[:cam_h // 2, 1:cam_w:2].flatten(),
matrix_inverse_uv,
(model_w // 2, model_h // 2),
(cam_h // 2, cam_w // 2),
0,
).realize()
yuv = y.cat(u).cat(v).reshape((model_h * 3 // 2, model_w))
return frames_to_tensor(yuv)
return frame_prepare_tinygrad
def make_tensor_inputs(vision_input_shapes, policy_input_shapes, frame_skip, device):
img = vision_input_shapes["img"]
n_frames = img[1] // 6
img_buf_shape = (frame_skip * (n_frames - 1) + 1, 6, img[2], img[3])
features_buffer = policy_input_shapes["features_buffer"]
desire_pulse = policy_input_shapes["desire_pulse"]
return {
"img_q": Tensor(np.zeros(img_buf_shape, dtype=np.uint8), device=device).contiguous().realize(),
"big_img_q": Tensor(np.zeros(img_buf_shape, dtype=np.uint8), device=device).contiguous().realize(),
"feat_q": Tensor(
np.zeros((frame_skip * (features_buffer[1] - 1) + 1, features_buffer[0], features_buffer[2]), dtype=np.float32),
device=device,
).contiguous().realize(),
"desire_q": Tensor(
np.zeros((frame_skip * desire_pulse[1], desire_pulse[0], desire_pulse[2]), dtype=np.float32),
device=device,
).contiguous().realize(),
}
def make_npy_inputs(policy_input_shapes):
desire_pulse = policy_input_shapes["desire_pulse"]
traffic_convention = policy_input_shapes["traffic_convention"]
npy = {
"desire": np.zeros(desire_pulse[2], dtype=np.float32),
"traffic_convention": np.zeros(traffic_convention, dtype=np.float32),
"tfm": np.zeros((3, 3), dtype=np.float32),
"big_tfm": np.zeros((3, 3), dtype=np.float32),
}
if "action_t" in policy_input_shapes:
npy["action_t"] = np.zeros(policy_input_shapes["action_t"], dtype=np.float32)
npy_tensors = {key: Tensor(value, device="NPY").realize() for key, value in npy.items()}
return npy, npy_tensors
def make_input_queues(vision_input_shapes, policy_input_shapes, frame_skip, device):
tensor_inputs = make_tensor_inputs(vision_input_shapes, policy_input_shapes, frame_skip, device)
npy, npy_tensors = make_npy_inputs(policy_input_shapes)
return {**tensor_inputs, **npy_tensors}, npy
def shift_and_sample(buf, new_val, sample_fn):
buf.assign(buf[1:].cat(new_val, dim=0).contiguous())
return sample_fn(buf)
def sample_skip(buf, frame_skip):
return buf[::frame_skip].contiguous().flatten(0, 1).unsqueeze(0)
def sample_desire(buf, frame_skip):
return buf.reshape(-1, frame_skip, *buf.shape[1:]).max(1).flatten(0, 1).unsqueeze(0)
def make_warp(nv12, model_w, model_h, frame_skip):
frame_prepare = make_frame_prepare(nv12, model_w, model_h)
sample_skip_fn = partial(sample_skip, frame_skip=frame_skip)
def warp_enqueue(img_q, big_img_q, tfm, big_tfm, frame, big_frame):
tfm = tfm.to(WARP_DEV)
big_tfm = big_tfm.to(WARP_DEV)
Tensor.realize(tfm, big_tfm)
warped_frame = frame_prepare(frame, tfm).unsqueeze(0).to(Device.DEFAULT)
warped_big_frame = frame_prepare(big_frame, big_tfm).unsqueeze(0).to(Device.DEFAULT)
img = shift_and_sample(img_q, warped_frame, sample_skip_fn)
big_img = shift_and_sample(big_img_q, warped_big_frame, sample_skip_fn)
return img, big_img
return warp_enqueue
def make_run_policy(vision_runner, off_policy_runner, on_policy_runner, vision_features_slice, frame_skip):
sample_desire_fn = partial(sample_desire, frame_skip=frame_skip)
sample_skip_fn = partial(sample_skip, frame_skip=frame_skip)
def run_policy(img, big_img, feat_q, desire_q, desire, traffic_convention, action_t):
desire = desire.to(Device.DEFAULT)
traffic_convention = traffic_convention.to(Device.DEFAULT)
action_t = action_t.to(Device.DEFAULT)
Tensor.realize(desire, traffic_convention, action_t)
desire_buf = shift_and_sample(desire_q, desire.reshape(1, 1, -1), sample_desire_fn)
vision_out = next(iter(vision_runner({"img": img, "big_img": big_img}).values())).cast("float32")
new_feat = vision_out[:, vision_features_slice].reshape(1, -1).unsqueeze(0)
feat_buf = shift_and_sample(feat_q, new_feat, sample_skip_fn)
inputs = {
"features_buffer": feat_buf,
"desire_pulse": desire_buf,
"traffic_convention": traffic_convention,
"action_t": action_t,
}
on_policy_out = next(iter(on_policy_runner(inputs).values())).cast("float32")
off_policy_out = next(iter(off_policy_runner(inputs).values())).cast("float32")
return vision_out, on_policy_out, off_policy_out
return run_policy
def compile_jit(jit, make_random_inputs, input_keys, frame_skip, vision_metadata, policy_metadata):
vision_input_shapes = vision_metadata["input_shapes"]
policy_input_shapes = policy_metadata["input_shapes"]
seed = 42
validation_rtol = 5e-3 if Device.DEFAULT == "QCOM" else 0.0
validation_atol = 5e-3 if Device.DEFAULT == "QCOM" else 0.0
def arrays_match(lhs, rhs):
if lhs.shape != rhs.shape:
return False
if np.issubdtype(lhs.dtype, np.floating) or np.issubdtype(rhs.dtype, np.floating):
return np.allclose(lhs, rhs, rtol=validation_rtol, atol=validation_atol, equal_nan=True)
return np.array_equal(lhs, rhs)
def random_inputs_run(fn, current_seed, test_val=None, test_buffers=None, expect_match=True):
input_queues, npy = make_input_queues(vision_input_shapes, policy_input_shapes, frame_skip, Device.DEFAULT)
np.random.seed(current_seed)
Tensor.manual_seed(current_seed)
testing = test_val is not None or test_buffers is not None
n_runs = 1 if testing else 3
for idx in range(n_runs):
for value in npy.values():
value[:] = np.random.randn(*value.shape).astype(value.dtype)
Device.default.synchronize()
random_inputs = make_random_inputs()
start = time.perf_counter()
outs = fn(**{key: input_queues[key] for key in input_keys}, **random_inputs)
mid = time.perf_counter()
Device.default.synchronize()
end = time.perf_counter()
print(f" [{idx + 1}/{n_runs}] enqueue {(mid - start) * 1e3:6.2f} ms -- total {(end - start) * 1e3:6.2f} ms")
if idx == 0:
val = [np.copy(value.numpy()) for value in outs]
buffers = [np.copy(value.numpy().copy()) for value in input_queues.values()]
if Device.DEFAULT != "QCOM":
if test_val is not None:
match = all(arrays_match(lhs, rhs) for lhs, rhs in zip(val, test_val, strict=True))
assert match == expect_match, f"outputs {'differ from' if expect_match else 'match'} baseline (seed={current_seed})"
if test_buffers is not None:
match = all(arrays_match(lhs, rhs) for lhs, rhs in zip(buffers, test_buffers, strict=True))
assert match == expect_match, f"buffers {'differ from' if expect_match else 'match'} baseline (seed={current_seed})"
return val, buffers
print("capture + replay")
test_val, test_buffers = random_inputs_run(jit, seed)
print("pickle round trip")
jit = pickle.loads(pickle.dumps(jit))
random_inputs_run(jit, seed, test_val, test_buffers, expect_match=True)
random_inputs_run(jit, seed + 1, test_val, test_buffers, expect_match=False)
return jit
def _parse_size(size):
width, height = size.lower().split("x")
return int(width), int(height)
def read_file_chunked_to_shm(path):
from openpilot.common.file_chunker import read_file_chunked
from openpilot.system.hardware.hw import Paths
shm_path = os.path.join(Paths.shm_path(), os.path.basename(path))
atexit.register(lambda: os.path.exists(shm_path) and os.remove(shm_path))
with open(shm_path, "wb") as f:
f.write(read_file_chunked(path))
return shm_path
if __name__ == "__main__":
from tinygrad.nn.onnx import OnnxRunner
from openpilot.selfdrive.modeld.get_model_metadata import make_metadata_dict
from openpilot.system.camerad.cameras.nv12_info import get_nv12_info
parser = argparse.ArgumentParser()
parser.add_argument("--model-size", type=_parse_size, required=True, help="model input WxH")
parser.add_argument("--camera-resolutions", type=_parse_size, nargs="+", required=True, help="camera resolutions WxH (one or more)")
parser.add_argument("--vision-onnx", required=True)
parser.add_argument("--off-policy-onnx", required=True)
parser.add_argument("--on-policy-onnx", required=True)
parser.add_argument("--output", required=True)
parser.add_argument("--frame-skip", type=int, required=True)
args = parser.parse_args()
out = defaultdict(dict)
vision_path = read_file_chunked_to_shm(args.vision_onnx)
off_policy_path = read_file_chunked_to_shm(args.off_policy_onnx)
on_policy_path = read_file_chunked_to_shm(args.on_policy_onnx)
model_w, model_h = args.model_size
vision_runner = OnnxRunner(vision_path)
off_policy_runner = OnnxRunner(off_policy_path)
on_policy_runner = OnnxRunner(on_policy_path)
vision_metadata = make_metadata_dict(vision_path)
off_policy_metadata = make_metadata_dict(off_policy_path)
on_policy_metadata = make_metadata_dict(on_policy_path)
assert off_policy_metadata["input_shapes"] == on_policy_metadata["input_shapes"]
run_policy_jit = TinyJit(
make_run_policy(
vision_runner,
off_policy_runner,
on_policy_runner,
vision_metadata["output_slices"]["hidden_state"],
args.frame_skip,
),
prune=True,
)
out["metadata"]["vision"] = vision_metadata
out["metadata"]["off_policy"] = off_policy_metadata
out["metadata"]["on_policy"] = on_policy_metadata
out["tensor_inputs"] = make_tensor_inputs(vision_metadata["input_shapes"], on_policy_metadata["input_shapes"], args.frame_skip, Device.DEFAULT)
make_random_model_inputs = partial(make_random_images, keys=["img", "big_img"], shape=vision_metadata["input_shapes"]["img"])
out["run_policy"] = compile_jit(run_policy_jit, make_random_model_inputs, POLICY_INPUTS, args.frame_skip, vision_metadata, on_policy_metadata)
for cam_w, cam_h in args.camera_resolutions:
nv12 = NV12Frame(cam_w, cam_h, *get_nv12_info(cam_w, cam_h))
# Capture warp against blob-backed frames so the JIT ABI matches runtime VisionBuf inputs.
make_random_warp_inputs = partial(make_random_blob_images, keys=["frame", "big_frame"], shape=nv12.size, device=WARP_DEV)
warp_enqueue = TinyJit(make_warp(nv12, model_w, model_h, args.frame_skip), prune=True)
out[(cam_w, cam_h)] = compile_jit(warp_enqueue, make_random_warp_inputs, WARP_INPUTS, args.frame_skip, vision_metadata, on_policy_metadata)
with open(args.output, "wb") as f:
pickle.dump(out, f)
print(f"Saved JITs to {args.output} ({os.path.getsize(args.output) / 1e6:.2f} MB)")
+15 -5
View File
@@ -66,7 +66,7 @@ def dm_warp_pkl_path(w, h):
return MODELS_DIR / f'dm_warp_{w}x{h}_tinygrad.pkl'
def warp_perspective_tinygrad(src_flat, M_inv, dst_shape, src_shape, stride_pad):
def warp_perspective_tinygrad(src_flat, M_inv, dst_shape, src_shape, stride_pad, border_fill_val=None):
w_dst, h_dst = dst_shape
h_src, w_src = src_shape
@@ -81,11 +81,19 @@ def warp_perspective_tinygrad(src_flat, M_inv, dst_shape, src_shape, stride_pad)
src_x = src_x / src_w
src_y = src_y / src_w
x_nn_clipped = Tensor.round(src_x).clip(0, w_src - 1).cast('int')
y_nn_clipped = Tensor.round(src_y).clip(0, h_src - 1).cast('int')
x_round = Tensor.round(src_x)
y_round = Tensor.round(src_y)
x_nn_clipped = x_round.clip(0, w_src - 1).cast('int')
y_nn_clipped = y_round.clip(0, h_src - 1).cast('int')
idx = y_nn_clipped * (w_src + stride_pad) + x_nn_clipped
return src_flat[idx]
sampled = src_flat[idx]
if border_fill_val is None:
return sampled
in_bounds = ((x_round >= 0) & (x_round <= w_src - 1) &
(y_round >= 0) & (y_round <= h_src - 1)).cast(sampled.dtype)
return sampled * in_bounds + Tensor(border_fill_val, dtype=sampled.dtype) * (1 - in_bounds)
def frames_to_tensor(frames, model_w, model_h):
@@ -152,7 +160,9 @@ def make_warp_dm(cam_w, cam_h, dm_w, dm_h):
def warp_dm(input_frame, M_inv):
M_inv = M_inv.to(Device.DEFAULT)
result = warp_perspective_tinygrad(input_frame[:cam_h*stride], M_inv, (dm_w, dm_h), (cam_h, cam_w), stride_pad).reshape(-1, dm_h * dm_w)
result = warp_perspective_tinygrad(
input_frame[:cam_h*stride], M_inv, (dm_w, dm_h), (cam_h, cam_w), stride_pad, border_fill_val=16
).reshape(-1, dm_h * dm_w)
return result
return warp_dm
+6
View File
@@ -80,6 +80,11 @@ def parse_model_output(model_output):
parsed[f'face_descs_{ds_suffix}_std'] = safe_exp(face_descs[:, -6:])
for key in ['face_prob', 'left_eye_prob', 'right_eye_prob', 'left_blink_prob', 'right_blink_prob', 'sunglasses_prob', 'using_phone_prob']:
parsed[f'{key}_{ds_suffix}'] = sigmoid(model_output[f'{key}_{ds_suffix}'])
sleep_key = f'sleep_prob_{ds_suffix}'
if sleep_key in model_output:
parsed[sleep_key] = sigmoid(model_output[sleep_key])
else:
parsed[sleep_key] = np.zeros((1, 1), dtype=np.float32)
return parsed
@@ -95,6 +100,7 @@ def fill_driver_data(msg, model_output, ds_suffix):
msg.rightBlinkProb = model_output[f'right_blink_prob_{ds_suffix}'][0, 0].item()
msg.sunglassesProb = model_output[f'sunglasses_prob_{ds_suffix}'][0, 0].item()
msg.phoneProb = model_output[f'using_phone_prob_{ds_suffix}'][0, 0].item()
msg.sleepProb = model_output[f'sleep_prob_{ds_suffix}'][0, 0].item()
def get_driverstate_packet(model_output, frame_id: int, location_ts: int, exec_time: float, gpu_exec_time: float):
+12 -7
View File
@@ -1,11 +1,12 @@
#!/usr/bin/env python3
import sys
import pathlib
import onnx
import codecs
import pickle
import pathlib
import sys
from typing import Any
import onnx
def get_name_and_shape(value_info:onnx.ValueInfoProto) -> tuple[str, tuple[int,...]]:
shape = tuple([int(dim.dim_value) for dim in value_info.type.tensor_type.shape.dim])
name = value_info.name
@@ -17,19 +18,23 @@ def get_metadata_value_by_name(model:onnx.ModelProto, name:str) -> str | Any:
return prop.value
return None
if __name__ == "__main__":
model_path = pathlib.Path(sys.argv[1])
def make_metadata_dict(model_path: str | pathlib.Path) -> dict[str, Any]:
model = onnx.load(str(model_path))
output_slices = get_metadata_value_by_name(model, 'output_slices')
assert output_slices is not None, 'output_slices not found in metadata'
metadata = {
return {
'model_checkpoint': get_metadata_value_by_name(model, 'model_checkpoint'),
'output_slices': pickle.loads(codecs.decode(output_slices.encode(), "base64")),
'input_shapes': dict([get_name_and_shape(x) for x in model.graph.input]),
'output_shapes': dict([get_name_and_shape(x) for x in model.graph.output])
'output_shapes': dict([get_name_and_shape(x) for x in model.graph.output]),
}
if __name__ == "__main__":
model_path = pathlib.Path(sys.argv[1])
metadata = make_metadata_dict(model_path)
metadata_path = model_path.parent / (model_path.stem + '_metadata.pkl')
with open(metadata_path, 'wb') as f:
pickle.dump(metadata, f)
+73
View File
@@ -0,0 +1,73 @@
import json
import os
from pathlib import Path
from tinygrad.device import Device
MODELS_DIR = Path(__file__).resolve().parent / "models"
TG_INPUT_DEVICES_PATH = MODELS_DIR / "tg_input_devices.json"
USBGPU_VID = 0xADD1
USBGPU_PID = 0x0001
def _default_tinygrad_backend() -> str:
env_dev = os.getenv("DEV", "").strip()
if env_dev:
return env_dev.split(":", 1)[0].split("+", 1)[-1] or env_dev
try:
default = Device.DEFAULT
except Exception:
default = ""
if isinstance(default, str) and default:
return default.split(":", 1)[0].split("+", 1)[-1] or default
return "QCOM" if Path("/dev/kgsl-3d0").exists() else "CPU"
def _load_tg_devices() -> dict:
if not TG_INPUT_DEVICES_PATH.is_file():
return {}
with open(TG_INPUT_DEVICES_PATH) as f:
return json.load(f)
def _fallback_tg_devices(process_name: str, usbgpu: bool) -> dict[str, str]:
backend = _default_tinygrad_backend()
if process_name == "selfdrive.modeld.dmonitoringmodeld":
return {"DEV": backend}
queue_dev = backend
if usbgpu:
try:
available = {name.split(":", 1)[0] for name in Device.get_available_devices()}
except Exception:
available = set()
if "AMD" in available:
queue_dev = "AMD"
return {"WARP_DEV": backend, "QUEUE_DEV": queue_dev}
def get_tg_input_devices(process_name: str, usbgpu: bool) -> dict[str, str]:
tg_devices = _load_tg_devices()
process_devices = tg_devices.get(process_name, {})
profile = "usbgpu" if usbgpu else "default"
if profile in process_devices:
return process_devices[profile]
return _fallback_tg_devices(process_name, usbgpu)
def modeld_pkl_path(usbgpu: bool):
prefix = "big_" if usbgpu else ""
return MODELS_DIR / f"{prefix}driving_tinygrad.pkl"
def usbgpu_present() -> bool:
for d in Path("/sys/bus/usb/devices").glob("*"):
try:
if int((d / "idVendor").read_text(), 16) == USBGPU_VID and \
int((d / "idProduct").read_text(), 16) == USBGPU_PID:
return True
except Exception:
pass
return False
+17 -7
View File
@@ -28,6 +28,11 @@ from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_
from openpilot.selfdrive.modeld.constants import ModelConstants, Plan
from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext
from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address
from openpilot.starpilot.common.model_versions import (
is_tinygrad_model_version,
uses_combined_driving_artifacts,
uses_split_off_policy_artifacts,
)
from openpilot.starpilot.common.starpilot_variables import get_starpilot_toggles, MODELS_PATH, params_memory
@@ -309,7 +314,7 @@ class ModelState:
self.is_v14 = (self.policy_generation == "v14")
self.is_v15 = (self.policy_generation == "v15")
self.is_v9 = (self.policy_generation == "v9")
self.mlsim = (self.policy_generation in ("v8", "v10", "v11", "v12", "v13", "v14", "v15"))
self.mlsim = is_tinygrad_model_version(self.policy_generation)
self.policy_has_plan = 'plan' in self.policy_output_slices
self.frames = {name: DrivingModelFrame(context, ModelConstants.TEMPORAL_SKIP) for name in self.vision_input_names}
@@ -334,7 +339,7 @@ class ModelState:
self.off_policy_output: np.ndarray | None = None
off_policy_metadata = None
if self.policy_generation in ("v12", "v13", "v14", "v15") or OFF_POLICY_METADATA_PATH.is_file() or OFF_POLICY_PKL_PATH.is_file():
if uses_split_off_policy_artifacts(self.policy_generation) or OFF_POLICY_METADATA_PATH.is_file() or OFF_POLICY_PKL_PATH.is_file():
resolved_off_policy_meta = ensure_artifact(OFF_POLICY_METADATA_PATH, "driving_off_policy_metadata.pkl", optional=True)
if resolved_off_policy_meta is not None:
with open(resolved_off_policy_meta, 'rb') as f:
@@ -453,14 +458,14 @@ class ModelState:
self.full_prev_desired_curv[0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
if self.prev_desired_curv_key is not None:
# v9/v10/v11/v12/v13/v14/v15 models expect zeros for prev_desired_curv(s); others use history
if self.is_v9 or self.is_v10 or self.is_v11 or self.is_v12 or self.is_v13 or self.is_v14 or self.is_v15:
# Tinygrad-era policy models expect zeros for prev_desired_curv(s); older ones use history.
if is_tinygrad_model_version(self.policy_generation):
self.numpy_inputs[self.prev_desired_curv_key][:] = 0 * self.full_prev_desired_curv[0, self.temporal_idxs]
else:
self.numpy_inputs[self.prev_desired_curv_key][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
if self.off_policy_enabled and self.off_policy_prev_desired_curv_key is not None:
if self.is_v9 or self.is_v12 or self.is_v13 or self.is_v14 or self.is_v15:
if self.is_v9 or uses_split_off_policy_artifacts(self.policy_generation) or uses_combined_driving_artifacts(self.policy_generation):
self.off_policy_numpy_inputs[self.off_policy_prev_desired_curv_key][:] = 0 * self.full_prev_desired_curv[0, self.temporal_idxs]
else:
self.off_policy_numpy_inputs[self.off_policy_prev_desired_curv_key][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
@@ -486,6 +491,13 @@ class ModelState:
def main(demo=False):
params = Params()
selected_version = _resolve_mirrored_param(params, "ModelVersion", "DrivingModelVersion")
if uses_combined_driving_artifacts(selected_version):
from openpilot.selfdrive.modeld.modeld_v16 import main as combined_main
return combined_main(demo=demo)
cloudlog.warning("modeld init")
sentry.set_tag("daemon", PROCESS_NAME)
@@ -527,8 +539,6 @@ def main(demo=False):
sm = SubMaster(["deviceState", "carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "carControl", "liveDelay", "starpilotPlan"])
publish_state = PublishState()
params = Params()
# setup filter to track dropped frames
frame_dropped_filter = FirstOrderFilter(0., 10., 1. / ModelConstants.MODEL_FREQ)
frame_id = 0
+459
View File
@@ -0,0 +1,459 @@
#!/usr/bin/env python3
from __future__ import annotations
import os
import pickle
import time
from pathlib import Path
from openpilot.system.hardware import TICI
os.environ["GMMU"] = "0" # noop on qcom, improves load path when a USB GPU is present
os.environ["DEV"] = "QCOM" if TICI else "LLVM"
import cereal.messaging as messaging
import numpy as np
from cereal import car, log
from msgq.visionipc import VisionBuf, VisionIpcClient, VisionStreamType
from opendbc.car.car_helpers import get_demo_car_params
from setproctitle import setproctitle
from tinygrad.tensor import Tensor
from openpilot.common.file_chunker import read_file_chunked
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.params import Params
from openpilot.common.realtime import DT_MDL, config_realtime_process
from openpilot.common.swaglog import cloudlog
from openpilot.common.transformations.camera import DEVICE_CAMERAS
from openpilot.common.transformations.model import get_warp_matrix
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
from openpilot.selfdrive.controls.lib.drive_helpers import smooth_value
from openpilot.selfdrive.modeld.compile_modeld import POLICY_INPUTS, WARP_INPUTS, make_npy_inputs, make_tensor_inputs
from openpilot.selfdrive.modeld.constants import ModelConstants
from openpilot.selfdrive.modeld.fill_model_msg import PublishState, fill_model_msg, fill_pose_msg
from openpilot.selfdrive.modeld.helpers import get_tg_input_devices
from openpilot.selfdrive.modeld.parse_model_outputs import Parser
from openpilot.starpilot.assets.model_manager import ModelManager
from openpilot.starpilot.common.model_versions import uses_combined_driving_artifacts
from openpilot.starpilot.common.starpilot_variables import MODELS_PATH, get_starpilot_toggles, params_memory
from openpilot.system import sentry
from openpilot.system.camerad.cameras.nv12_info import get_nv12_info
PROCESS_NAME = "selfdrive.modeld.modeld"
SEND_RAW_PRED = os.getenv("SEND_RAW_PRED")
BUILTIN_MODEL_KEY = "sc2"
BUILTIN_MODEL_ALIASES = {BUILTIN_MODEL_KEY, "sc"}
LAT_SMOOTH_SECONDS = 0.0
LONG_SMOOTH_SECONDS = 0.3
MIN_LAT_CONTROL_SPEED = 0.3
def _get_param_str(params: Params, key: str, default: str = "") -> str:
try:
value = params.get(key)
except Exception:
return default
if value is None:
return default
if isinstance(value, bytes):
try:
return value.decode("utf-8")
except Exception:
return default
if isinstance(value, (dict, list)):
return default
return str(value)
def _get_default_param_str(params: Params, key: str) -> str:
try:
value = params.get_default_value(key)
except Exception:
return ""
if value is None:
return ""
if isinstance(value, bytes):
try:
return value.decode("utf-8")
except Exception:
return ""
return str(value)
def _resolve_mirrored_param(params: Params, primary_key: str, secondary_key: str) -> str:
primary_val = _get_param_str(params, primary_key).strip()
secondary_val = _get_param_str(params, secondary_key).strip()
if primary_val == secondary_val:
return secondary_val or primary_val
primary_default = _get_default_param_str(params, primary_key).strip()
secondary_default = _get_default_param_str(params, secondary_key).strip()
primary_non_default = bool(primary_val) and primary_val != primary_default
secondary_non_default = bool(secondary_val) and secondary_val != secondary_default
if secondary_non_default:
return secondary_val
if primary_non_default:
return primary_val
return secondary_val or primary_val
def _canonical_model_id(model_id: str) -> str:
key = (model_id or "").strip().lower()
return BUILTIN_MODEL_KEY if key in BUILTIN_MODEL_ALIASES else key
def _combined_model_path(model_id: str, use_builtin_model: bool) -> Path:
if use_builtin_model:
return Path(__file__).parent / "models" / "driving_tinygrad.pkl"
return MODELS_PATH / f"{model_id}_driving_tinygrad.pkl"
def get_action_from_model(model_output: dict[str, np.ndarray], prev_action: log.ModelDataV2.Action, v_ego: float) -> log.ModelDataV2.Action:
desired_curv_unscaled, desired_accel = model_output["action"][0]
desired_curvature = float(desired_curv_unscaled) / max(1.0, v_ego) ** 2
should_stop = (v_ego < 0.3 and desired_accel < 0.1)
desired_accel = smooth_value(float(desired_accel), prev_action.desiredAcceleration, LONG_SMOOTH_SECONDS)
if v_ego > MIN_LAT_CONTROL_SPEED:
desired_curvature = smooth_value(desired_curvature, prev_action.desiredCurvature, LAT_SMOOTH_SECONDS)
else:
desired_curvature = prev_action.desiredCurvature
return log.ModelDataV2.Action(
desiredCurvature=float(desired_curvature),
desiredAcceleration=float(desired_accel),
shouldStop=bool(should_stop),
)
class FrameMeta:
frame_id: int = 0
timestamp_sof: int = 0
timestamp_eof: int = 0
def __init__(self, vipc=None):
if vipc is not None:
self.frame_id, self.timestamp_sof, self.timestamp_eof = vipc.frame_id, vipc.timestamp_sof, vipc.timestamp_eof
class ModelState:
prev_desire: np.ndarray
def __init__(self, cam_w: int, cam_h: int, usbgpu: bool):
params = Params()
model_id_raw = _resolve_mirrored_param(params, "Model", "DrivingModel") or BUILTIN_MODEL_KEY
self.model_id = _canonical_model_id(model_id_raw)
self.model_version = _resolve_mirrored_param(params, "ModelVersion", "DrivingModelVersion")
if not uses_combined_driving_artifacts(self.model_version):
raise ValueError(f"Combined runtime requested for non-combined version {self.model_version!r}")
use_builtin_model = self.model_id == BUILTIN_MODEL_KEY
model_path = _combined_model_path(self.model_id, use_builtin_model)
if not model_path.is_file():
if use_builtin_model:
raise FileNotFoundError(
f"Missing builtin combined model artifact: {model_path}. "
"Rebuild/deploy the combined builtin model before selecting this version."
)
cloudlog.error(f"Missing combined model artifact {model_path}, downloading {self.model_id}...")
ModelManager(params, params_memory).download_model(self.model_id)
if not model_path.is_file():
raise FileNotFoundError(model_path)
jits = pickle.loads(read_file_chunked(model_path))
vision_metadata = jits["metadata"]["vision"]
off_policy_metadata = jits["metadata"]["off_policy"]
on_policy_metadata = jits["metadata"]["on_policy"]
self.vision_input_shapes = vision_metadata["input_shapes"]
self.vision_input_names = list(self.vision_input_shapes.keys())
self.vision_output_slices = vision_metadata["output_slices"]
self.off_policy_output_slices = off_policy_metadata["output_slices"]
self.policy_input_shapes = on_policy_metadata["input_shapes"]
self.policy_output_slices = on_policy_metadata["output_slices"]
self.desire_key = "desire_pulse" if "desire_pulse" in self.policy_input_shapes else next(
key for key in self.policy_input_shapes if key.startswith("desire")
)
self.frame_skip = ModelConstants.MODEL_RUN_FREQ // ModelConstants.MODEL_CONTEXT_FREQ
input_devices = get_tg_input_devices(PROCESS_NAME, usbgpu)
self.WARP_DEV, self.QUEUE_DEV = input_devices["WARP_DEV"], input_devices["QUEUE_DEV"]
tensor_inputs = jits.get("tensor_inputs")
if tensor_inputs is None:
tensor_inputs = make_tensor_inputs(self.vision_input_shapes, self.policy_input_shapes, self.frame_skip, device=self.QUEUE_DEV)
self.npy, npy_tensors = make_npy_inputs(self.policy_input_shapes)
self.input_queues = {**tensor_inputs, **npy_tensors}
self.full_frames: dict[str, Tensor] = {}
self._blob_cache: dict[tuple[str, int], Tensor] = {}
self.parser = Parser()
self.frame_buf_params = {key: get_nv12_info(cam_w, cam_h) for key in ("img", "big_img")}
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
camera_jit = jits[(cam_w, cam_h)]
self.split_warp_layout = "run_policy" in jits and not isinstance(camera_jit, dict)
if self.split_warp_layout:
self.run_policy = jits["run_policy"]
self.warp_enqueue = camera_jit
else:
self.run_policy = camera_jit["run_policy"]
self.warp_enqueue = camera_jit["warp_enqueue"]
def slice_outputs(self, model_outputs: np.ndarray, output_slices: dict[str, slice]) -> dict[str, np.ndarray]:
return {key: model_outputs[np.newaxis, value] for key, value in output_slices.items()}
def run(self, bufs: dict[str, VisionBuf], transforms: dict[str, np.ndarray], inputs: dict[str, np.ndarray], prepare_only: bool) -> dict[str, np.ndarray] | None:
for key in bufs.keys():
ptr = np.frombuffer(bufs[key].data, dtype=np.uint8).ctypes.data
yuv_size = self.frame_buf_params[key][3]
cache_key = (key, ptr)
if cache_key not in self._blob_cache:
self._blob_cache[cache_key] = Tensor.from_blob(ptr, (yuv_size,), dtype="uint8", device=self.WARP_DEV)
self.full_frames[key] = self._blob_cache[cache_key]
inputs[self.desire_key][0] = 0
self.npy["desire"][:] = np.where(inputs[self.desire_key] - self.prev_desire > 0.99, inputs[self.desire_key], 0)
self.prev_desire[:] = inputs[self.desire_key]
self.npy["traffic_convention"][:] = inputs["traffic_convention"]
if "action_t" in self.npy:
self.npy["action_t"][:] = inputs["action_t"]
self.npy["tfm"][:, :] = transforms["img"][:, :]
self.npy["big_tfm"][:, :] = transforms["big_img"][:, :]
if self.split_warp_layout:
img, big_img = self.warp_enqueue(
**{key: self.input_queues[key] for key in WARP_INPUTS},
frame=self.full_frames["img"],
big_frame=self.full_frames["big_img"],
)
if prepare_only:
return None
policy_inputs = {key: self.input_queues[key] for key in POLICY_INPUTS if key in self.input_queues}
vision_output, policy_output, off_policy_output = self.run_policy(**policy_inputs, img=img, big_img=big_img)
else:
if prepare_only:
self.warp_enqueue(**self.input_queues, frame=self.full_frames["img"], big_frame=self.full_frames["big_img"])
return None
vision_output, policy_output, off_policy_output = self.run_policy(
**self.input_queues,
frame=self.full_frames["img"],
big_frame=self.full_frames["big_img"],
)
vision_output = vision_output.numpy().flatten()
policy_output = policy_output.numpy().flatten()
off_policy_output = off_policy_output.numpy().flatten()
vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(vision_output, self.vision_output_slices))
off_policy_outputs_dict = self.parser.parse_off_policy_outputs(self.slice_outputs(off_policy_output, self.off_policy_output_slices))
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(policy_output, self.policy_output_slices))
combined_outputs_dict = {**vision_outputs_dict, **off_policy_outputs_dict, **policy_outputs_dict}
if SEND_RAW_PRED:
combined_outputs_dict["raw_pred"] = np.concatenate([vision_output.copy(), policy_output.copy(), off_policy_output.copy()])
return combined_outputs_dict
def main(demo=False):
cloudlog.warning("modeld init")
sentry.set_tag("daemon", PROCESS_NAME)
cloudlog.bind(daemon=PROCESS_NAME)
setproctitle(PROCESS_NAME)
config_realtime_process(7, 54)
# Combined downloaded models currently ship one runtime artifact, so stay on the default
# queue profile until a separate USBGPU artifact path exists for custom models.
usbgpu = False
while True:
available_streams = VisionIpcClient.available_streams("camerad", block=False)
if available_streams:
use_extra_client = VisionStreamType.VISION_STREAM_WIDE_ROAD in available_streams and VisionStreamType.VISION_STREAM_ROAD in available_streams
main_wide_camera = VisionStreamType.VISION_STREAM_ROAD not in available_streams
break
time.sleep(0.1)
vipc_client_main_stream = VisionStreamType.VISION_STREAM_WIDE_ROAD if main_wide_camera else VisionStreamType.VISION_STREAM_ROAD
vipc_client_main = VisionIpcClient("camerad", vipc_client_main_stream, True)
vipc_client_extra = VisionIpcClient("camerad", VisionStreamType.VISION_STREAM_WIDE_ROAD, False)
cloudlog.warning(f"vision stream set up, main_wide_camera: {main_wide_camera}, use_extra_client: {use_extra_client}")
while not vipc_client_main.connect(False):
time.sleep(0.1)
while use_extra_client and not vipc_client_extra.connect(False):
time.sleep(0.1)
cloudlog.warning(f"connected main cam with buffer size: {vipc_client_main.buffer_len} ({vipc_client_main.width} x {vipc_client_main.height})")
if use_extra_client:
cloudlog.warning(f"connected extra cam with buffer size: {vipc_client_extra.buffer_len} ({vipc_client_extra.width} x {vipc_client_extra.height})")
start_time = time.monotonic()
cloudlog.warning("loading combined model")
model = ModelState(vipc_client_main.width, vipc_client_main.height, usbgpu)
cloudlog.warning(f"combined model loaded in {time.monotonic() - start_time:.1f}s, modeld starting")
pm = messaging.PubMaster(["modelV2", "drivingModelData", "cameraOdometry", "starpilotModelV2"])
sm = messaging.SubMaster(["deviceState", "carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "carControl", "liveDelay", "starpilotPlan"])
publish_state = PublishState()
params = Params()
frame_dropped_filter = FirstOrderFilter(0.0, 10.0, 1.0 / ModelConstants.MODEL_RUN_FREQ)
last_vipc_frame_id = 0
run_count = 0
model_transform_main = np.zeros((3, 3), dtype=np.float32)
model_transform_extra = np.zeros((3, 3), dtype=np.float32)
live_calib_seen = False
buf_main, buf_extra = None, None
meta_main = FrameMeta()
meta_extra = FrameMeta()
if demo:
CP = get_demo_car_params()
else:
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)
cloudlog.info("modeld got CarParams: %s", CP.brand)
long_delay = CP.longitudinalActuatorDelay + LONG_SMOOTH_SECONDS
prev_action = log.ModelDataV2.Action()
desire_helper = DesireHelper()
starpilot_toggles = get_starpilot_toggles(sm)
while True:
while meta_main.timestamp_sof < meta_extra.timestamp_sof + 25000000:
buf_main = vipc_client_main.recv()
meta_main = FrameMeta(vipc_client_main)
if buf_main is None:
break
if buf_main is None:
cloudlog.debug("vipc_client_main no frame")
continue
if use_extra_client:
while True:
buf_extra = vipc_client_extra.recv()
meta_extra = FrameMeta(vipc_client_extra)
if buf_extra is None or meta_main.timestamp_sof < meta_extra.timestamp_sof + 25000000:
break
if buf_extra is None:
cloudlog.debug("vipc_client_extra no frame")
continue
if abs(meta_main.timestamp_sof - meta_extra.timestamp_sof) > 10000000:
cloudlog.error(
f"frames out of sync! main: {meta_main.frame_id} ({meta_main.timestamp_sof / 1e9:.5f}), "
f"extra: {meta_extra.frame_id} ({meta_extra.timestamp_sof / 1e9:.5f})"
)
else:
buf_extra = buf_main
meta_extra = meta_main
sm.update(0)
desire = desire_helper.desire
is_rhd = sm["driverMonitoringState"].isRHD
frame_id = sm["roadCameraState"].frameId
v_ego = max(sm["carState"].vEgo, 0.0)
lat_delay = sm["liveDelay"].lateralDelay + LAT_SMOOTH_SECONDS
if sm.updated["liveCalibration"] and sm.seen["roadCameraState"] and sm.seen["deviceState"]:
device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32)
dc = DEVICE_CAMERAS[(str(sm["deviceState"].deviceType), str(sm["roadCameraState"].sensor))]
model_transform_main = get_warp_matrix(
device_from_calib_euler,
dc.ecam.intrinsics if main_wide_camera else dc.fcam.intrinsics,
False,
).astype(np.float32)
model_transform_extra = get_warp_matrix(device_from_calib_euler, dc.ecam.intrinsics, True).astype(np.float32)
live_calib_seen = True
traffic_convention = np.zeros(2, dtype=np.float32)
traffic_convention[int(is_rhd)] = 1
vec_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
if 0 <= desire < ModelConstants.DESIRE_LEN:
vec_desire[desire] = 1
vipc_dropped_frames = max(0, meta_main.frame_id - last_vipc_frame_id - 1)
frames_dropped = frame_dropped_filter.update(min(vipc_dropped_frames, 10))
if run_count < 10:
frame_dropped_filter.x = 0.0
frames_dropped = 0.0
run_count += 1
frame_drop_ratio = frames_dropped / (1 + frames_dropped)
prepare_only = vipc_dropped_frames > 0
if prepare_only:
cloudlog.error(f"skipping model eval. Dropped {vipc_dropped_frames} frames")
bufs = {name: buf_extra if "big" in name else buf_main for name in model.vision_input_names}
transforms = {name: model_transform_extra if "big" in name else model_transform_main for name in model.vision_input_names}
frame_delay = DT_MDL
action_delay = DT_MDL / 2
lat_action_t = lat_delay + frame_delay + action_delay
long_action_t = long_delay + frame_delay + action_delay
inputs: dict[str, np.ndarray] = {
model.desire_key: vec_desire,
"traffic_convention": traffic_convention,
}
if "action_t" in model.npy:
inputs["action_t"] = np.array([lat_action_t, long_action_t], dtype=np.float32)
start = time.perf_counter()
model_output = model.run(bufs, transforms, inputs, prepare_only)
end = time.perf_counter()
model_execution_time = end - start
if model_output is not None:
modelv2_send = messaging.new_message("modelV2")
starpilot_modelv2_send = messaging.new_message("starpilotModelV2")
drivingdata_send = messaging.new_message("drivingModelData")
posenet_send = messaging.new_message("cameraOdometry")
action = get_action_from_model(model_output, prev_action, v_ego)
prev_action = action
fill_model_msg(
drivingdata_send,
modelv2_send,
model_output,
action,
publish_state,
meta_main.frame_id,
meta_extra.frame_id,
frame_id,
frame_drop_ratio,
meta_main.timestamp_eof,
model_execution_time,
live_calib_seen,
)
desire_state = modelv2_send.modelV2.meta.desireState
l_lane_change_prob = desire_state[log.Desire.laneChangeLeft]
r_lane_change_prob = desire_state[log.Desire.laneChangeRight]
lane_change_prob = l_lane_change_prob + r_lane_change_prob
desire_helper.update(sm["carState"], sm["carControl"].latActive, lane_change_prob, sm["starpilotPlan"], starpilot_toggles)
modelv2_send.modelV2.meta.laneChangeState = desire_helper.lane_change_state
modelv2_send.modelV2.meta.laneChangeDirection = desire_helper.lane_change_direction
starpilot_modelv2_send.starpilotModelV2.turnDirection = desire_helper.turn_direction
drivingdata_send.drivingModelData.meta.laneChangeState = desire_helper.lane_change_state
drivingdata_send.drivingModelData.meta.laneChangeDirection = desire_helper.lane_change_direction
fill_pose_msg(posenet_send, model_output, meta_main.frame_id, vipc_dropped_frames, meta_main.timestamp_eof, live_calib_seen)
pm.send("modelV2", modelv2_send)
pm.send("starpilotModelV2", starpilot_modelv2_send)
pm.send("drivingModelData", drivingdata_send)
pm.send("cameraOdometry", posenet_send)
last_vipc_frame_id = meta_main.frame_id
if sm.updated["starpilotPlan"]:
starpilot_toggles = get_starpilot_toggles(sm)
Binary file not shown.
+6
View File
@@ -120,6 +120,12 @@ class Parser:
if 'lead_prob' in outs:
self.parse_binary_crossentropy('lead_prob', outs)
def parse_off_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
self.split_outputs(outs)
if 'desire_state' in outs:
self.parse_categorical_crossentropy('desire_state', outs, out_shape=(ModelConstants.DESIRE_PRED_WIDTH,))
return outs
def parse_vision_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]:
self.parse_mdn('pose', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,))
self.parse_mdn('wide_from_device_euler', outs, in_N=0, out_N=0, out_shape=(ModelConstants.WIDE_FROM_DEVICE_WIDTH,))
+1 -1
View File
@@ -57,7 +57,7 @@ class DRIVER_MONITOR_SETTINGS:
self._YAW_MIN_OFFSET = -0.0246
self._DCAM_UNCERTAIN_ALERT_THRESHOLD = 0.1
self._DCAM_UNCERTAIN_RESET_COUNT = int(20 / self._DT_DMON)
self._DCAM_UNCERTAIN_RESET_COUNT = int(2 / self._DT_DMON)
self._POSESTD_THRESHOLD = 0.3
self._HI_STD_FALLBACK_TIME = int(10 / self._DT_DMON) # fall back to wheel touch if model is uncertain for 10s
self._DISTRACTED_FILTER_TS = 0.25 # 0.6Hz
Binary file not shown.
+6
View File
@@ -957,10 +957,16 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
# ten times the regular interval, or the average interval is more than 10% too high.
EventName.commIssue: {
ET.SOFT_DISABLE: soft_disable_alert("Communication Issue Between Processes"),
ET.PERMANENT: Alert("Communication Issue Between Processes", "",
AlertStatus.normal, AlertSize.small,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 1., creation_delay=30.),
ET.NO_ENTRY: comm_issue_alert,
},
EventName.commIssueAvgFreq: {
ET.SOFT_DISABLE: soft_disable_alert("Low Communication Rate Between Processes"),
ET.PERMANENT: Alert("Low Communication Rate Between Processes", "",
AlertStatus.normal, AlertSize.small,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 1., creation_delay=30.),
ET.NO_ENTRY: NoEntryAlert("Low Communication Rate Between Processes"),
},
-1
View File
@@ -161,7 +161,6 @@ class SelfdriveD:
self.cancel_pressed_previously = False
self.distance_pressed_previously = False
self.display_timer = 0
self.last_below_steer_speed_alert_time = -float("inf")
self.last_steer_saturated_alert_time = -float("inf")
@@ -17,11 +17,15 @@ from openpilot.starpilot.assets.model_manager import (
MODEL_DOWNLOAD_ALL_PARAM,
MODEL_DOWNLOAD_PARAM,
ModelManager,
TINYGRAD_VERSIONS,
canonical_model_key,
is_builtin_model_key,
model_key_aliases,
)
from openpilot.starpilot.common.model_versions import (
is_tinygrad_model_version,
uses_combined_driving_artifacts,
uses_split_off_policy_artifacts,
)
from openpilot.starpilot.common.starpilot_variables import MODELS_PATH, update_starpilot_toggles
from openpilot.system.ui.lib.application import FontWeight, MouseEvent, MousePos, gui_app
from openpilot.system.ui.lib.multilang import tr
@@ -674,7 +678,7 @@ class StarPilotDrivingModelLayout(_SettingsPage):
if f"{model_key}.thneed" in files:
return True
if version in TINYGRAD_VERSIONS:
if is_tinygrad_model_version(version):
required_files = set(self._required_files_for_version(model_key, version))
return required_files.issubset(files)
@@ -684,6 +688,9 @@ class StarPilotDrivingModelLayout(_SettingsPage):
return any(file.startswith(f"{model_key}.") or file.startswith(f"{model_key}_") for file in files)
def _required_files_for_version(self, key: str, version: str) -> list[str]:
if uses_combined_driving_artifacts(version):
return [f"{key}_driving_tinygrad.pkl"]
files = [
f"{key}_driving_policy_tinygrad.pkl",
f"{key}_driving_vision_tinygrad.pkl",
@@ -691,7 +698,7 @@ class StarPilotDrivingModelLayout(_SettingsPage):
f"{key}_driving_vision_metadata.pkl",
]
if version in {"v12", "v13", "v14", "v15"}:
if uses_split_off_policy_artifacts(version):
files.extend(
[
f"{key}_driving_off_policy_tinygrad.pkl",
@@ -242,6 +242,11 @@ class StarPilotLateralLayout(_SettingsPage):
get_state=lambda: self._params.get_bool("TurnDesires"),
set_state=lambda s: self._params.put_bool("TurnDesires", s),
visible=lambda: self._params.get_bool("LateralTune")),
SettingRow("NavDesiresAllowed", "toggle", tr_noop("Use Route Desires"),
subtitle=tr_noop("Allow an active navigation route to request keep-left, keep-right, and low-speed turn desires."),
get_state=lambda: self._params.get_bool("NavDesiresAllowed"),
set_state=lambda s: self._params.put_bool("NavDesiresAllowed", s),
visible=lambda: self._params.get_bool("LateralTune")),
SettingRow("NNFF", "toggle", tr_noop("Neural Network Feedforward (NNFF)"),
subtitle=tr_noop("Use the full neural-network feedforward steering controller when available."),
get_state=lambda: self._params.get_bool("NNFF"),
@@ -382,6 +382,11 @@ class StarPilotLongitudinalTuneLayout(_SettingsPage):
get_state=lambda: self._params.get_bool("TacoTune"),
set_state=lambda s: self._params.put_bool("TacoTune", s),
visible=self._longitudinal_enabled),
SettingRow("NavLongitudinalAllowed", "toggle", tr_noop("Use Route Speed Control"),
subtitle=tr_noop("Allow an active navigation route to reduce cruise speed for upcoming turns, ramps, and roundabouts."),
get_state=lambda: self._params.get_bool("NavLongitudinalAllowed"),
set_state=lambda s: self._params.put_bool("NavLongitudinalAllowed", s),
visible=self._longitudinal_enabled),
], column_pair="detection_tune"),
]
self._manager_view = AetherSettingsView(
-68
View File
@@ -1,68 +0,0 @@
import time
import pyray as rl
from openpilot.selfdrive.ui.lib.starpilot_status import get_border_color, get_mode_transition_banner_text
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.application import FontWeight
from openpilot.system.ui.widgets.label import UnifiedLabel
class ModeTransitionBanner:
SHOW_TIME_SECONDS = 2.5
def __init__(self, *, font_size: int = 34, width: int = 520, height: int = 72, top_margin: int = 22):
self._last_mode: str | None = None
self._visible_until = 0.0
self._width = width
self._height = height
self._top_margin = top_margin
self._label = UnifiedLabel(
"",
font_size,
FontWeight.BOLD,
text_color=rl.WHITE,
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE,
)
def update(self):
current_mode = get_mode_transition_banner_text(ui_state) if ui_state.started else None
if not ui_state.started:
self._last_mode = None
self._visible_until = 0.0
return
if not ui_state.params.get_bool("ShowModeStatusBanner", default=True):
self._last_mode = current_mode
self._visible_until = 0.0
return
if self._last_mode is None:
self._last_mode = current_mode
return
if current_mode != self._last_mode:
self._last_mode = current_mode
if current_mode is not None:
self._label.set_text(f"{current_mode} MODE")
self._visible_until = time.monotonic() + self.SHOW_TIME_SECONDS
def render(self, rect: rl.Rectangle):
if (not ui_state.started or
not ui_state.params.get_bool("ShowModeStatusBanner", default=True) or
time.monotonic() > self._visible_until):
return
banner_width = min(rect.width - 120, self._width)
banner_rect = rl.Rectangle(
rect.x + (rect.width - banner_width) / 2,
rect.y + self._top_margin,
banner_width,
self._height,
)
rl.draw_rectangle_rounded(banner_rect, 0.3, 12, rl.Color(0, 0, 0, 175))
rl.draw_rectangle_rounded_lines_ex(banner_rect, 0.3, 12, 4, get_border_color(ui_state))
self._label.render(banner_rect)

Some files were not shown because too many files have changed in this diff Show More