mirror of
https://github.com/MoreTore/openpilot.git
synced 2026-08-05 08:16:06 +08:00
Volt | Genesis | Ioniq | Kia | Model randomizer
This commit is contained in:
@@ -2,17 +2,19 @@ from hypothesis import settings, given, strategies as st
|
||||
|
||||
import pytest
|
||||
|
||||
from opendbc.car import gen_empty_fingerprint
|
||||
from opendbc.can import CANPacker
|
||||
from opendbc.car import Bus, gen_empty_fingerprint
|
||||
from opendbc.car.structs import CarParams
|
||||
from opendbc.car.fw_versions import build_fw_dict
|
||||
from opendbc.car.hyundai.carstate import CarState
|
||||
from opendbc.car.hyundai.interface import CarInterface
|
||||
from opendbc.car.hyundai import hyundaicanfd
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR
|
||||
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, \
|
||||
HyundaiFlags, get_platform_codes, HyundaiSafetyFlags
|
||||
CarControllerParams, DBC, HyundaiFlags, get_platform_codes, HyundaiSafetyFlags
|
||||
from opendbc.car.hyundai.fingerprints import FW_VERSIONS
|
||||
|
||||
Ecu = CarParams.Ecu
|
||||
@@ -120,6 +122,39 @@ class TestHyundaiFingerprint:
|
||||
assert CarState.get_canfd_blinker_sig_names(CAR.HYUNDAI_KONA_EV_2ND_GEN, False) == ("LEFT_LAMP_ALT", "RIGHT_LAMP_ALT")
|
||||
assert CarState.get_canfd_blinker_sig_names(CAR.KIA_EV6, False) == ("LEFT_LAMP", "RIGHT_LAMP")
|
||||
|
||||
def test_sportage_angle_steering_uses_adas_cmd_with_send_lfa(self):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
cam_can = CanBus(None, fingerprint).CAM
|
||||
fingerprint[cam_can][0xCB] = 24
|
||||
CP = CarInterface.get_params(CAR.KIA_SPORTAGE_HEV_2026, fingerprint, [], False, False, False, None)
|
||||
|
||||
assert CP.flags & HyundaiFlags.SEND_LFA
|
||||
assert CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING
|
||||
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
msgs = hyundaicanfd.create_steering_messages(packer, CP, CanBus(CP), True, True, 1.0, 12.3)
|
||||
assert [(addr, bus) for addr, _, bus in msgs] == [(0xCB, CanBus(CP).ECAN)]
|
||||
|
||||
def test_sportage_angle_jerk_override_is_scoped(self):
|
||||
sportage = CarParams.new_message()
|
||||
sportage.carFingerprint = CAR.KIA_SPORTAGE_HEV_2026
|
||||
sportage.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_ANGLE_STEERING)
|
||||
|
||||
comparison_angle = CarParams.new_message()
|
||||
comparison_angle.carFingerprint = CAR.KIA_EV6
|
||||
comparison_angle.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_ANGLE_STEERING)
|
||||
|
||||
ioniq6 = CarParams.new_message()
|
||||
ioniq6.carFingerprint = CAR.HYUNDAI_IONIQ_6
|
||||
ioniq6.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT)
|
||||
|
||||
sportage_params = CarControllerParams(sportage)
|
||||
comparison_params = CarControllerParams(comparison_angle)
|
||||
ioniq6_params = CarControllerParams(ioniq6)
|
||||
|
||||
assert sportage_params.ANGLE_LIMITS.MAX_LATERAL_JERK < comparison_params.ANGLE_LIMITS.MAX_LATERAL_JERK
|
||||
assert comparison_params.ANGLE_LIMITS.MAX_LATERAL_JERK == ioniq6_params.ANGLE_LIMITS.MAX_LATERAL_JERK
|
||||
|
||||
def test_blacklisted_parts(self, subtests):
|
||||
# Asserts no ECUs known to be shared across platforms exist in the database.
|
||||
# Tucson having Santa Cruz camera and EPS for example
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass, field, replace
|
||||
from enum import IntFlag
|
||||
|
||||
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY, Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, uds
|
||||
@@ -29,6 +29,7 @@ class CarControllerParams:
|
||||
ANGLE_ACTIVE_TORQUE_REDUCTION_GAIN = 0.6
|
||||
|
||||
def __init__(self, CP, vEgoRaw=100.):
|
||||
self.ANGLE_LIMITS = self.ANGLE_LIMITS
|
||||
self.STEER_DELTA_UP = 3
|
||||
self.STEER_DELTA_DOWN = 7
|
||||
self.STEER_DRIVER_ALLOWANCE = 50
|
||||
@@ -52,6 +53,13 @@ class CarControllerParams:
|
||||
if CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
|
||||
self.STEER_THRESHOLD = 175
|
||||
|
||||
# The Sportage angle port is rough at low speed on the higher global jerk limit.
|
||||
# Keep the branch-wide higher limit for other cars, but restore the older calmer
|
||||
# jerk ceiling on this port only.
|
||||
if CP.carFingerprint == CAR.KIA_SPORTAGE_HEV_2026:
|
||||
self.ANGLE_LIMITS = replace(self.ANGLE_LIMITS,
|
||||
MAX_LATERAL_JERK=3.0 + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL))
|
||||
|
||||
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
|
||||
# If the max stock LKAS request is <384, add your car to this list.
|
||||
elif CP.carFingerprint in (CAR.GENESIS_G80, CAR.HYUNDAI_ELANTRA, CAR.HYUNDAI_ELANTRA_GT_I30, CAR.HYUNDAI_IONIQ,
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
extern const uint8_t gitversion[19];
|
||||
const uint8_t gitversion[19] = "DEV-49c71e2e-DEBUG";
|
||||
const uint8_t gitversion[19] = "DEV-f20d22d6-DEBUG";
|
||||
|
||||
@@ -1 +1 @@
|
||||
DEV-49c71e2e-DEBUG
|
||||
DEV-f20d22d6-DEBUG
|
||||
@@ -155,81 +155,81 @@ VOLT_STANDARD_FF_CUTOFF = 1.30
|
||||
VOLT_STANDARD_FF_CUTOFF_WIDTH = 0.24
|
||||
VOLT_STANDARD_TRANSITION_SPEED = 10.0
|
||||
VOLT_STANDARD_PHASE_SCALE = 0.10
|
||||
VOLT_STANDARD_TURN_IN_BOOST_LEFT = 0.02
|
||||
VOLT_STANDARD_TURN_IN_BOOST_LEFT = 0.06
|
||||
VOLT_STANDARD_TURN_IN_BOOST_RIGHT = 0.30
|
||||
VOLT_STANDARD_UNWIND_TAPER_LEFT = 0.08
|
||||
VOLT_STANDARD_UNWIND_TAPER_RIGHT = 0.14
|
||||
VOLT_STANDARD_UNWIND_TAPER_LEFT = 0.12
|
||||
VOLT_STANDARD_UNWIND_TAPER_RIGHT = 0.22
|
||||
VOLT_STANDARD_FRICTION_MULT = 1.04
|
||||
VOLT_STANDARD_FRICTION_LAT_RISE = 0.20
|
||||
VOLT_STANDARD_FRICTION_JERK_RISE = 0.24
|
||||
VOLT_STANDARD_TURN_IN_THRESHOLD_REDUCTION_LEFT = 0.02
|
||||
VOLT_STANDARD_TURN_IN_THRESHOLD_REDUCTION_RIGHT = 0.18
|
||||
VOLT_STANDARD_UNWIND_THRESHOLD_INCREASE_LEFT = 0.02
|
||||
VOLT_STANDARD_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.10
|
||||
VOLT_STANDARD_UNWIND_THRESHOLD_INCREASE_LEFT = 0.04
|
||||
VOLT_STANDARD_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.18
|
||||
VOLT_STANDARD_TURN_IN_FRICTION_BOOST_LEFT = 0.01
|
||||
VOLT_STANDARD_TURN_IN_FRICTION_BOOST_RIGHT = 0.10
|
||||
VOLT_STANDARD_UNWIND_FRICTION_REDUCTION_LEFT = 0.02
|
||||
VOLT_STANDARD_UNWIND_FRICTION_REDUCTION_RIGHT = 0.08
|
||||
VOLT_STANDARD_CENTER_TAPER_MAX = 0.11
|
||||
VOLT_STANDARD_CENTER_TAPER_LAT = 0.12
|
||||
VOLT_STANDARD_UNWIND_FRICTION_REDUCTION_LEFT = 0.04
|
||||
VOLT_STANDARD_UNWIND_FRICTION_REDUCTION_RIGHT = 0.14
|
||||
VOLT_STANDARD_CENTER_TAPER_MAX = 0.08
|
||||
VOLT_STANDARD_CENTER_TAPER_LAT = 0.10
|
||||
VOLT_STANDARD_CENTER_TAPER_LAT_WIDTH = 0.02
|
||||
VOLT_STANDARD_CENTER_TAPER_SPEED = 17.0
|
||||
VOLT_STANDARD_CENTER_TAPER_SPEED = 20.0
|
||||
VOLT_STANDARD_CENTER_TAPER_SPEED_WIDTH = 2.5
|
||||
|
||||
GENESIS_G90_LATERAL_TESTING_GROUND_ID = testing_ground.id_4
|
||||
GENESIS_G90_FF_GAIN_LEFT = 0.13
|
||||
GENESIS_G90_FF_GAIN_RIGHT = 0.10
|
||||
GENESIS_G90_FF_GAIN_RIGHT = 0.14
|
||||
GENESIS_G90_FF_ONSET = 0.10
|
||||
GENESIS_G90_FF_ONSET_WIDTH = 0.05
|
||||
GENESIS_G90_FF_CUTOFF = 1.55
|
||||
GENESIS_G90_FF_CUTOFF_WIDTH = 0.30
|
||||
GENESIS_G90_TRANSITION_SPEED = 8.5
|
||||
GENESIS_G90_PHASE_SCALE = 0.12
|
||||
GENESIS_G90_TURN_IN_BOOST_LEFT = 0.14
|
||||
GENESIS_G90_TURN_IN_BOOST_RIGHT = 0.22
|
||||
GENESIS_G90_UNWIND_TAPER_LEFT = 0.12
|
||||
GENESIS_G90_UNWIND_TAPER_RIGHT = 0.18
|
||||
GENESIS_G90_TURN_IN_BOOST_LEFT = 0.22
|
||||
GENESIS_G90_TURN_IN_BOOST_RIGHT = 0.34
|
||||
GENESIS_G90_UNWIND_TAPER_LEFT = 0.18
|
||||
GENESIS_G90_UNWIND_TAPER_RIGHT = 0.26
|
||||
GENESIS_G90_FRICTION_MULT = 1.02
|
||||
GENESIS_G90_FRICTION_LAT_RISE = 0.22
|
||||
GENESIS_G90_FRICTION_JERK_RISE = 0.24
|
||||
GENESIS_G90_TURN_IN_THRESHOLD_REDUCTION_LEFT = 0.10
|
||||
GENESIS_G90_TURN_IN_THRESHOLD_REDUCTION_RIGHT = 0.14
|
||||
GENESIS_G90_UNWIND_THRESHOLD_INCREASE_LEFT = 0.08
|
||||
GENESIS_G90_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.14
|
||||
GENESIS_G90_TURN_IN_FRICTION_BOOST_LEFT = 0.05
|
||||
GENESIS_G90_TURN_IN_FRICTION_BOOST_RIGHT = 0.08
|
||||
GENESIS_G90_UNWIND_FRICTION_REDUCTION_LEFT = 0.07
|
||||
GENESIS_G90_UNWIND_FRICTION_REDUCTION_RIGHT = 0.11
|
||||
GENESIS_G90_UNWIND_THRESHOLD_INCREASE_LEFT = 0.12
|
||||
GENESIS_G90_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.20
|
||||
GENESIS_G90_TURN_IN_FRICTION_BOOST_LEFT = 0.06
|
||||
GENESIS_G90_TURN_IN_FRICTION_BOOST_RIGHT = 0.10
|
||||
GENESIS_G90_UNWIND_FRICTION_REDUCTION_LEFT = 0.10
|
||||
GENESIS_G90_UNWIND_FRICTION_REDUCTION_RIGHT = 0.16
|
||||
|
||||
IONIQ_6_LATERAL_TESTING_GROUND_ID = testing_ground.id_5
|
||||
IONIQ_6_LATERAL_TESTING_GROUND_VARIANT = "C"
|
||||
IONIQ_6_FF_GAIN_LEFT = 0.04
|
||||
IONIQ_6_FF_GAIN_RIGHT = 0.015
|
||||
IONIQ_6_FF_GAIN_LEFT = 0.045
|
||||
IONIQ_6_FF_GAIN_RIGHT = 0.008
|
||||
IONIQ_6_FF_ONSET = 0.10
|
||||
IONIQ_6_FF_ONSET_WIDTH = 0.04
|
||||
IONIQ_6_FF_CUTOFF = 0.60
|
||||
IONIQ_6_FF_CUTOFF_WIDTH = 0.14
|
||||
IONIQ_6_TRANSITION_SPEED = 10.0
|
||||
IONIQ_6_PHASE_SCALE = 0.10
|
||||
IONIQ_6_TURN_IN_BOOST_LEFT = 0.38
|
||||
IONIQ_6_TURN_IN_BOOST_RIGHT = 0.32
|
||||
IONIQ_6_UNWIND_TAPER_LEFT = 0.34
|
||||
IONIQ_6_UNWIND_TAPER_RIGHT = 0.54
|
||||
IONIQ_6_TURN_IN_BOOST_LEFT = 0.42
|
||||
IONIQ_6_TURN_IN_BOOST_RIGHT = 0.40
|
||||
IONIQ_6_UNWIND_TAPER_LEFT = 0.40
|
||||
IONIQ_6_UNWIND_TAPER_RIGHT = 0.66
|
||||
IONIQ_6_FRICTION_MULT = 0.995
|
||||
IONIQ_6_FRICTION_LAT_RISE = 0.20
|
||||
IONIQ_6_FRICTION_JERK_RISE = 0.24
|
||||
IONIQ_6_TURN_IN_THRESHOLD_REDUCTION_LEFT = 0.12
|
||||
IONIQ_6_TURN_IN_THRESHOLD_REDUCTION_RIGHT = 0.10
|
||||
IONIQ_6_UNWIND_THRESHOLD_INCREASE_LEFT = 0.24
|
||||
IONIQ_6_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.36
|
||||
IONIQ_6_UNWIND_THRESHOLD_INCREASE_LEFT = 0.28
|
||||
IONIQ_6_UNWIND_THRESHOLD_INCREASE_RIGHT = 0.44
|
||||
IONIQ_6_TURN_IN_FRICTION_BOOST_LEFT = 0.05
|
||||
IONIQ_6_TURN_IN_FRICTION_BOOST_RIGHT = 0.04
|
||||
IONIQ_6_UNWIND_FRICTION_REDUCTION_LEFT = 0.18
|
||||
IONIQ_6_UNWIND_FRICTION_REDUCTION_RIGHT = 0.28
|
||||
IONIQ_6_CENTER_TAPER_MAX = 0.05
|
||||
IONIQ_6_CENTER_TAPER_LAT = 0.10
|
||||
IONIQ_6_UNWIND_FRICTION_REDUCTION_LEFT = 0.22
|
||||
IONIQ_6_UNWIND_FRICTION_REDUCTION_RIGHT = 0.34
|
||||
IONIQ_6_CENTER_TAPER_MAX = 0.025
|
||||
IONIQ_6_CENTER_TAPER_LAT = 0.08
|
||||
IONIQ_6_CENTER_TAPER_LAT_WIDTH = 0.02
|
||||
IONIQ_6_CENTER_TAPER_SPEED = 20.0
|
||||
IONIQ_6_CENTER_TAPER_SPEED = 22.0
|
||||
IONIQ_6_CENTER_TAPER_SPEED_WIDTH = 2.5
|
||||
|
||||
KIA_EV6_LATERAL_TESTING_GROUND_ID = testing_ground.id_6
|
||||
|
||||
@@ -181,7 +181,7 @@ class TestLatControl:
|
||||
|
||||
def test_genesis_g90_ff_scale_curve(self):
|
||||
assert get_genesis_g90_ff_scale(0.0, 0.0, 20.0) == 1.0
|
||||
assert get_genesis_g90_ff_scale(0.5, 0.0, 20.0) > get_genesis_g90_ff_scale(-0.5, 0.0, 20.0)
|
||||
assert get_genesis_g90_ff_scale(-0.5, 0.0, 20.0) > get_genesis_g90_ff_scale(0.5, 0.0, 20.0)
|
||||
assert get_genesis_g90_ff_scale(0.6, 0.7, 8.0) > get_genesis_g90_ff_scale(0.6, 0.0, 8.0) > get_genesis_g90_ff_scale(0.6, -0.7, 8.0)
|
||||
assert get_genesis_g90_ff_scale(-0.6, -0.7, 8.0) > get_genesis_g90_ff_scale(-0.6, 0.0, 8.0) > get_genesis_g90_ff_scale(-0.6, 0.7, 8.0)
|
||||
assert get_genesis_g90_ff_scale(2.0, 0.0, 20.0) < get_genesis_g90_ff_scale(0.8, 0.0, 20.0)
|
||||
@@ -219,7 +219,9 @@ class TestLatControl:
|
||||
right_turn_in = get_ioniq_6_friction_threshold(6.0, -0.5, -0.8)
|
||||
left_unwind = get_ioniq_6_friction_threshold(6.0, 0.5, -0.8)
|
||||
right_unwind = get_ioniq_6_friction_threshold(6.0, -0.5, 0.8)
|
||||
assert left_turn_in < right_turn_in < base < left_unwind < right_unwind
|
||||
assert max(left_turn_in, right_turn_in) < base
|
||||
assert left_unwind >= base
|
||||
assert right_unwind >= base
|
||||
|
||||
def test_ioniq_6_friction_scale_curve(self):
|
||||
base = get_ioniq_6_friction_scale(25.0, 0.5, 0.8)
|
||||
|
||||
@@ -60,6 +60,39 @@ def _get_param_str(params: Params, key: str, default: str = "") -> str:
|
||||
return str(val)
|
||||
|
||||
|
||||
def _get_default_param_str(params: Params, key: str) -> str:
|
||||
try:
|
||||
val = params.get_default_value(key)
|
||||
except Exception:
|
||||
return ""
|
||||
if val is None:
|
||||
return ""
|
||||
if isinstance(val, bytes):
|
||||
try:
|
||||
return val.decode("utf-8")
|
||||
except Exception:
|
||||
return ""
|
||||
return str(val)
|
||||
|
||||
|
||||
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
|
||||
@@ -143,14 +176,10 @@ class ModelState:
|
||||
def __init__(self, context: CLContext):
|
||||
# Dynamically build paths based on current model ID
|
||||
params = Params()
|
||||
model_id_raw = _get_param_str(params, "Model")
|
||||
if not model_id_raw:
|
||||
model_id_raw = _get_param_str(params, "DrivingModel", BUILTIN_MODEL_KEY)
|
||||
model_id_raw = _resolve_mirrored_param(params, "Model", "DrivingModel") or BUILTIN_MODEL_KEY
|
||||
model_id = _canonical_model_id(model_id_raw)
|
||||
|
||||
model_version = _get_param_str(params, "ModelVersion")
|
||||
if not model_version:
|
||||
model_version = _get_param_str(params, "DrivingModelVersion")
|
||||
model_version = _resolve_mirrored_param(params, "ModelVersion", "DrivingModelVersion")
|
||||
|
||||
model_dir = MODELS_PATH
|
||||
use_builtin_model = model_id == BUILTIN_MODEL_KEY
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import urllib.request
|
||||
|
||||
@@ -89,6 +90,12 @@ class ModelManager:
|
||||
return raw.decode("utf-8", errors="ignore").strip()
|
||||
return str(raw).strip()
|
||||
|
||||
def _param_bool(self, key: str) -> bool:
|
||||
try:
|
||||
return bool(self.params.get_bool(key))
|
||||
except Exception:
|
||||
return self._param_text(key).lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
def _default_param_text(self, key: str) -> str:
|
||||
try:
|
||||
default_value = self.params.get_default_value(key)
|
||||
@@ -100,6 +107,23 @@ class ModelManager:
|
||||
return default_value.decode("utf-8", errors="ignore").strip()
|
||||
return str(default_value).strip()
|
||||
|
||||
def _resolve_mirrored_param(self, primary_key: str, secondary_key: str) -> str:
|
||||
primary_val = self._param_text(primary_key)
|
||||
secondary_val = self._param_text(secondary_key)
|
||||
if primary_val == secondary_val:
|
||||
return secondary_val or primary_val
|
||||
|
||||
primary_default = self._default_param_text(primary_key)
|
||||
secondary_default = self._default_param_text(secondary_key)
|
||||
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 _load_catalog_from_params(self):
|
||||
self.available_models = [entry for entry in self._param_text("AvailableModels").split(",") if entry]
|
||||
self.model_versions = [entry for entry in self._param_text("ModelVersions").split(",") if entry]
|
||||
@@ -119,7 +143,7 @@ class ModelManager:
|
||||
|
||||
def _ensure_model_params(self):
|
||||
selected_model = self._selected_model()
|
||||
current_version = self._param_text("ModelVersion") or self._param_text("DrivingModelVersion")
|
||||
current_version = self._resolve_mirrored_param("ModelVersion", "DrivingModelVersion")
|
||||
if not current_version:
|
||||
current_version = self._default_param_text("ModelVersion") or self._default_param_text("DrivingModelVersion") or "v11"
|
||||
|
||||
@@ -141,8 +165,15 @@ class ModelManager:
|
||||
if index < len(self.model_versions) and model_key
|
||||
}
|
||||
|
||||
def _blacklisted_model_keys(self) -> set[str]:
|
||||
return {
|
||||
self._canonical_model_key(entry)
|
||||
for entry in self._param_text("BlacklistedModels").split(",")
|
||||
if entry.strip()
|
||||
}
|
||||
|
||||
def _selected_model(self) -> str:
|
||||
selected = self._param_text("Model") or self._param_text("DrivingModel")
|
||||
selected = self._resolve_mirrored_param("Model", "DrivingModel")
|
||||
if selected:
|
||||
return self._canonical_model_key(selected)
|
||||
default_value = self._default_param_text("Model") or self._default_param_text("DrivingModel")
|
||||
@@ -178,6 +209,60 @@ class ModelManager:
|
||||
return False
|
||||
return all((MODELS_PATH / filename).is_file() for filename in required_files)
|
||||
|
||||
def _installed_model_choices(self) -> list[tuple[str, str, str]]:
|
||||
self._load_catalog_from_params()
|
||||
version_map = self._model_version_map()
|
||||
blacklisted_keys = self._blacklisted_model_keys()
|
||||
choices: list[tuple[str, str, str]] = []
|
||||
seen_keys: set[str] = set()
|
||||
|
||||
for index, model_key in enumerate(self.available_models):
|
||||
if not model_key:
|
||||
continue
|
||||
|
||||
canonical_key = self._canonical_model_key(model_key)
|
||||
if canonical_key in blacklisted_keys or canonical_key in seen_keys:
|
||||
continue
|
||||
|
||||
model_version = version_map.get(model_key) or version_map.get(canonical_key) or ""
|
||||
if not model_version and is_builtin_model_key(canonical_key):
|
||||
model_version = self._default_param_text("ModelVersion") or self._default_param_text("DrivingModelVersion") or "v11"
|
||||
|
||||
if not self._is_model_downloaded(model_key, model_version):
|
||||
continue
|
||||
|
||||
model_name = self.available_model_names[index] if index < len(self.available_model_names) else canonical_key
|
||||
choices.append((canonical_key, model_name, model_version))
|
||||
seen_keys.add(canonical_key)
|
||||
|
||||
return choices
|
||||
|
||||
def randomize_selected_model(self) -> str | None:
|
||||
if not self._param_bool("ModelRandomizer"):
|
||||
return None
|
||||
|
||||
choices = self._installed_model_choices()
|
||||
if not choices:
|
||||
print("Model Randomizer skipped: no installed, non-blacklisted models available.")
|
||||
return None
|
||||
|
||||
selected = self._selected_model()
|
||||
eligible_choices = [choice for choice in choices if self._canonical_model_key(choice[0]) != selected]
|
||||
if not eligible_choices:
|
||||
eligible_choices = choices
|
||||
|
||||
model_key, model_name, model_version = random.choice(eligible_choices)
|
||||
if not model_version:
|
||||
model_version = self._default_param_text("ModelVersion") or self._default_param_text("DrivingModelVersion") or "v11"
|
||||
|
||||
self._set_model_param_keys(model_key, model_name, model_version)
|
||||
try:
|
||||
self.params_memory.put_bool("StarPilotTogglesUpdated", True)
|
||||
except Exception:
|
||||
pass
|
||||
print(f"Model Randomizer selected {model_name} ({model_key}, {model_version}).")
|
||||
return model_key
|
||||
|
||||
def _sync_selected_model_version(self):
|
||||
version_map = self._model_version_map()
|
||||
name_map = {model_key: model_name for model_key, model_name in zip(self.available_models, self.available_model_names)}
|
||||
@@ -194,7 +279,7 @@ class ModelManager:
|
||||
self._set_model_param_keys(selected, selected_name, version)
|
||||
return
|
||||
|
||||
fallback_version = self._param_text("ModelVersion") or self._param_text("DrivingModelVersion")
|
||||
fallback_version = self._resolve_mirrored_param("ModelVersion", "DrivingModelVersion")
|
||||
if not fallback_version:
|
||||
fallback_version = self._default_param_text("ModelVersion") or self._default_param_text("DrivingModelVersion") or "v11"
|
||||
self._set_model_param_keys(selected, name_map.get(selected, ""), fallback_version)
|
||||
@@ -390,6 +475,7 @@ class ModelManager:
|
||||
|
||||
self.params_memory.put(DOWNLOAD_PROGRESS_PARAM, "All models downloaded!")
|
||||
self.params_memory.remove(MODEL_DOWNLOAD_ALL_PARAM)
|
||||
self.randomize_selected_model()
|
||||
|
||||
def update_tinygrad(self):
|
||||
# This branch ships tinygrad runtime in-tree. "Update" here refreshes local model files.
|
||||
|
||||
@@ -115,7 +115,7 @@ def sync_drive_stats(params, session):
|
||||
except Exception as exception:
|
||||
print(f"Failed to sync drive stats: {exception}")
|
||||
|
||||
def transition_offroad(starpilot_planner, theme_manager, thread_manager, time_validated, sm, params, starpilot_toggles):
|
||||
def transition_offroad(starpilot_planner, model_manager, theme_manager, thread_manager, time_validated, sm, params, starpilot_toggles):
|
||||
params.put("LastGPSPosition", json.dumps(starpilot_planner.gps_position))
|
||||
|
||||
if starpilot_toggles.lock_doors_timer != 0:
|
||||
@@ -124,6 +124,8 @@ def transition_offroad(starpilot_planner, theme_manager, thread_manager, time_va
|
||||
if starpilot_toggles.random_themes:
|
||||
theme_manager.update_active_theme(time_validated, starpilot_toggles, randomize_theme=True)
|
||||
|
||||
model_manager.randomize_selected_model()
|
||||
|
||||
if time_validated:
|
||||
thread_manager.run_with_lock(send_stats)
|
||||
|
||||
@@ -193,6 +195,7 @@ def starpilot_thread():
|
||||
run_update_checks = False
|
||||
safe_mode_active = safe_mode_enabled(params_raw)
|
||||
started_previously = False
|
||||
model_randomizer_previously = params.get_bool("ModelRandomizer")
|
||||
time_validated = False
|
||||
|
||||
error_log = ERROR_LOGS_PATH / "error.txt"
|
||||
@@ -216,7 +219,7 @@ def starpilot_thread():
|
||||
starpilot_toggles = update_toggles(starpilot_variables, started, theme_manager, thread_manager, time_validated, params, starpilot_toggles)
|
||||
serialized_starpilot_toggles = serialize_starpilot_toggles(starpilot_toggles)
|
||||
toggle_broadcast_pending = True
|
||||
transition_offroad(starpilot_planner, theme_manager, thread_manager, time_validated, sm, params, starpilot_toggles)
|
||||
transition_offroad(starpilot_planner, model_manager, theme_manager, thread_manager, time_validated, sm, params, starpilot_toggles)
|
||||
|
||||
run_update_checks = True
|
||||
elif started and not started_previously:
|
||||
@@ -268,6 +271,11 @@ def starpilot_thread():
|
||||
serialized_starpilot_toggles = serialize_starpilot_toggles(starpilot_toggles)
|
||||
toggle_broadcast_pending = True
|
||||
|
||||
model_randomizer_enabled = params.get_bool("ModelRandomizer")
|
||||
if model_randomizer_enabled and not model_randomizer_previously and not started:
|
||||
model_manager.randomize_selected_model()
|
||||
model_randomizer_previously = model_randomizer_enabled
|
||||
|
||||
periodic_update_due = monotonic_now >= next_periodic_update_check
|
||||
if periodic_update_due:
|
||||
next_periodic_update_check = get_next_periodic_update_check(monotonic_now, periodic_update_phase)
|
||||
|
||||
Reference in New Issue
Block a user