diff --git a/.gitignore b/.gitignore index a1c7bcc6..f3a632ff 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,6 @@ a.out .cache/ .comma_sysroot/ .venv-linux-arm64/ -compiledmodels/ /docs_site/ diff --git a/frogpilot/common/frogpilot_variables.py b/frogpilot/common/frogpilot_variables.py index 7f97de33..05e698b2 100644 --- a/frogpilot/common/frogpilot_variables.py +++ b/frogpilot/common/frogpilot_variables.py @@ -249,18 +249,11 @@ def get_frogpilot_toggles(sm=messaging.SubMaster(["frogpilotPlan"])): return toggles @cache -def _process_frogpilot_plan_toggles(toggles): - return SimpleNamespace(**json.loads(toggles)) - - def process_frogpilot_toggles(toggles): if toggles: - return _process_frogpilot_plan_toggles(toggles) + return SimpleNamespace(**json.loads(toggles)) return FrogPilotVariables().frogpilot_toggles - -process_frogpilot_toggles.cache_clear = _process_frogpilot_plan_toggles.cache_clear - def update_frogpilot_toggles(): if not hasattr(update_frogpilot_toggles, "_params_memory"): update_frogpilot_toggles._params_memory = Params(memory=True) diff --git a/frogpilot/navigation/mapd_wrapper.py b/frogpilot/navigation/mapd_wrapper.py deleted file mode 100644 index ff469d8a..00000000 --- a/frogpilot/navigation/mapd_wrapper.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python3 -import json -import os -import signal -import subprocess -import sys -import time - -from collections import defaultdict, deque -from pathlib import Path - -from openpilot.common.basedir import BASEDIR -from openpilot.common.swaglog import cloudlog - -MAPD_DIR = Path(BASEDIR) / "frogpilot/navigation" -MAPD_BIN = MAPD_DIR / "mapd" -OFFLINE_ROOT = Path("/data/media/0/osm/offline") -RESTART_DELAY_S = 0.25 -FAILURE_WINDOW_S = 3.0 -FAILURE_THRESHOLD = 3 - - -def extract_bounds_filename(line: str) -> str | None: - try: - payload = json.loads(line) - except json.JSONDecodeError: - return None - - if payload.get("msg") != "Loading bounds file": - return None - - filename = payload.get("filename") - return filename if isinstance(filename, str) else None - - -def is_offline_read_error(line: str) -> bool: - try: - payload = json.loads(line) - except json.JSONDecodeError: - return False - - return payload.get("msg") == "could not unmarshal offline data" - - -class CorruptTileMonitor: - def __init__(self, threshold: int = FAILURE_THRESHOLD, window_s: float = FAILURE_WINDOW_S): - self.threshold = threshold - self.window_s = window_s - self.current_filename: str | None = None - self.failures: dict[str, deque[float]] = defaultdict(deque) - - def observe(self, line: str, now: float | None = None) -> str | None: - filename = extract_bounds_filename(line) - if filename is not None: - self.current_filename = filename - return None - - if not is_offline_read_error(line) or self.current_filename is None: - return None - - ts = time.monotonic() if now is None else now - failures = self.failures[self.current_filename] - failures.append(ts) - - cutoff = ts - self.window_s - while failures and failures[0] < cutoff: - failures.popleft() - - if len(failures) >= self.threshold: - return self.current_filename - return None - - -def quarantine_offline_tile(filename: str) -> Path | None: - tile_path = Path(filename) - try: - tile_path.relative_to(OFFLINE_ROOT) - except ValueError: - cloudlog.warning(f"mapd_wrapper refusing to quarantine unexpected path: {filename}") - return None - - if not tile_path.exists(): - return None - - quarantined = tile_path.with_name(f"{tile_path.name}.corrupt.{int(time.time())}") - tile_path.rename(quarantined) - return quarantined - - -def terminate_child(proc: subprocess.Popen[str]) -> None: - if proc.poll() is not None: - return - - proc.terminate() - try: - proc.wait(timeout=2) - except subprocess.TimeoutExpired: - proc.kill() - proc.wait(timeout=2) - - -def run_mapd_once() -> int: - proc = subprocess.Popen( - [MAPD_BIN.as_posix()], - cwd=MAPD_DIR, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - bufsize=1, - ) - assert proc.stdout is not None - - def _handle_signal(signum, _frame): - terminate_child(proc) - raise SystemExit(128 + signum) - - signal.signal(signal.SIGTERM, _handle_signal) - signal.signal(signal.SIGINT, _handle_signal) - - monitor = CorruptTileMonitor() - - for line in proc.stdout: - print(line, end="") - bad_tile = monitor.observe(line) - if bad_tile is None: - continue - - quarantined = quarantine_offline_tile(bad_tile) - if quarantined is None: - cloudlog.warning(f"mapd_wrapper detected repeated offline read failures for {bad_tile}, but could not quarantine it") - else: - message = f"mapd_wrapper quarantined corrupt offline tile: {bad_tile} -> {quarantined}" - print(message, flush=True) - cloudlog.warning(message) - - terminate_child(proc) - return 1 - - return proc.wait() - - -def main() -> None: - while True: - exit_code = run_mapd_once() - if exit_code == 1: - time.sleep(RESTART_DELAY_S) - continue - raise SystemExit(exit_code) - - -if __name__ == "__main__": - main() diff --git a/frogpilot/navigation/test_mapd_wrapper.py b/frogpilot/navigation/test_mapd_wrapper.py deleted file mode 100644 index e1c591c6..00000000 --- a/frogpilot/navigation/test_mapd_wrapper.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 -import json - -from pathlib import Path - -from openpilot.frogpilot.navigation.mapd_wrapper import CorruptTileMonitor, quarantine_offline_tile - - -def _loading_line(filename: str) -> str: - return json.dumps({"msg": "Loading bounds file", "filename": filename}) - - -def _error_line() -> str: - return json.dumps({"msg": "could not unmarshal offline data", "error": "EOF"}) - - -def test_corrupt_tile_monitor_triggers_after_repeated_failures(): - filename = "/data/media/0/osm/offline/36/-98/37.500000_-98.000000_37.750000_-97.750000" - monitor = CorruptTileMonitor(threshold=3, window_s=3.0) - - assert monitor.observe(_loading_line(filename), now=0.0) is None - assert monitor.observe(_error_line(), now=0.1) is None - assert monitor.observe(_loading_line(filename), now=0.2) is None - assert monitor.observe(_error_line(), now=0.3) is None - assert monitor.observe(_loading_line(filename), now=0.4) is None - assert monitor.observe(_error_line(), now=0.5) == filename - - -def test_quarantine_offline_tile_renames_file(tmp_path, monkeypatch): - offline_root = tmp_path / "offline" - tile = offline_root / "36/-98/37.500000_-98.000000_37.750000_-97.750000" - tile.parent.mkdir(parents=True) - tile.write_text("bad") - - monkeypatch.setattr("openpilot.frogpilot.navigation.mapd_wrapper.OFFLINE_ROOT", offline_root) - - quarantined = quarantine_offline_tile(tile.as_posix()) - - assert quarantined is not None - assert not tile.exists() - assert Path(quarantined).exists() - assert Path(quarantined).name.startswith(f"{tile.name}.corrupt.") diff --git a/models b/models deleted file mode 100755 index 1e648cdc..00000000 --- a/models +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail - -DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" -set +u -source "$DIR/launch_env.sh" -exec python3 "$DIR/scripts/model_compiler.py" "$@" diff --git a/opendbc_repo/opendbc/car/gm/interface.py b/opendbc_repo/opendbc/car/gm/interface.py index 1d1dadd8..4d280a11 100755 --- a/opendbc_repo/opendbc/car/gm/interface.py +++ b/opendbc_repo/opendbc/car/gm/interface.py @@ -485,6 +485,7 @@ class CarInterface(CarInterfaceBase): elif candidate == CAR.GMC_YUKON: ret.steerActuatorDelay = 0.5 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + ret.dashcamOnly = True # Needs steerRatio, tireStiffness, and lat accel factor tuning # OPGM variables elif candidate in (CAR.CHEVROLET_MALIBU, CAR.CHEVROLET_MALIBU_CC, CAR.CHEVROLET_MALIBU_HYBRID_CC): diff --git a/opendbc_repo/opendbc/dbc/gm_global_a_powertrain_volt.dbc b/opendbc_repo/opendbc/dbc/gm_global_a_powertrain_volt.dbc deleted file mode 100644 index 9361c756..00000000 --- a/opendbc_repo/opendbc/dbc/gm_global_a_powertrain_volt.dbc +++ /dev/null @@ -1,375 +0,0 @@ -CM_ "AUTOGENERATED FILE, DO NOT EDIT"; - - -CM_ "Imported file _comma.dbc starts here"; -BO_ 512 GAS_COMMAND: 6 NEO - SG_ GAS_COMMAND : 7|16@0+ (0.2777778,-96.111115) [0|1] "" INTERCEPTOR - SG_ GAS_COMMAND2 : 23|16@0+ (0.120853074,-79.15877) [0|1] "" INTERCEPTOR - SG_ ENABLE : 39|1@0+ (1,0) [0|1] "" INTERCEPTOR - SG_ COUNTER_PEDAL : 35|4@0+ (1,0) [0|15] "" INTERCEPTOR - SG_ CHECKSUM_PEDAL : 47|8@0+ (1,0) [0|255] "" INTERCEPTOR - -BO_ 513 GAS_SENSOR: 6 INTERCEPTOR - SG_ INTERCEPTOR_GAS : 7|16@0+ (0.2777778,-96.111115) [0|1] "" NEO - SG_ INTERCEPTOR_GAS2 : 23|16@0+ (0.120853074,-79.15877) [0|1] "" NEO - SG_ STATE : 39|4@0+ (1,0) [0|15] "" NEO - SG_ COUNTER_PEDAL : 35|4@0+ (1,0) [0|15] "" NEO - SG_ CHECKSUM_PEDAL : 47|8@0+ (1,0) [0|255] "" NEO - -VAL_ 513 STATE 5 "FAULT_TIMEOUT" 4 "FAULT_STARTUP" 3 "FAULT_SCE" 2 "FAULT_SEND" 1 "FAULT_BAD_CHECKSUM" 0 "NO_FAULT" ; - -CM_ "gm_global_a_powertrain.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_: K16_BECM K73_TCIC K9_BCM K43_PSCM K17_EBCM K20_ECM K114B_HPCM NEO K124_ASCM EPB -VAL_TABLE_ TurnSignals 2 "Right Turn" 1 "Left Turn" 0 "None" ; -VAL_TABLE_ Intellibeam 1 "Active" 0 "Inactive" ; -VAL_TABLE_ HighBeamsActive 1 "Active" 0 "Inactive" ; -VAL_TABLE_ HighBeamsTemporary 1 "Active" 0 "Inactive" ; -VAL_TABLE_ ACCLeadCar 1 "Present" 0 "Not Present" ; -VAL_TABLE_ ACCCmdActive 1 "Active" 0 "Inactive" ; -VAL_TABLE_ BrakePedalPressed 1 "Pressed" 0 "Depressed" ; -VAL_TABLE_ DistanceButton 1 "Active" 0 "Inactive" ; -VAL_TABLE_ LKAButton 1 "Active" 0 "Inactive" ; -VAL_TABLE_ ACCButtons 6 "Cancel" 5 "Main" 3 "Set" 2 "Resume" 1 "None" ; -VAL_TABLE_ DriveModeButton 1 "Active" 0 "Inactive" ; -VAL_TABLE_ PRNDL 3 "Reverse" 2 "Drive" 1 "Neutral" 0 "Park" ; -VAL_TABLE_ ESPButton 1 "Active" 0 "Inactive" ; -VAL_TABLE_ DoorStatus 1 "Opened" 0 "Closed" ; -VAL_TABLE_ SeatBeltStatus 1 "Latched" 0 "Unlatched" ; -VAL_TABLE_ LKASteeringCmdActive 1 "Active" 0 "Inactive" ; -VAL_TABLE_ ACCGapLevel 3 "Far" 2 "Med" 1 "Near" 0 "Inactive" ; -VAL_TABLE_ GasRegenCmdActiveInv 1 "Inactive" 0 "Active" ; -VAL_TABLE_ GasRegenCmdActive 1 "Active" 0 "Inactive" ; -VAL_TABLE_ LKATorqueDeliveredStatus 3 "Failed" 2 "Temp. Limited" 1 "Active" 0 "Inactive" ; -VAL_TABLE_ HandsOffSWDetectionStatus 1 "Hands On" 0 "Hands Off" ; -VAL_TABLE_ HandsOffSWDetectionMode 2 "Failed" 1 "Enabled" 0 "Disabled" ; - - -BO_ 189 EBCMRegenPaddle: 7 K17_EBCM - SG_ RegenPaddle : 7|4@0+ (1,0) [0|0] "" NEO - -BO_ 190 ECMAcceleratorPos: 6 K20_ECM - SG_ BrakePedalPos : 15|8@0+ (1,0) [0|0] "sticky" NEO - SG_ GasPedalAndAcc : 23|8@0+ (1,0) [0|0] "" NEO - -BO_ 201 ECMEngineStatus: 8 K20_ECM - SG_ EngineTPS : 39|8@0+ (0.392156863,0) [0|100.000000065] "%" NEO - SG_ EngineRPM : 15|16@0+ (0.25,0) [0|0] "RPM" NEO - SG_ CruiseMainOn : 29|1@0+ (1,0) [0|1] "" NEO - SG_ BrakePressed : 40|1@0+ (1,0) [0|1] "" NEO - SG_ Standstill : 2|1@0+ (1,0) [0|1] "" NEO - SG_ CruiseActive : 31|2@0+ (1,0) [0|3] "" NEO - -BO_ 209 EBCMBrakePedalSensors: 7 K17_EBCM - SG_ Counter1 : 7|2@0+ (1,0) [0|3] "" XXX - SG_ Counter2 : 23|2@0+ (1,0) [0|3] "" XXX - SG_ BrakePedalPosition1 : 5|14@0+ (1,0) [0|16383] "" XXX - SG_ BrakePedalPosition2 : 21|14@0- (-1,0) [0|16383] "" XXX - SG_ BrakeNormalized1 : 39|8@0+ (1,0) [0|255] "" XXX - SG_ BrakeNormalized2 : 47|8@0- (-1,0) [0|255] "" XXX - -BO_ 241 EBCMBrakePedalPosition: 6 K17_EBCM - SG_ BrakePressed : 1|1@0+ (1,0) [0|1] "" XXX - SG_ BrakePedalPosition : 15|8@0+ (1,0) [0|255] "" NEO - -BO_ 298 BCMDoorBeltStatus: 8 K9_BCM - SG_ RearLeftDoor : 8|1@0+ (1,0) [0|0] "" NEO - SG_ FrontLeftDoor : 9|1@0+ (1,0) [0|0] "" NEO - SG_ FrontRightDoor : 10|1@0+ (1,0) [0|0] "" NEO - SG_ RearRightDoor : 23|1@0+ (1,0) [0|0] "" NEO - SG_ LeftSeatBelt : 12|1@0+ (1,0) [0|0] "" NEO - SG_ RightSeatBelt : 53|1@0+ (1,0) [0|0] "" NEO - -BO_ 309 ECMPRDNL: 8 K20_ECM - SG_ PRNDL : 2|3@0+ (1,0) [0|0] "" NEO - SG_ ESPButton : 4|1@0+ (1,0) [0|1] "" XXX - -BO_ 320 BCMTurnSignals: 3 K9_BCM - SG_ TurnSignals : 19|2@0+ (1,0) [0|0] "" NEO - SG_ Intellibeam : 13|1@0+ (1,0) [0|1] "" XXX - SG_ HighBeamsActive : 7|1@0+ (1,0) [0|1] "" XXX - SG_ HighBeamsTemporary : 5|1@0+ (1,0) [0|1] "" XXX - -BO_ 322 BCMBlindSpotMonitor: 7 K9_BCM - SG_ LeftBSM : 6|1@0+ (1,0) [0|1] "" XXX - SG_ RightBSM : 7|1@0+ (1,0) [0|1] "" XXX - -BO_ 328 PSCM_148: 1 K43_PSCM - -BO_ 381 ESPStatus: 6 K20_ECM - SG_ TractionControlOn : 5|1@0+ (1,0) [0|0] "" NEO - SG_ MSG17D_AccPower : 35|12@0- (1,0) [0|0] "" NEO - -BO_ 384 ASCMLKASteeringCmd: 4 NEO - SG_ RollingCounter : 5|2@0+ (1,0) [0|0] "" NEO - SG_ LKASteeringCmdChecksum : 19|12@0+ (1,0) [0|0] "" NEO - SG_ LKASteeringCmdActive : 3|1@0+ (1,0) [0|0] "" NEO - SG_ LKASteeringCmd : 2|11@0- (1,0) [0|0] "" NEO - -BO_ 388 PSCMStatus: 8 K43_PSCM - SG_ HandsOffSWDetectionMode : 20|2@0+ (1,0) [0|3] "" NEO - SG_ HandsOffSWlDetectionStatus : 21|1@0+ (1,0) [0|1] "" NEO - SG_ LKATorqueDeliveredStatus : 5|3@0+ (1,0) [0|7] "" NEO - SG_ LKADriverAppldTrq : 50|11@0- (0.01,0) [-10.24|10.23] "Nm" NEO - SG_ LKATorqueDelivered : 18|11@0- (0.01,0) [0|1] "" NEO - SG_ LKATotalTorqueDelivered : 2|11@0- (0.01,0) [-10.24|10.23] "Nm" NEO - SG_ RollingCounter : 38|4@0+ (1,0) [0|15] "" XXX - SG_ PSCMStatusChecksum : 33|10@0+ (1,0) [0|1023] "" XXX - -BO_ 417 AcceleratorPedal: 7 XXX - SG_ AcceleratorPedal : 55|8@0+ (1,0) [0|0] "" NEO - -BO_ 451 GasAndAcc: 8 XXX - SG_ GasPedalAndAcc2 : 55|8@0+ (1,0) [0|0] "" NEO - -BO_ 452 AcceleratorPedal2: 8 XXX - SG_ CruiseState : 15|3@0+ (1,0) [0|7] "" NEO - SG_ AcceleratorPedal2 : 47|8@0+ (1,0) [0|0] "" NEO - -BO_ 481 ASCMSteeringButton: 7 K124_ASCM - SG_ DistanceButton : 22|1@0+ (1,0) [0|0] "" NEO - SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO - SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX - SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO - SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX - SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO - SG_ SteeringButtonChecksum : 43|12@0+ (1,0) [0|255] "" NEO - -BO_ 485 PSCMSteeringAngle: 8 K43_PSCM - SG_ SteeringWheelAngle : 15|16@0- (0.0625,0) [-2047|2047] "deg" NEO - SG_ SteeringWheelRate : 27|12@0- (1,0) [-2047|2047] "deg/s" NEO - -BO_ 489 EBCMVehicleDynamic: 8 K17_EBCM - SG_ BrakePedalPressed : 6|1@0+ (1,0) [0|0] "" NEO - SG_ LateralAcceleration : 3|10@0- (0.161,0) [-2047|2047] "m/s2" NEO - SG_ YawRate : 35|12@0- (0.625,0) [0|1] "" NEO - SG_ YawRate2 : 51|12@0- (0.0625,0) [-2047|2047] "grad/s" NEO - -BO_ 352 BCMImmobilizer: 5 K9_BCM - SG_ ImmobilizerInfo : 7|32@0+ (1,0) [0|4294967295] "" XXX - -BO_ 497 BCMGeneralPlatformStatus: 8 K9_BCM - SG_ SystemPowerMode : 1|2@0+ (1,0) [0|3] "" XXX - SG_ SystemBackUpPowerMode : 5|2@0+ (1,0) [0|3] "" XXX - SG_ ParkBrakeSwActive : 36|1@0+ (1,0) [0|3] "" XXX - -BO_ 500 SportMode: 6 XXX - SG_ SportMode : 15|1@0+ (1,0) [0|1] "" XXX - -BO_ 501 ECMPRDNL2: 8 K20_ECM - SG_ TransmissionState : 48|4@1+ (1,0) [0|7] "" NEO - SG_ PRNDL2 : 27|4@0+ (1,0) [0|255] "" NEO - SG_ ManualMode : 41|1@0+ (1,0) [0|1] "" NEO - -BO_ 532 BRAKE_RELATED: 6 XXX - SG_ UserBrakePressure : 0|9@0+ (1,0) [0|511] "" XXX - -BO_ 560 EPBStatus: 8 EPB - SG_ EPBClosed : 12|1@0+ (1,0) [0|1] "" NEO - -BO_ 562 EBCMFrictionBrakeStatus: 8 K17_EBCM - SG_ FrictionBrakeUnavailable : 46|1@0+ (1,0) [0|1] "" XXX - -BO_ 608 SPEED_RELATED: 8 XXX - SG_ RollingCounter : 5|2@0+ (1,0) [0|0] "" XXX - SG_ ClusterSpeed : 31|8@0+ (1,0) [0|0] "" XXX - -BO_ 711 BECMBatteryVoltageCurrent: 6 K17_EBCM - SG_ HVBatteryVoltage : 31|12@0+ (0.125,0) [0|511.875] "V" NEO - SG_ HVBatteryCurrent : 12|13@0- (0.15,0) [-614.4|614.25] "A" NEO - -BO_ 715 ASCMGasRegenCmd: 8 K124_ASCM - SG_ GasRegenAlwaysOne2 : 9|1@0+ (1,0) [0|1] "" NEO - SG_ GasRegenAlwaysOne : 14|1@0+ (1,0) [0|1] "" NEO - SG_ GasRegenChecksum : 47|24@0+ (1,0) [0|0] "" NEO - SG_ GasRegenCmdActiveInv : 32|1@0+ (1,0) [0|0] "" NEO - SG_ GasRegenFullStopActive : 13|1@0+ (1,0) [0|0] "" NEO - SG_ GasRegenCmdActive : 0|1@0+ (1,0) [0|0] "" NEO - SG_ RollingCounter : 7|2@0+ (1,0) [0|0] "" NEO - SG_ GasRegenAlwaysOne3 : 23|1@0+ (1,0) [0|1] "" NEO - SG_ GasRegenCmd : 22|12@0+ (1,0) [0|0] "" NEO - -BO_ 717 ASCM_2CD: 5 K124_ASCM - -BO_ 761 BRAKE_RELATED_2: 7 XXX - SG_ UserBrakePressure2 : 47|9@0+ (1,0) [0|511] "" XXX - -BO_ 789 EBCMFrictionBrakeCmd: 5 K124_ASCM - SG_ RollingCounter : 33|2@0+ (1,0) [0|0] "" NEO - SG_ FrictionBrakeMode : 7|4@0+ (1,0) [0|0] "" NEO - SG_ FrictionBrakeChecksum : 23|16@0+ (1,0) [0|0] "" NEO - SG_ FrictionBrakeCmd : 3|12@0- (1,0) [0|0] "" NEO - -BO_ 800 AEBCmd: 6 K124_ASCM - SG_ RollingCounter : 5|2@0+ (1,0) [0|3] "" NEO - SG_ AEBChecksum : 27|20@0+ (1,0) [0|0] "" NEO - SG_ AEBCmdActive : 3|1@1+ (1,0) [0|1] "" NEO - SG_ AEBCmd : 2|11@0+ (1,0) [0|0] "" NEO - SG_ AEBCmd2 : 23|8@0+ (1,0) [0|0] "" NEO - -BO_ 810 TCICOnStarGPSPosition: 8 K73_TCIC - SG_ GPSLongitude : 39|32@0+ (1,-2147483648) [0|0] "milliarcsecond" NEO - SG_ GPSLatitude : 7|32@0+ (1,0) [0|0] "milliarcsecond" NEO - -BO_ 840 EBCMWheelSpdFront: 5 K17_EBCM - SG_ FLWheelSpd : 7|16@0+ (0.0311,0) [0|255] "km/h" NEO - SG_ FRWheelSpd : 23|16@0+ (0.0311,0) [0|255] "km/h" NEO - -BO_ 842 EBCMWheelSpdRear: 5 K17_EBCM - SG_ RLWheelSpd : 7|16@0+ (0.0311,0) [0|255] "km/h" NEO - SG_ RRWheelSpd : 23|16@0+ (0.0311,0) [0|255] "km/h" NEO - SG_ RRWheelDir : 34|3@0+ (1,0) [0|7] "" NEO - SG_ RLWheelDir : 37|3@0+ (1,0) [0|7] "" NEO - -BO_ 869 ASCM_365: 4 K124_ASCM - -BO_ 880 ASCMActiveCruiseControlStatus: 6 K124_ASCM - SG_ ACCCruiseState : 8|3@1+ (1,0) [0|7] "" XXX - SG_ ACCLeadCar : 44|1@0+ (1,0) [0|0] "" Vector__XXX - SG_ ACCAlwaysOne2 : 32|1@0+ (1,0) [0|0] "" Vector__XXX - SG_ ACCAlwaysOne : 0|1@0+ (1,0) [0|0] "" Vector__XXX - SG_ ACCSpeedSetpoint : 19|12@0+ (0.0625,0) [0|255.9375] "km/h" NEO - SG_ ACCGapLevel : 21|2@0+ (1,0) [0|0] "" NEO - SG_ ACCResumeButton : 1|1@0+ (1,0) [0|0] "" NEO - SG_ ACCCmdActive : 23|1@0+ (1,0) [0|0] "" NEO - SG_ FCWAlert : 41|2@0+ (1,0) [0|3] "" XXX - -BO_ 967 EVDriveMode: 4 XXX - SG_ SinglePedalModeActive : 7|1@0+ (1,0) [0|1] "" XXX - SG_ SinglePedalModeRisingEdge : 21|1@0+ (1,0) [0|1] "" XXX - SG_ SinglePedalModeFallingEdge : 22|1@0+ (1,0) [0|1] "" XXX - -BO_ 977 ECMCruiseControl: 8 K20_ECM - SG_ CruiseActive : 39|1@0+ (1,0) [0|3] "" NEO - SG_ CruiseSetSpeed : 19|12@0+ (0.0625,0) [0|0] "km/h" NEO - -BO_ 1001 ECMVehicleSpeed: 8 K20_ECM - SG_ VehicleSpeed : 7|16@0+ (0.01,0) [0|0] "mph" NEO - SG_ VehicleSpeedLeft : 39|16@0+ (0.01,0) [0|0] "mph" NEO - -BO_ 1033 ASCMKeepAlive: 7 NEO - SG_ ASCMKeepAliveAllZero : 7|56@0+ (1,0) [0|0] "" NEO - -BO_ 1034 ASCM_40A: 7 K124_ASCM - -BO_ 1217 ECMEngineCoolantTemp: 8 K20_ECM - SG_ EngineCoolantTemp : 23|8@0+ (1,-40) [0|0] "C" NEO - -BO_ 1249 VIN_Part2: 8 K20_ECM - SG_ VINPart2 : 7|64@0+ (1,0) [0|0] "" NEO - -BO_ 1296 ASCM_510: 4 K124_ASCM - -BO_ 1300 VIN_Part1: 8 K20_ECM - SG_ VINPart1 : 7|64@0+ (1,0) [0|0] "" NEO - -BO_ 1912 PSCM_778: 8 K43_PSCM - -BO_ 1930 ASCM_78A: 7 K124_ASCM - -BO_TX_BU_ 384 : K124_ASCM,NEO; -BO_TX_BU_ 880 : NEO,K124_ASCM; -BO_TX_BU_ 1033 : K124_ASCM,NEO; -BO_TX_BU_ 715 : NEO,K124_ASCM; -BO_TX_BU_ 789 : NEO,K124_ASCM; -BO_TX_BU_ 800 : NEO,K124_ASCM; - - -CM_ BU_ K16_BECM "Battery Energy Control Module"; -CM_ BU_ K73_TCIC "Telematics Communication Control Module"; -CM_ BU_ K9_BCM "Body Control Module"; -CM_ BU_ K43_PSCM "Power Steering Control Module"; -CM_ BU_ K17_EBCM "Electronic Brake Control Module"; -CM_ BU_ K20_ECM "Engine Control Module"; -CM_ BU_ K114B_HPCM "Hybrid Powertrain Control Module"; -CM_ BU_ NEO "Comma NEO"; -CM_ BU_ K124_ASCM "Active Safety Control Module"; -CM_ SG_ 381 MSG17D_AccPower "Need to investigate"; -CM_ BO_ 190 "Length varies from 6 to 8 bytes by car"; -CM_ SG_ 190 GasPedalAndAcc "ACC baseline is 62"; -CM_ SG_ 322 LeftBSM "For some cars, this can only be when the blinker is also active"; -CM_ SG_ 322 RightBSM "For some cars, this can only be when the blinker is also active"; -CM_ SG_ 352 ImmobilizerInfo "Non-zero when ignition or accessory mode"; -CM_ SG_ 451 GasPedalAndAcc2 "ACC baseline is 62"; -CM_ SG_ 481 ACCAlwaysOne "Usually 1 if the car is equipped with ACC"; -CM_ SG_ 562 FrictionBrakeUnavailable "1 when ACC brake control is unavailable. Stays high if brake command messages are blocked for a period of time"; -CM_ SG_ 497 SystemPowerMode "Describes ignition"; -CM_ SG_ 497 SystemBackUpPowerMode "Describes ignition + preconditioning mode, noisy"; -CM_ SG_ 501 PRNDL2 "When ManualMode is Active, Value is 13=L1 12=L2 11=L3 ... 4=L10"; -CM_ SG_ 532 UserBrakePressure "can be lower than other brake position signals when the brakes are pre-filled from ACC braking and the user presses on the brakes. user-only pressure?"; -CM_ SG_ 608 ClusterSpeed "Cluster speed signal seems to match dash on newer cars, but is a lower rate and can be noisier."; -CM_ SG_ 761 UserBrakePressure2 "Similar to BRAKE_RELATED->UserBrakePressure"; -CM_ SG_ 1001 VehicleSpeed "Spinouts show here on 2wd. Speed derived from right front wheel (drive tire)"; -BA_DEF_ "UseGMParameterIDs" INT 0 0; -BA_DEF_ "ProtocolType" STRING ; -BA_DEF_ "BusType" STRING ; -BA_DEF_DEF_ "UseGMParameterIDs" 1; -BA_DEF_DEF_ "ProtocolType" "GMLAN"; -BA_DEF_DEF_ "BusType" ""; -BA_ "BusType" "CAN"; -BA_ "ProtocolType" "GMLAN"; -BA_ "UseGMParameterIDs" 0; -VAL_ 497 SystemPowerMode 3 "Crank Request" 2 "Run" 1 "Accessory" 0 "Off"; -VAL_ 497 SystemBackUpPowerMode 3 "Crank Request" 2 "Run" 1 "Accessory" 0 "Off"; -VAL_ 481 DistanceButton 1 "Active" 0 "Inactive" ; -VAL_ 481 LKAButton 1 "Active" 0 "Inactive" ; -VAL_ 481 ACCButtons 6 "Cancel" 5 "Main" 3 "Set" 2 "Resume" 1 "None" ; -VAL_ 481 DriveModeButton 1 "Active" 0 "Inactive" ; -VAL_ 452 CruiseState 4 "Standstill" 3 "Faulted" 1 "Active" 0 "Off" ; -VAL_ 309 PRNDL 3 "R" 2 "D" 1 "N" 0 "P" ; -VAL_ 309 ESPButton 1 "Active" 0 "Inactive" ; -VAL_ 384 LKASteeringCmdActive 1 "Active" 0 "Inactive" ; -VAL_ 842 RRWheelDir 0 "Stationary" 1 "Forward" 2 "Reverse" 3 "Unsupported" 4 "Fault"; -VAL_ 842 RLWheelDir 0 "Stationary" 1 "Forward" 2 "Reverse" 3 "Unsupported" 4 "Fault"; -VAL_ 880 ACCCruiseState 2 "Adaptive" 3 "Adaptive" 4 "Non-adaptive" 5 "Non-adaptive" ; -VAL_ 880 ACCLeadCar 1 "Present" 0 "Not Present" ; -VAL_ 880 ACCGapLevel 3 "Far" 2 "Med" 1 "Near" 0 "Inactive" ; -VAL_ 880 ACCResumeButton 1 "Pressed" 0 "Depressed" ; -VAL_ 880 ACCCmdActive 1 "Active" 0 "Inactive" ; -VAL_ 388 HandsOffSWDetectionMode 2 "Failed" 1 "Enabled" 0 "Disabled" ; -VAL_ 388 HandsOffSWlDetectionStatus 1 "Hands On" 0 "Hands Off" ; -VAL_ 388 LKATorqueDeliveredStatus 3 "Failed" 2 "Temp. Limited" 1 "Active" 0 "Inactive" ; -VAL_ 489 BrakePedalPressed 1 "Pressed" 0 "Depressed" ; -VAL_ 715 GasRegenCmdActiveInv 1 "Inactive" 0 "Active" ; -VAL_ 715 GasRegenCmdActive 1 "Active" 0 "Inactive" ; -VAL_ 320 Intellibeam 1 "Active" 0 "Inactive" ; -VAL_ 320 HighBeamsActive 1 "Active" 0 "Inactive" ; -VAL_ 320 HighBeamsTemporary 1 "Active" 0 "Inactive" ; -VAL_ 501 PRNDL2 6 "L" 4 "D" 3 "N" 2 "R" 1 "P" 0 "Shifting"; -VAL_ 501 TransmissionState 11 "Shifting" 10 "Reverse" 9 "Forward" 8 "Disengaged"; -VAL_ 501 ManualMode 1 "Active" 0 "Inactive" diff --git a/panda/board/obj/body_h7.bin.signed b/panda/board/obj/body_h7.bin.signed index f08d972a..f8c50c0f 100644 Binary files a/panda/board/obj/body_h7.bin.signed and b/panda/board/obj/body_h7.bin.signed differ diff --git a/panda/board/obj/body_h7/bootstub.elf b/panda/board/obj/body_h7/bootstub.elf index e928f540..9bdd11ec 100755 Binary files a/panda/board/obj/body_h7/bootstub.elf and b/panda/board/obj/body_h7/bootstub.elf differ diff --git a/panda/board/obj/body_h7/main.bin b/panda/board/obj/body_h7/main.bin index c47a9cf4..13afad54 100755 Binary files a/panda/board/obj/body_h7/main.bin and b/panda/board/obj/body_h7/main.bin differ diff --git a/panda/board/obj/body_h7/main.elf b/panda/board/obj/body_h7/main.elf index 26dcdf8c..faee7588 100755 Binary files a/panda/board/obj/body_h7/main.elf and b/panda/board/obj/body_h7/main.elf differ diff --git a/panda/board/obj/bootstub.body_h7.bin b/panda/board/obj/bootstub.body_h7.bin index ccec2665..8f8dc686 100755 Binary files a/panda/board/obj/bootstub.body_h7.bin and b/panda/board/obj/bootstub.body_h7.bin differ diff --git a/panda/board/obj/bootstub.panda.bin b/panda/board/obj/bootstub.panda.bin index 859fdab2..4e129a1b 100755 Binary files a/panda/board/obj/bootstub.panda.bin and b/panda/board/obj/bootstub.panda.bin differ diff --git a/panda/board/obj/bootstub.panda_h7.bin b/panda/board/obj/bootstub.panda_h7.bin index 44913911..d42e08f2 100755 Binary files a/panda/board/obj/bootstub.panda_h7.bin and b/panda/board/obj/bootstub.panda_h7.bin differ diff --git a/panda/board/obj/bootstub.panda_h7_remote.bin b/panda/board/obj/bootstub.panda_h7_remote.bin index 44913911..d42e08f2 100755 Binary files a/panda/board/obj/bootstub.panda_h7_remote.bin and b/panda/board/obj/bootstub.panda_h7_remote.bin differ diff --git a/panda/board/obj/bootstub.panda_jungle_h7.bin b/panda/board/obj/bootstub.panda_jungle_h7.bin index 024084d1..4f8c37b1 100755 Binary files a/panda/board/obj/bootstub.panda_jungle_h7.bin and b/panda/board/obj/bootstub.panda_jungle_h7.bin differ diff --git a/panda/board/obj/bootstub.panda_remote.bin b/panda/board/obj/bootstub.panda_remote.bin index 859fdab2..4e129a1b 100755 Binary files a/panda/board/obj/bootstub.panda_remote.bin and b/panda/board/obj/bootstub.panda_remote.bin differ diff --git a/panda/board/obj/gitversion.h b/panda/board/obj/gitversion.h index 71ab066b..d04731af 100644 --- a/panda/board/obj/gitversion.h +++ b/panda/board/obj/gitversion.h @@ -1,2 +1,2 @@ extern const uint8_t gitversion[19]; -const uint8_t gitversion[19] = "DEV-d17d41fb-DEBUG"; +const uint8_t gitversion[19] = "DEV-60a7fb11-DEBUG"; diff --git a/panda/board/obj/panda.bin.signed b/panda/board/obj/panda.bin.signed index 6195b612..0c650c2a 100644 Binary files a/panda/board/obj/panda.bin.signed and b/panda/board/obj/panda.bin.signed differ diff --git a/panda/board/obj/panda/bootstub.elf b/panda/board/obj/panda/bootstub.elf index 3cc7211c..06125f5b 100755 Binary files a/panda/board/obj/panda/bootstub.elf and b/panda/board/obj/panda/bootstub.elf differ diff --git a/panda/board/obj/panda/main.bin b/panda/board/obj/panda/main.bin index f0d1f590..75dd3ae9 100755 Binary files a/panda/board/obj/panda/main.bin and b/panda/board/obj/panda/main.bin differ diff --git a/panda/board/obj/panda/main.elf b/panda/board/obj/panda/main.elf index 6eb51ae3..fdff9927 100755 Binary files a/panda/board/obj/panda/main.elf and b/panda/board/obj/panda/main.elf differ diff --git a/panda/board/obj/panda_h7.bin.signed b/panda/board/obj/panda_h7.bin.signed index ec4ad13a..1e8e353f 100644 Binary files a/panda/board/obj/panda_h7.bin.signed and b/panda/board/obj/panda_h7.bin.signed differ diff --git a/panda/board/obj/panda_h7/bootstub.elf b/panda/board/obj/panda_h7/bootstub.elf index 32b969cf..40ad4d9f 100755 Binary files a/panda/board/obj/panda_h7/bootstub.elf and b/panda/board/obj/panda_h7/bootstub.elf differ diff --git a/panda/board/obj/panda_h7/main.bin b/panda/board/obj/panda_h7/main.bin index 60d1ae49..48fa8308 100755 Binary files a/panda/board/obj/panda_h7/main.bin and b/panda/board/obj/panda_h7/main.bin differ diff --git a/panda/board/obj/panda_h7/main.elf b/panda/board/obj/panda_h7/main.elf index e95a617f..4eeb2a64 100755 Binary files a/panda/board/obj/panda_h7/main.elf and b/panda/board/obj/panda_h7/main.elf differ diff --git a/panda/board/obj/panda_h7_remote.bin.signed b/panda/board/obj/panda_h7_remote.bin.signed index 328a1c3d..29d819fb 100644 Binary files a/panda/board/obj/panda_h7_remote.bin.signed and b/panda/board/obj/panda_h7_remote.bin.signed differ diff --git a/panda/board/obj/panda_h7_remote/bootstub.elf b/panda/board/obj/panda_h7_remote/bootstub.elf index fcf532fb..7aa4cab3 100755 Binary files a/panda/board/obj/panda_h7_remote/bootstub.elf and b/panda/board/obj/panda_h7_remote/bootstub.elf differ diff --git a/panda/board/obj/panda_h7_remote/main.bin b/panda/board/obj/panda_h7_remote/main.bin index 004b0148..d78d074b 100755 Binary files a/panda/board/obj/panda_h7_remote/main.bin and b/panda/board/obj/panda_h7_remote/main.bin differ diff --git a/panda/board/obj/panda_h7_remote/main.elf b/panda/board/obj/panda_h7_remote/main.elf index a2dfaf93..083bd177 100755 Binary files a/panda/board/obj/panda_h7_remote/main.elf and b/panda/board/obj/panda_h7_remote/main.elf differ diff --git a/panda/board/obj/panda_jungle_h7.bin.signed b/panda/board/obj/panda_jungle_h7.bin.signed index 52703056..0c359998 100644 Binary files a/panda/board/obj/panda_jungle_h7.bin.signed and b/panda/board/obj/panda_jungle_h7.bin.signed differ diff --git a/panda/board/obj/panda_jungle_h7/bootstub.elf b/panda/board/obj/panda_jungle_h7/bootstub.elf index 85d7edd3..530d99d6 100755 Binary files a/panda/board/obj/panda_jungle_h7/bootstub.elf and b/panda/board/obj/panda_jungle_h7/bootstub.elf differ diff --git a/panda/board/obj/panda_jungle_h7/main.bin b/panda/board/obj/panda_jungle_h7/main.bin index 3b5f158d..9e1033bb 100755 Binary files a/panda/board/obj/panda_jungle_h7/main.bin and b/panda/board/obj/panda_jungle_h7/main.bin differ diff --git a/panda/board/obj/panda_jungle_h7/main.elf b/panda/board/obj/panda_jungle_h7/main.elf index 4446a9b5..3dde733f 100755 Binary files a/panda/board/obj/panda_jungle_h7/main.elf and b/panda/board/obj/panda_jungle_h7/main.elf differ diff --git a/panda/board/obj/panda_remote.bin.signed b/panda/board/obj/panda_remote.bin.signed index 5f6f4a6c..690cf937 100644 Binary files a/panda/board/obj/panda_remote.bin.signed and b/panda/board/obj/panda_remote.bin.signed differ diff --git a/panda/board/obj/panda_remote/bootstub.elf b/panda/board/obj/panda_remote/bootstub.elf index bb949282..9bc68593 100755 Binary files a/panda/board/obj/panda_remote/bootstub.elf and b/panda/board/obj/panda_remote/bootstub.elf differ diff --git a/panda/board/obj/panda_remote/main.bin b/panda/board/obj/panda_remote/main.bin index 7e42e0f8..1b88b64e 100755 Binary files a/panda/board/obj/panda_remote/main.bin and b/panda/board/obj/panda_remote/main.bin differ diff --git a/panda/board/obj/panda_remote/main.elf b/panda/board/obj/panda_remote/main.elf index 45467650..6ca31b2c 100755 Binary files a/panda/board/obj/panda_remote/main.elf and b/panda/board/obj/panda_remote/main.elf differ diff --git a/panda/board/obj/version b/panda/board/obj/version index 57b311e4..5c83ce11 100644 --- a/panda/board/obj/version +++ b/panda/board/obj/version @@ -1 +1 @@ -DEV-d17d41fb-DEBUG \ No newline at end of file +DEV-60a7fb11-DEBUG \ No newline at end of file diff --git a/scripts/model_compiler.py b/scripts/model_compiler.py deleted file mode 100644 index 18340d06..00000000 --- a/scripts/model_compiler.py +++ /dev/null @@ -1,233 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import codecs -import os -import pickle -import re -import shutil -import subprocess -import sys - -from pathlib import Path - - -REPO_ROOT = Path(__file__).resolve().parents[1] -DEFAULT_INPUT_ROOT = Path("/data/openpilot/uncompiledmodels") -DEFAULT_OUTPUT_ROOT = Path("/data/openpilot/compiledmodels") -COMPILE_SCRIPT = REPO_ROOT / "tinygrad_repo/examples/openpilot/compile3.py" - -COMPONENT_ALIASES = { - "driving_off_policy": ("driving_off_policy", "off_policy", "offpolicy"), - "driving_policy": ("driving_policy", "policy"), - "driving_vision": ("driving_vision", "vision"), -} -REQUIRED_COMPONENTS = {"driving_policy", "driving_vision"} - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - description="Compile staged ONNX driving models into tinygrad pkls without touching selfdrive/modeld/models.", - ) - parser.add_argument("--model", help="Output model key, for example sc2.") - 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("--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.") - - args, unknown = parser.parse_known_args() - dynamic_model_flags = [arg[2:] for arg in unknown if arg.startswith("--")] - invalid = [arg for arg in unknown if not arg.startswith("--")] - if invalid: - parser.error(f"Unexpected arguments: {' '.join(invalid)}") - if len(dynamic_model_flags) > 1: - parser.error("Pass only one dynamic model flag, for example ./models --sc2") - if args.model and dynamic_model_flags and args.model != dynamic_model_flags[0]: - parser.error("Use either --model sc2 or --sc2, not both with different values.") - args.model = args.model or (dynamic_model_flags[0] if dynamic_model_flags else None) - return args - - -def detect_component(path: Path) -> str | None: - stem = path.stem.lower() - for component, aliases in COMPONENT_ALIASES.items(): - if any(alias in stem for alias in aliases): - return component - return None - - -def find_staged_models(input_root: Path) -> dict[str, dict[str, Path]]: - found: dict[str, dict[str, Path]] = {} - if not input_root.is_dir(): - return found - - for child in sorted(input_root.iterdir()): - if not child.is_dir(): - continue - model_files = {} - for onnx_file in sorted(child.glob("*.onnx")): - component = detect_component(onnx_file) - if component: - model_files[component] = onnx_file - if model_files: - found[child.name] = model_files - - flat_root_files = {} - for onnx_file in sorted(input_root.glob("*.onnx")): - component = detect_component(onnx_file) - if component is None: - continue - - model_key = None - lowered = onnx_file.stem.lower() - for alias in COMPONENT_ALIASES[component]: - if lowered == alias: - model_key = None - break - suffix = f"_{alias}" - if lowered.endswith(suffix): - model_key = onnx_file.stem[:-len(suffix)] - break - - if model_key in ("", "driving"): - model_key = None - - if model_key: - found.setdefault(model_key, {})[component] = onnx_file - else: - flat_root_files[component] = onnx_file - - if flat_root_files: - found["_root"] = flat_root_files - - return found - - -def resolve_model_files(input_root: Path, model_key: str) -> dict[str, Path]: - staged = find_staged_models(input_root) - if model_key in staged: - return staged[model_key] - - root_files = staged.get("_root") - if root_files and len(staged) == 1: - return root_files - - prefixed_files = {} - for onnx_file in sorted(input_root.glob(f"{model_key}_*.onnx")): - component = detect_component(onnx_file) - if component: - prefixed_files[component] = onnx_file - return prefixed_files - - -def get_metadata_value_by_name(model, name: str): - for prop in model.metadata_props: - if prop.key == name: - return prop.value - return None - - -def write_metadata(onnx_path: Path, output_path: Path) -> None: - import onnx - - model = onnx.load(str(onnx_path)) - output_slices = get_metadata_value_by_name(model, "output_slices") - if output_slices is None: - raise ValueError(f"output_slices not found in metadata for {onnx_path.name}") - - def get_name_and_shape(value_info) -> tuple[str, tuple[int, ...]]: - shape = tuple(int(dim.dim_value) for dim in value_info.type.tensor_type.shape.dim) - return value_info.name, shape - - metadata = { - "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), - } - - with open(output_path, "wb") as f: - pickle.dump(metadata, f) - - -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, - check=True, - ) - - -def clear_existing_outputs(output_dir: Path) -> list[Path]: - removed = [] - for existing in sorted(output_dir.iterdir()): - if existing.is_file() or existing.is_symlink(): - existing.unlink() - elif existing.is_dir(): - shutil.rmtree(existing) - removed.append(existing) - return removed - - -def list_models(staged: dict[str, dict[str, Path]], input_root: Path) -> int: - if not staged: - print(f"No staged models found in {input_root}") - return 0 - - for model_key, files in sorted(staged.items()): - print(model_key) - for component, path in sorted(files.items()): - print(f" {component}: {path}") - return 0 - - -def main() -> int: - args = parse_args() - staged = find_staged_models(args.input_dir) - - if args.list: - return list_models(staged, args.input_dir) - - if not args.model: - available = ", ".join(sorted(k for k in staged if k != "_root")) - raise SystemExit(f"Choose a model key, for example ./models --sc2. Available staged models: {available or 'none'}") - - model_key = args.model.strip() - files = resolve_model_files(args.input_dir, model_key) - if not files: - raise SystemExit( - f"No staged ONNX files found for {model_key} in {args.input_dir}. " - f"Use {args.input_dir}/driving_policy.onnx and {args.input_dir}/driving_vision.onnx, " - 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)}") - - args.output_dir.mkdir(parents=True, exist_ok=True) - print(f"Compiling {model_key} 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()): - output_pkl = args.output_dir / f"{model_key}_{component}_tinygrad.pkl" - output_metadata = args.output_dir / f"{model_key}_{component}_metadata.pkl" - - print(f" compiling {component}: {onnx_path.name}") - compile_component(onnx_path, output_pkl) - write_metadata(onnx_path, output_metadata) - print(f" saved {output_pkl.name}") - print(f" saved {output_metadata.name}") - - print("Done.") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/selfdrive/assets/icons_mici/settings/horizontal_scroll_indicator.png b/selfdrive/assets/icons_mici/settings/horizontal_scroll_indicator.png deleted file mode 100644 index 4b848657..00000000 Binary files a/selfdrive/assets/icons_mici/settings/horizontal_scroll_indicator.png and /dev/null differ diff --git a/selfdrive/modeld/dmonitoringmodeld.py b/selfdrive/modeld/dmonitoringmodeld.py index 28190db3..3e357ee0 100755 --- a/selfdrive/modeld/dmonitoringmodeld.py +++ b/selfdrive/modeld/dmonitoringmodeld.py @@ -25,6 +25,7 @@ MODEL_PKL_PATH = Path(__file__).parent / 'models/dmonitoring_model_tinygrad.pkl' METADATA_PATH = Path(__file__).parent / 'models/dmonitoring_model_metadata.pkl' MODELS_DIR = Path(__file__).parent / 'models' + class ModelState: inputs: dict[str, np.ndarray] output: np.ndarray @@ -45,8 +46,42 @@ class ModelState: self.tensor_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()} self._blob_cache : dict[int, Tensor] = {} self.image_warp = None + self._warp_rebuild_attempted: set[tuple[int, int]] = set() + self._warp_backend_rebuild_attempted: set[tuple[int, int]] = set() self.model_run = pickle.loads(read_file_chunked(str(MODEL_PKL_PATH))) + def _load_or_rebuild_dm_warp(self, width: int, height: int): + warp_path = MODELS_DIR / f'dm_warp_{width}x{height}_tinygrad.pkl' + resolution_key = (width, height) + + def load_warp(): + with open(warp_path, "rb") as f: + return pickle.load(f) + + try: + return load_warp() + except Exception as error: + if resolution_key in self._warp_rebuild_attempted: + raise + + self._warp_rebuild_attempted.add(resolution_key) + cloudlog.exception(f"Failed to load DM warp artifact {warp_path}: {error}") + cloudlog.warning(f"Rebuilding DM warp artifact for {width}x{height}") + + try: + warp_path.unlink(missing_ok=True) + except Exception: + pass + + from openpilot.selfdrive.modeld.compile_warp import compile_dm_warp + compile_dm_warp(width, height) + + try: + return load_warp() + except Exception as retry_error: + cloudlog.exception(f"Reload failed after rebuilding {warp_path}: {retry_error}") + raise + def run(self, buf: VisionBuf, calib: np.ndarray, transform: np.ndarray) -> tuple[np.ndarray, float]: self.numpy_inputs['calib'][0,:] = calib @@ -54,16 +89,33 @@ class ModelState: if self.image_warp is None: self.frame_buf_params = get_nv12_info(buf.width, buf.height) - warp_path = MODELS_DIR / f'dm_warp_{buf.width}x{buf.height}_tinygrad.pkl' - with open(warp_path, "rb") as f: - self.image_warp = pickle.load(f) + self.image_warp = self._load_or_rebuild_dm_warp(buf.width, buf.height) ptr = buf.data.ctypes.data # There is a ringbuffer of imgs, just cache tensors pointing to all of them if ptr not in self._blob_cache: self._blob_cache[ptr] = Tensor.from_blob(ptr, (self.frame_buf_params[3],), dtype='uint8') self.warp_inputs_np['transform'][:] = transform[:] - self.tensor_inputs['input_img'] = self.image_warp(self._blob_cache[ptr], self.warp_inputs['transform']).realize() + resolution_key = (buf.width, buf.height) + try: + self.tensor_inputs['input_img'] = self.image_warp(self._blob_cache[ptr], self.warp_inputs['transform']).realize() + except AssertionError as error: + # Handle runtime backend mismatch (e.g. CPU-captured warp artifact on QCOM device). + if "args mismatch in JIT" not in str(error) or resolution_key in self._warp_backend_rebuild_attempted: + raise + + self._warp_backend_rebuild_attempted.add(resolution_key) + cloudlog.warning(f"DM warp JIT backend mismatch for {buf.width}x{buf.height}; rebuilding artifact for active backend") + warp_path = MODELS_DIR / f'dm_warp_{buf.width}x{buf.height}_tinygrad.pkl' + try: + warp_path.unlink(missing_ok=True) + except Exception: + pass + + from openpilot.selfdrive.modeld.compile_warp import compile_dm_warp + compile_dm_warp(buf.width, buf.height) + self.image_warp = self._load_or_rebuild_dm_warp(buf.width, buf.height) + self.tensor_inputs['input_img'] = self.image_warp(self._blob_cache[ptr], self.warp_inputs['transform']).realize() output = self.model_run(**self.tensor_inputs).contiguous().realize().uop.base.buffer.numpy().flatten() diff --git a/selfdrive/modeld/models/dmonitoring_model.onnx b/selfdrive/modeld/models/dmonitoring_model.onnx index 7d59ce24..0e08fe94 100644 Binary files a/selfdrive/modeld/models/dmonitoring_model.onnx and b/selfdrive/modeld/models/dmonitoring_model.onnx differ diff --git a/selfdrive/modeld/models/dmonitoring_model_metadata.pkl b/selfdrive/modeld/models/dmonitoring_model_metadata.pkl index 71e4b289..efcdd4c3 100644 Binary files a/selfdrive/modeld/models/dmonitoring_model_metadata.pkl and b/selfdrive/modeld/models/dmonitoring_model_metadata.pkl differ diff --git a/selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl b/selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl index 299065b5..f80ca5a2 100644 Binary files a/selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl and b/selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl differ diff --git a/selfdrive/monitoring/dmonitoringd.py b/selfdrive/monitoring/dmonitoringd.py index d2a6163a..fe51af1c 100644 --- a/selfdrive/monitoring/dmonitoringd.py +++ b/selfdrive/monitoring/dmonitoringd.py @@ -48,11 +48,16 @@ def dmonitoringd_thread(): DM.always_on = params.get_bool("AlwaysOnDM") demo_mode = params.get_bool("IsDriverViewEnabled") and sm["carState"].gearShifter != GearShifter.reverse - # save rhd virtual toggle every 5 mins + # save rhd virtual toggle every 5 mins, but only with clear confidence. if (sm['driverStateV2'].frameId % 6000 == 0 and not demo_mode and - DM.wheelpos.prob_offseter.filtered_stat.n > DM.settings._WHEELPOS_FILTER_MIN_COUNT and - DM.wheel_on_right == (DM.wheelpos.prob_offseter.filtered_stat.M > DM.settings._WHEELPOS_THRESHOLD)): - params.put_bool_nonblocking("IsRhdDetected", DM.wheel_on_right) + DM.wheelpos.prob_offseter.filtered_stat.n > DM.settings._WHEELPOS_FILTER_MIN_COUNT): + wheelpos_mean = DM.wheelpos.prob_offseter.filtered_stat.M + save_rhd = DM.settings._WHEELPOS_THRESHOLD_ENTER_RHD + DM.settings._WHEELPOS_SAVE_MARGIN + save_lhd = DM.settings._WHEELPOS_THRESHOLD_ENTER_LHD - DM.settings._WHEELPOS_SAVE_MARGIN + if wheelpos_mean >= save_rhd: + params.put_bool_nonblocking("IsRhdDetected", True) + elif wheelpos_mean <= save_lhd: + params.put_bool_nonblocking("IsRhdDetected", False) def main(): dmonitoringd_thread() diff --git a/selfdrive/monitoring/helpers.py b/selfdrive/monitoring/helpers.py index ca569627..70945f8c 100644 --- a/selfdrive/monitoring/helpers.py +++ b/selfdrive/monitoring/helpers.py @@ -35,7 +35,11 @@ class DRIVER_MONITOR_SETTINGS: self._EYE_THRESHOLD = 0.65 self._SG_THRESHOLD = 0.9 self._BLINK_THRESHOLD = 0.865 - self._PHONE_THRESH = 0.5 + + self._PHONE_THRESH = 0.75 if device_type == 'mici' else 0.4 + self._PHONE_THRESH2 = 15.0 + self._PHONE_MAX_OFFSET = 0.06 + self._PHONE_MIN_OFFSET = 0.025 self._POSE_PITCH_THRESHOLD = 0.3133 self._POSE_PITCH_THRESHOLD_SLACK = 0.3237 @@ -46,8 +50,6 @@ class DRIVER_MONITOR_SETTINGS: self._PITCH_NATURAL_OFFSET = 0.011 # initial value before offset is learned self._PITCH_NATURAL_THRESHOLD = 0.449 self._YAW_NATURAL_OFFSET = 0.075 # initial value before offset is learned - self._PITCH_NATURAL_VAR = 3*0.01 - self._YAW_NATURAL_VAR = 3*0.05 self._PITCH_MAX_OFFSET = 0.124 self._PITCH_MIN_OFFSET = -0.0881 self._YAW_MAX_OFFSET = 0.289 @@ -68,9 +70,18 @@ class DRIVER_MONITOR_SETTINGS: self._WHEELPOS_CALIB_MIN_SPEED = 11 self._WHEELPOS_THRESHOLD = 0.5 self._WHEELPOS_FILTER_MIN_COUNT = int(15 / self._DT_DMON) # allow 15 seconds to converge wheel side - self._WHEELPOS_DATA_AVG = 0.03 - self._WHEELPOS_DATA_VAR = 3*5.5e-5 - self._WHEELPOS_MAX_COUNT = -1 + self._WHEELPOS_THRESHOLD_ENTER_RHD = self._WHEELPOS_THRESHOLD + self._WHEELPOS_THRESHOLD_ENTER_LHD = self._WHEELPOS_THRESHOLD + self._WHEELPOS_SAVE_MARGIN = 0.0 + self._WHEELPOS_STARTUP_OVERRIDE_RHD = 0.55 + self._WHEELPOS_STARTUP_OVERRIDE_LHD = 0.45 + + # C4 (mici) has shown borderline wheel-side probabilities around 0.5x. + # Use hysteresis and stricter persistence thresholds to avoid false RHD latching. + if device_type == 'mici': + self._WHEELPOS_THRESHOLD_ENTER_RHD = 0.65 + self._WHEELPOS_THRESHOLD_ENTER_LHD = 0.35 + self._WHEELPOS_SAVE_MARGIN = 0.05 self._RECOVERY_FACTOR_MAX = 5. # relative to minus step change self._RECOVERY_FACTOR_MIN = 1.25 # relative to minus step change @@ -85,26 +96,24 @@ class DistractedType: DISTRACTED_PHONE = 1 << 2 class DriverPose: - def __init__(self, settings): - pitch_filter_raw_priors = (settings._PITCH_NATURAL_OFFSET, settings._PITCH_NATURAL_VAR, 2) - yaw_filter_raw_priors = (settings._YAW_NATURAL_OFFSET, settings._YAW_NATURAL_VAR, 2) + def __init__(self, max_trackable): self.yaw = 0. self.pitch = 0. self.roll = 0. self.yaw_std = 0. self.pitch_std = 0. self.roll_std = 0. - self.pitch_offseter = RunningStatFilter(raw_priors=pitch_filter_raw_priors, max_trackable=settings._POSE_OFFSET_MAX_COUNT) - self.yaw_offseter = RunningStatFilter(raw_priors=yaw_filter_raw_priors, max_trackable=settings._POSE_OFFSET_MAX_COUNT) + self.pitch_offseter = RunningStatFilter(max_trackable=max_trackable) + self.yaw_offseter = RunningStatFilter(max_trackable=max_trackable) self.calibrated = False self.low_std = True self.cfactor_pitch = 1. self.cfactor_yaw = 1. class DriverProb: - def __init__(self, raw_priors, max_trackable): + def __init__(self, max_trackable): self.prob = 0. - self.prob_offseter = RunningStatFilter(raw_priors=raw_priors, max_trackable=max_trackable) + self.prob_offseter = RunningStatFilter(max_trackable=max_trackable) self.prob_calibrated = False class DriverBlink: @@ -143,11 +152,10 @@ class DriverMonitoring: self.settings = settings if settings is not None else DRIVER_MONITOR_SETTINGS(device_type=HARDWARE.get_device_type()) # init driver status - wheelpos_filter_raw_priors = (self.settings._WHEELPOS_DATA_AVG, self.settings._WHEELPOS_DATA_VAR, 2) - self.wheelpos = DriverProb(raw_priors=wheelpos_filter_raw_priors, max_trackable=self.settings._WHEELPOS_MAX_COUNT) - self.pose = DriverPose(settings=self.settings) + self.wheelpos = DriverProb(-1) + self.pose = DriverPose(self.settings._POSE_OFFSET_MAX_COUNT) + self.phone = DriverProb(self.settings._POSE_OFFSET_MAX_COUNT) self.blink = DriverBlink() - self.phone_prob = 0. self.always_on = always_on self.distracted_types = [] @@ -248,7 +256,12 @@ class DriverMonitoring: if (self.blink.left + self.blink.right)*0.5 > self.settings._BLINK_THRESHOLD: distracted_types.append(DistractedType.DISTRACTED_BLINK) - if self.phone_prob > self.settings._PHONE_THRESH: + if self.phone.prob_calibrated: + using_phone = self.phone.prob > max(min(self.phone.prob_offseter.filtered_stat.M, self.settings._PHONE_MAX_OFFSET), self.settings._PHONE_MIN_OFFSET) \ + * self.settings._PHONE_THRESH2 + else: + using_phone = self.phone.prob > self.settings._PHONE_THRESH + if using_phone: distracted_types.append(DistractedType.DISTRACTED_PHONE) return distracted_types @@ -261,8 +274,34 @@ class DriverMonitoring: self.wheelpos.prob_offseter.push_and_update(rhd_pred) self.wheelpos.prob_calibrated = self.wheelpos.prob_offseter.filtered_stat.n > self.settings._WHEELPOS_FILTER_MIN_COUNT + startup_override = None + if not self.wheelpos.prob_calibrated and not demo_mode and not op_engaged: + left_face_detected = driver_state.leftDriverData.faceProb > self.settings._FACE_THRESHOLD + right_face_detected = driver_state.rightDriverData.faceProb > self.settings._FACE_THRESHOLD + if rhd_pred <= self.settings._WHEELPOS_STARTUP_OVERRIDE_LHD and left_face_detected and not right_face_detected: + startup_override = False + elif rhd_pred >= self.settings._WHEELPOS_STARTUP_OVERRIDE_RHD and right_face_detected and not left_face_detected: + startup_override = True + if self.wheelpos.prob_calibrated or demo_mode: - self.wheel_on_right = self.wheelpos.prob_offseter.filtered_stat.M > self.settings._WHEELPOS_THRESHOLD + wheelpos_mean = self.wheelpos.prob_offseter.filtered_stat.M + enter_rhd = self.settings._WHEELPOS_THRESHOLD_ENTER_RHD + enter_lhd = self.settings._WHEELPOS_THRESHOLD_ENTER_LHD + + # Hysteresis: avoid side flapping near 0.5 and preserve last stable side. + if self.wheel_on_right_last is None: + if wheelpos_mean >= enter_rhd: + self.wheel_on_right = True + elif wheelpos_mean <= enter_lhd: + self.wheel_on_right = False + else: + self.wheel_on_right = self.wheel_on_right_default + elif self.wheel_on_right_last: + self.wheel_on_right = wheelpos_mean > enter_lhd + else: + self.wheel_on_right = wheelpos_mean >= enter_rhd + elif startup_override is not None: + self.wheel_on_right = startup_override else: self.wheel_on_right = self.wheel_on_right_default # use default/saved if calibration is unfinished # make sure no switching when engaged @@ -286,7 +325,7 @@ class DriverMonitoring: * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD) self.blink.right = driver_data.rightBlinkProb * (driver_data.rightEyeProb > self.settings._EYE_THRESHOLD) \ * (driver_data.sunglassesProb < self.settings._SG_THRESHOLD) - self.phone_prob = driver_data.phoneProb + self.phone.prob = driver_data.phoneProb self.distracted_types = self._get_distracted_types() self.driver_distracted = (DistractedType.DISTRACTED_PHONE in self.distracted_types @@ -300,9 +339,11 @@ class DriverMonitoring: if self.face_detected and car_speed > self.settings._POSE_CALIB_MIN_SPEED and self.pose.low_std and (not op_engaged or not self.driver_distracted): self.pose.pitch_offseter.push_and_update(self.pose.pitch) self.pose.yaw_offseter.push_and_update(self.pose.yaw) + self.phone.prob_offseter.push_and_update(self.phone.prob) self.pose.calibrated = self.pose.pitch_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT and \ self.pose.yaw_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT + self.phone.prob_calibrated = self.phone.prob_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT if self.face_detected and not self.driver_distracted: if model_std_max > self.settings._DCAM_UNCERTAIN_ALERT_THRESHOLD: @@ -408,8 +449,8 @@ class DriverMonitoring: "posePitchValidCount": self.pose.pitch_offseter.filtered_stat.n, "poseYawOffset": self.pose.yaw_offseter.filtered_stat.mean(), "poseYawValidCount": self.pose.yaw_offseter.filtered_stat.n, - "phoneProbOffset": 0., - "phoneProbValidCount": 0, + "phoneProbOffset": self.phone.prob_offseter.filtered_stat.mean(), + "phoneProbValidCount": self.phone.prob_offseter.filtered_stat.n, "stepChange": self.step_change, "awarenessActive": self.awareness_active, "awarenessPassive": self.awareness_passive, diff --git a/selfdrive/monitoring/test_monitoring.py b/selfdrive/monitoring/test_monitoring.py index 6ea9b802..46fe72b1 100644 --- a/selfdrive/monitoring/test_monitoring.py +++ b/selfdrive/monitoring/test_monitoring.py @@ -30,6 +30,23 @@ def make_msg(face_detected, distracted=False, model_uncertain=False): return ds +def make_dual_msg(left_face_prob, right_face_prob, wheel_on_right_prob=0., model_uncertain=False): + ds = log.DriverStateV2.new_message() + ds.wheelOnRightProb = wheel_on_right_prob + for side, face_prob in ((ds.leftDriverData, left_face_prob), (ds.rightDriverData, right_face_prob)): + side.faceOrientation = [0., 0., 0.] + side.facePosition = [0., 0.] + side.faceProb = face_prob + side.leftEyeProb = 1. + side.rightEyeProb = 1. + side.leftBlinkProb = 0. + side.rightBlinkProb = 0. + side.faceOrientationStd = [1.*model_uncertain, 1.*model_uncertain, 1.*model_uncertain] + side.facePositionStd = [1.*model_uncertain, 1.*model_uncertain] + side.phoneProb = 0. + return ds + + # driver state from neural net, 10Hz msg_NO_FACE_DETECTED = make_msg(False) msg_ATTENTIVE = make_msg(True) @@ -71,6 +88,16 @@ class TestMonitoring: events, _ = self._run_seq(always_attentive, always_false, always_true, always_false) self._assert_no_events(events) + def test_saved_rhd_recovers_to_lhd_with_strong_left_face(self): + settings = DRIVER_MONITOR_SETTINGS(device_type='mici') + DM = DriverMonitoring(rhd_saved=True, settings=settings) + msg = make_dual_msg(left_face_prob=0.95, right_face_prob=0.2, wheel_on_right_prob=0.35) + + DM._update_states(msg, [0, 0, 0], 0, False, False) + + assert not DM.wheel_on_right + assert DM.face_detected + # engaged, driver is distracted and does nothing def test_fully_distracted_driver(self): events, d_status = self._run_seq(always_distracted, always_false, always_true, always_false) @@ -203,4 +230,3 @@ class TestMonitoring: events[int((INVISIBLE_SECONDS_TO_ORANGE-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names assert EventName.driverUnresponsive in \ events[int((INVISIBLE_SECONDS_TO_RED-1+DT_DMON*d_status.settings._HI_STD_FALLBACK_TIME+0.1)/DT_DMON)].names - diff --git a/selfdrive/ui/mici/layouts/settings/developer.py b/selfdrive/ui/mici/layouts/settings/developer.py index 05f99bec..b1c4cab5 100644 --- a/selfdrive/ui/mici/layouts/settings/developer.py +++ b/selfdrive/ui/mici/layouts/settings/developer.py @@ -91,7 +91,7 @@ class DeveloperLayoutMici(NavWidget): self._long_maneuver_toggle, self._alpha_long_toggle, self._debug_mode_toggle, - ], snap_items=False, scroll_indicator=True, edge_shadows=True) + ], snap_items=False) # Toggle lists self._refresh_toggles = ( diff --git a/selfdrive/ui/mici/layouts/settings/device.py b/selfdrive/ui/mici/layouts/settings/device.py index 70a8e8ca..e37869ee 100644 --- a/selfdrive/ui/mici/layouts/settings/device.py +++ b/selfdrive/ui/mici/layouts/settings/device.py @@ -76,8 +76,6 @@ def _engaged_confirmation_callback(callback: Callable, action_text: str): icon = "icons_mici/settings/device/reboot.png" elif action_text == "reset": icon = "icons_mici/settings/device/lkas.png" - elif action_text == "reset driver monitoring": - icon = "icons_mici/settings/device/cameras.png" elif action_text == "uninstall": icon = "icons_mici/settings/device/uninstall.png" else: @@ -85,7 +83,7 @@ def _engaged_confirmation_callback(callback: Callable, action_text: str): icon = "icons_mici/settings/comma_icon.png" dlg: BigConfirmationDialogV2 | BigDialog = BigConfirmationDialogV2(f"slide to\n{action_text.lower()}", icon, red=red, - exit_on_confirm=action_text in {"reset", "reset driver monitoring"}, + exit_on_confirm=action_text == "reset", confirm_callback=confirm_callback) gui_app.set_modal_overlay(dlg) else: @@ -461,17 +459,9 @@ class DeviceLayoutMici(NavWidget): params.remove("LiveDelay") params.put_bool("OnroadCycleRequested", True) - def reset_driver_monitoring_callback(): - params = ui_state.params - params.remove("IsRhdDetected") - params.put_bool("OnroadCycleRequested", True) - def uninstall_openpilot_callback(): ui_state.params.put_bool("DoUninstall", True) - reset_driver_monitoring_btn = BigButton("reset driver monitoring calibration", "", "icons_mici/settings/device/cameras.png") - reset_driver_monitoring_btn.set_click_callback(lambda: _engaged_confirmation_callback(reset_driver_monitoring_callback, "reset driver monitoring")) - reset_calibration_btn = BigButton("reset calibration", "", "icons_mici/settings/device/lkas.png") reset_calibration_btn.set_click_callback(lambda: _engaged_confirmation_callback(reset_calibration_callback, "reset")) @@ -518,14 +508,13 @@ class DeviceLayoutMici(NavWidget): PairBigButton(), review_training_guide_btn, driver_cam_btn, - reset_driver_monitoring_btn, # lang_button, reset_calibration_btn, uninstall_openpilot_btn, regulatory_btn, reboot_btn, self._power_off_btn, - ], snap_items=False, scroll_indicator=True, edge_shadows=True) + ], snap_items=False) # Set up back navigation self.set_back_callback(back_callback) diff --git a/selfdrive/ui/mici/layouts/settings/network/__init__.py b/selfdrive/ui/mici/layouts/settings/network/__init__.py index 0326f71b..1faf4931 100644 --- a/selfdrive/ui/mici/layouts/settings/network/__init__.py +++ b/selfdrive/ui/mici/layouts/settings/network/__init__.py @@ -3,7 +3,7 @@ from enum import IntEnum from collections.abc import Callable from openpilot.system.ui.widgets.scroller import Scroller -from openpilot.selfdrive.ui.mici.layouts.settings.network.wifi_ui import WifiUIMici, WifiIcon, normalize_ssid +from openpilot.selfdrive.ui.mici.layouts.settings.network.wifi_ui import WifiUIMici from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigMultiToggle, BigToggle, BigParamControl from openpilot.selfdrive.ui.mici.widgets.dialog import BigInputDialog from openpilot.selfdrive.ui.ui_state import ui_state @@ -75,14 +75,8 @@ class NetworkLayoutMici(NavWidget): self._network_metered_btn = BigMultiToggle("network usage", ["default", "metered", "unmetered"], select_callback=network_metered_callback) self._network_metered_btn.set_enabled(False) - self._wifi_slash_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_slash.png", 64, 56) - self._wifi_low_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_low.png", 64, 47) - self._wifi_medium_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_medium.png", 64, 47) - self._wifi_full_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_full.png", 64, 47) - - wifi_button = BigButton("wi-fi", "not connected", self._wifi_slash_txt) + wifi_button = BigButton("wi-fi") wifi_button.set_click_callback(lambda: self._switch_to_panel(NetworkPanelType.WIFI)) - self._wifi_button = wifi_button # ******** Advanced settings ******** # ******** Roaming toggle ******** @@ -107,7 +101,7 @@ class NetworkLayoutMici(NavWidget): self._cellular_metered_btn, # */ self._ip_address_btn, - ], snap_items=False, scroll_indicator=True, edge_shadows=True) + ], snap_items=False) # Set initial config roaming_enabled = ui_state.params.get_bool("GsmRoaming") diff --git a/selfdrive/ui/mici/layouts/settings/settings.py b/selfdrive/ui/mici/layouts/settings/settings.py index 3471b348..41267f16 100644 --- a/selfdrive/ui/mici/layouts/settings/settings.py +++ b/selfdrive/ui/mici/layouts/settings/settings.py @@ -90,7 +90,7 @@ class SettingsLayout(NavWidget): #BigDialogButton("manual", "", "icons_mici/settings/manual_icon.png", "Check out the mici user\nmanual at comma.ai/setup"), firehose_btn, developer_btn, - ], snap_items=False, scroll_indicator=True, edge_shadows=True) + ], snap_items=False) # Set up back navigation self.set_back_callback(self.close_settings) diff --git a/selfdrive/ui/mici/layouts/settings/toggles.py b/selfdrive/ui/mici/layouts/settings/toggles.py index b847fe74..c16504fa 100644 --- a/selfdrive/ui/mici/layouts/settings/toggles.py +++ b/selfdrive/ui/mici/layouts/settings/toggles.py @@ -35,7 +35,7 @@ class TogglesLayoutMici(NavWidget): record_front, record_mic, enable_openpilot, - ], snap_items=False, scroll_indicator=True, edge_shadows=True) + ], snap_items=False) # Toggle lists self._refresh_toggles = ( diff --git a/selfdrive/ui/mici/onroad/augmented_road_view.py b/selfdrive/ui/mici/onroad/augmented_road_view.py index 1575a2f8..75291fb7 100644 --- a/selfdrive/ui/mici/onroad/augmented_road_view.py +++ b/selfdrive/ui/mici/onroad/augmented_road_view.py @@ -214,10 +214,6 @@ class AugmentedRoadView(CameraView): # debug self._pm = messaging.PubMaster(['uiDebug']) - @staticmethod - def _controls_ready() -> bool: - return ui_state.sm.recv_frame["selfdriveState"] >= ui_state.started_frame - def is_swiping_left(self) -> bool: """Check if currently swiping left (for scroller to disable).""" return self._bookmark_icon.is_swiping_left() @@ -228,8 +224,6 @@ class AugmentedRoadView(CameraView): # update offroad label if ui_state.panda_type == log.PandaState.PandaType.unknown: self._offroad_label.set_text("system booting") - elif ui_state.started and not self._controls_ready(): - self._offroad_label.set_text("waiting for\ncontrols to start") else: self._offroad_label.set_text("start the car to\nuse openpilot") @@ -265,21 +259,6 @@ class AugmentedRoadView(CameraView): # Render the base camera view super()._render(self._content_rect) - waiting_for_controls = ui_state.started and not self._controls_ready() - if waiting_for_controls: - rl.draw_rectangle(int(self._content_rect.x), int(self._content_rect.y), - int(self._content_rect.width), int(self._content_rect.height), - rl.Color(0, 0, 0, 145)) - self._offroad_label.render(self._content_rect) - rl.end_scissor_mode() - self._draw_border() - self._bookmark_icon.render(self.rect) - - msg = messaging.new_message('uiDebug') - msg.uiDebug.drawTimeMillis = (time.monotonic() - start_draw) * 1000 - self._pm.send('uiDebug', msg) - return - in_reverse = self._is_in_reverse() # Draw all UI overlays diff --git a/selfdrive/ui/mici/widgets/button.py b/selfdrive/ui/mici/widgets/button.py index b500f143..be08e0fe 100644 --- a/selfdrive/ui/mici/widgets/button.py +++ b/selfdrive/ui/mici/widgets/button.py @@ -110,7 +110,6 @@ class BigButton(Widget): self.text = text self.value = value self.set_icon(icon) - self._label_font_size_override: int | None = None self._scale_filter = BounceFilter(1.0, 0.1, 1 / gui_app.target_fps) @@ -137,18 +136,6 @@ class BigButton(Widget): def set_icon(self, icon: Union[str, rl.Texture]): self._txt_icon = gui_app.texture(icon, 64, 64) if isinstance(icon, str) and len(icon) else icon - def _refresh_label_metrics(self): - font_size = self._label_font_size_override if self._label_font_size_override is not None else self._get_label_font_size() - self._label.set_font_size(font_size) - self._needs_scroll = measure_text_cached(self._label_font, self.text, font_size).x + 25 > self._rect.width - self._scroll_offset = 0 - self._scroll_timer = 0 - self._scroll_state = ScrollState.PRE_SCROLL - - def _set_label_font_size_override(self, font_size: int | None): - self._label_font_size_override = font_size - self._refresh_label_metrics() - def set_rotate_icon(self, rotate: bool): if rotate and self._rotate_icon_t is not None: return @@ -178,12 +165,10 @@ class BigButton(Widget): def set_text(self, text: str): self.text = text self._label.set_text(text) - self._refresh_label_metrics() def set_value(self, value: str): self.value = value self._sub_label.set_text(value) - self._refresh_label_metrics() def get_value(self) -> str: return self.value @@ -271,7 +256,7 @@ class BigToggle(BigButton): self._checked = initial_state self._toggle_callback = toggle_callback - self._set_label_font_size_override(48) + self._label.set_font_size(48) def _load_images(self): super()._load_images() @@ -311,8 +296,8 @@ class BigMultiToggle(BigToggle): self._select_callback = select_callback self._label.set_width(int(self._rect.width - LABEL_HORIZONTAL_PADDING * 2 - self._txt_enabled_toggle.width)) - # Keep the title size stable when the selected option changes. - self._set_label_font_size_override(self._get_label_font_size()) + # TODO: why isn't this automatic? + self._label.set_font_size(self._get_label_font_size()) self.set_value(self._options[0]) diff --git a/selfdrive/ui/mici/widgets/dialog.py b/selfdrive/ui/mici/widgets/dialog.py index 5f201766..34760925 100644 --- a/selfdrive/ui/mici/widgets/dialog.py +++ b/selfdrive/ui/mici/widgets/dialog.py @@ -113,14 +113,6 @@ class BigConfirmationDialogV2(BigDialogBase): self._slider = BigSlider(title, icon_txt, confirm_callback=self._on_confirm) self._slider.set_enabled(lambda: not self._swiping_away) - def show_event(self): - super().show_event() - self._slider.show_event() - - def hide_event(self): - super().hide_event() - self._slider.hide_event() - def _on_confirm(self): if self._confirm_callback: self._confirm_callback() @@ -130,7 +122,7 @@ class BigConfirmationDialogV2(BigDialogBase): def _update_state(self): super()._update_state() if self._swiping_away and not self._slider.confirmed: - self._slider.reset(reset_shimmer=False) + self._slider.reset() def _render(self, _) -> DialogResult: self._slider.render(self._rect) diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 65568e71..e54c6f6f 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -363,26 +363,6 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { connect(dcamBtn, &ButtonControl::clicked, [=]() { emit showDriverView(); }); addItem(dcamBtn); - resetDmCalibBtn = new ButtonControl( - tr("Reset Driver Monitoring"), - tr("RESET"), - tr("Clears the saved driver monitoring wheel-side calibration if the device thinks you're seated on the wrong side. " - "Resetting will restart openpilot if the car is powered on.") - ); - connect(resetDmCalibBtn, &ButtonControl::clicked, [&]() { - if (!uiState()->engaged()) { - if (ConfirmationDialog::confirm(tr("Are you sure you want to reset driver monitoring calibration?"), tr("Reset"), this)) { - if (!uiState()->engaged()) { - params.remove("IsRhdDetected"); - params.putBool("OnroadCycleRequested", true); - } - } - } else { - ConfirmationDialog::alert(tr("Disengage to Reset Driver Monitoring"), this); - } - }); - addItem(resetDmCalibBtn); - resetCalibBtn = new ButtonControl(tr("Reset Calibration"), tr("RESET"), ""); connect(resetCalibBtn, &ButtonControl::showDescriptionEvent, this, &DevicePanel::updateCalibDescription); connect(resetCalibBtn, &ButtonControl::clicked, [&]() { @@ -440,7 +420,7 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { }); QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { for (auto btn : findChildren()) { - if (btn != pair_device && btn != resetCalibBtn && btn != resetDmCalibBtn) { + if (btn != pair_device && btn != resetCalibBtn) { btn->setEnabled(offroad); } } diff --git a/selfdrive/ui/qt/offroad/settings.h b/selfdrive/ui/qt/offroad/settings.h index 252b5062..438ee0eb 100644 --- a/selfdrive/ui/qt/offroad/settings.h +++ b/selfdrive/ui/qt/offroad/settings.h @@ -94,7 +94,6 @@ private: ButtonControl *pair_galaxy; QPushButton *galaxy_qr_btn; ButtonControl *resetCalibBtn; - ButtonControl *resetDmCalibBtn; }; class TogglesPanel : public ListWidget { diff --git a/selfdrive/ui/ui b/selfdrive/ui/ui index e1077059..2035f80e 100755 Binary files a/selfdrive/ui/ui and b/selfdrive/ui/ui differ diff --git a/system/ui/lib/wifi_manager.py b/system/ui/lib/wifi_manager.py index 5296cfaa..b09db0ab 100644 --- a/system/ui/lib/wifi_manager.py +++ b/system/ui/lib/wifi_manager.py @@ -324,14 +324,6 @@ class WifiManager: def ipv4_address(self) -> str: return self._ipv4_address - @property - def networks(self) -> list[Network]: - return list(self._networks) - - @property - def connecting_to_ssid(self) -> str: - return self._connecting_to_ssid - @property def current_network_metered(self) -> MeteredType: return self._current_network_metered diff --git a/system/ui/mici_setup.py b/system/ui/mici_setup.py index 079267b6..3624fd77 100644 --- a/system/ui/mici_setup.py +++ b/system/ui/mici_setup.py @@ -133,17 +133,11 @@ class SoftwareSelectionPage(Widget): super().__init__() self._openpilot_slider = LargerSlider("slide to use\nstarpilot", use_openpilot_callback) - self._custom_software_slider = LargerSlider("slide to use\ncustom software", use_custom_software_callback, - green=False, shimmer_offset=0.4) - - def show_event(self): - super().show_event() - self._openpilot_slider.show_event() - self._custom_software_slider.show_event() + self._custom_software_slider = LargerSlider("slide to use\ncustom software", use_custom_software_callback, green=False) def reset(self): - self._openpilot_slider.reset(reset_shimmer=False) - self._custom_software_slider.reset(reset_shimmer=False) + self._openpilot_slider.reset() + self._custom_software_slider.reset() def _render(self, rect: rl.Rectangle): self._openpilot_slider.set_opacity(1.0 - self._custom_software_slider.slider_percentage) diff --git a/system/ui/widgets/label.py b/system/ui/widgets/label.py index 7bfbd6dc..97b29308 100644 --- a/system/ui/widgets/label.py +++ b/system/ui/widgets/label.py @@ -1,4 +1,3 @@ -import math from enum import IntEnum from collections.abc import Callable from itertools import zip_longest @@ -402,12 +401,6 @@ class UnifiedLabel(Widget): - Proper multiline vertical alignment - Height calculation for layout purposes """ - SHIMMER_BAND_WIDTH = 0.3 - SHIMMER_BLUR_RADIUS = 0.12 - SHIMMER_CYCLE_PERIOD = 2.5 - SHIMMER_SWEEP_FRACTION = 0.9 - SHIMMER_LOW_OPACITY = 0.65 - def __init__(self, text: str | Callable[[], str], font_size: int = DEFAULT_TEXT_SIZE, @@ -421,8 +414,7 @@ class UnifiedLabel(Widget): wrap_text: bool = True, scroll: bool = False, line_height: float = 1.0, - letter_spacing: float = 0.0, - shimmer: bool = False): + letter_spacing: float = 0.0): super().__init__() self._text = text self._font_size = font_size @@ -439,8 +431,6 @@ class UnifiedLabel(Widget): self._line_height = line_height * 0.9 self._letter_spacing = letter_spacing # 0.1 = 10% self._spacing_pixels = font_size * letter_spacing - self._shimmer = shimmer - self._shimmer_start_time = 0.0 # Scroll state self._scroll = scroll @@ -499,13 +489,6 @@ class UnifiedLabel(Widget): self._spacing_pixels = self._font_size * letter_spacing self._cached_text = None # Invalidate cache - def set_line_height(self, line_height: float): - """Update line height (multiplier, e.g., 1.0 = default).""" - new_line_height = line_height * 0.9 - if self._line_height != new_line_height: - self._line_height = new_line_height - self._cached_text = None - def set_font_weight(self, font_weight: FontWeight): """Update the font weight.""" if self._font_weight != font_weight: @@ -527,9 +510,6 @@ class UnifiedLabel(Widget): self._scroll_pause_t = None self._scroll_state = ScrollState.STARTING - def reset_shimmer(self, offset: float = 0.0): - self._shimmer_start_time = rl.get_time() + offset - def set_max_width(self, max_width: int | None): """Set the maximum width constraint for wrapping/eliding.""" if self._max_width != max_width: @@ -647,25 +627,6 @@ class UnifiedLabel(Widget): return self._cached_total_height return 0.0 - def _compute_shimmer_alpha(self, char_center_x: float, text_left: float, text_width: float) -> float: - if text_width <= 0: - return self.SHIMMER_LOW_OPACITY - - elapsed = rl.get_time() - self._shimmer_start_time - sigma = text_width * self.SHIMMER_BLUR_RADIUS - - t_raw = (elapsed % self.SHIMMER_CYCLE_PERIOD) / self.SHIMMER_CYCLE_PERIOD - t_clamped = max(0.0, min(t_raw / self.SHIMMER_SWEEP_FRACTION, 1.0)) - t = t_clamped * t_clamped * (3.0 - 2.0 * t_clamped) - - margin = text_width * self.SHIMMER_BAND_WIDTH - text_right = text_left + text_width - center = text_right + margin - t * (text_width + 2.0 * margin) - - d = char_center_x - center - shimmer = math.exp(-0.5 * d * d / (sigma * sigma)) if sigma > 0 else 0.0 - return self.SHIMMER_LOW_OPACITY + (1.0 - self.SHIMMER_LOW_OPACITY) * shimmer - def _render(self, _): """Render the label.""" if self._rect.width <= 0 or self._rect.height <= 0: @@ -809,20 +770,6 @@ class UnifiedLabel(Widget): line_x = self._rect.x + self._text_padding line_x += self._scroll_offset + x_offset - if self._shimmer and not emojis and line: - base_alpha = self._text_color.a / 255.0 - text_width = max(size.x, 1.0) - cursor_x = line_x - for char in line: - char_width = measure_text_cached(self._font, char, self._font_size, self._spacing_pixels).x - char_center_x = cursor_x + char_width / 2.0 - shimmer_alpha = self._compute_shimmer_alpha(char_center_x, line_x, text_width) - char_alpha = int(255 * base_alpha * shimmer_alpha) - char_color = rl.Color(self._text_color.r, self._text_color.g, self._text_color.b, char_alpha) - rl.draw_text_ex(self._font, char, rl.Vector2(cursor_x, current_y), self._font_size, self._spacing_pixels, char_color) - cursor_x += char_width - return - # Render line with emojis line_pos = rl.Vector2(line_x, current_y) prev_index = 0 diff --git a/system/ui/widgets/scroller.py b/system/ui/widgets/scroller.py index e941486a..f33ba941 100644 --- a/system/ui/widgets/scroller.py +++ b/system/ui/widgets/scroller.py @@ -11,7 +11,6 @@ ITEM_SPACING = 20 LINE_COLOR = rl.GRAY LINE_PADDING = 40 ANIMATION_SCALE = 0.6 -EDGE_SHADOW_WIDTH = 20 MIN_ZOOM_ANIMATION_TIME = 0.075 # seconds DO_ZOOM = False @@ -34,50 +33,9 @@ class LineSeparator(Widget): LINE_COLOR) -class ScrollIndicator(Widget): - def __init__(self): - super().__init__() - self._txt_scroll_indicator = gui_app.texture("icons_mici/settings/horizontal_scroll_indicator.png", 96, 48) - self._scroll_offset: float = 0.0 - self._content_size: float = 0.0 - self._viewport: rl.Rectangle = rl.Rectangle(0, 0, 0, 0) - - def update(self, scroll_offset: float, content_size: float, viewport: rl.Rectangle) -> None: - self._scroll_offset = scroll_offset - self._content_size = content_size - self._viewport = viewport - - def _render(self, _): - if self._viewport.width <= 0 or self._viewport.height <= 0: - return - - indicator_w = min(float(np.interp(self._content_size, [1000, 3000], [300, 100])), self._viewport.width) - max_scroll = self._content_size - self._viewport.width - if max_scroll > 0: - scroll_ratio = -self._scroll_offset / max_scroll - slide_range = max(self._viewport.width - indicator_w, 0.0) - x = self._viewport.x + scroll_ratio * slide_range - else: - x = self._viewport.x + (self._viewport.width - indicator_w) / 2 - y = max(self._viewport.y, 0) + self._viewport.height - self._txt_scroll_indicator.height / 2 - - dest_left = max(x, self._viewport.x) - dest_right = min(x + indicator_w, self._viewport.x + self._viewport.width) - dest_w = max(indicator_w / 2, dest_right - dest_left) - - dest_left = min(dest_left, self._viewport.x + self._viewport.width - dest_w) - dest_left = max(dest_left, self._viewport.x) - - src_rec = rl.Rectangle(0, 0, self._txt_scroll_indicator.width, self._txt_scroll_indicator.height) - dest_rec = rl.Rectangle(dest_left, y, dest_w, self._txt_scroll_indicator.height) - rl.draw_texture_pro(self._txt_scroll_indicator, src_rec, dest_rec, rl.Vector2(0, 0), 0.0, - rl.Color(255, 255, 255, int(255 * 0.45))) - - class Scroller(Widget): def __init__(self, items: list[Widget], horizontal: bool = True, snap_items: bool = True, spacing: int = ITEM_SPACING, - line_separator: bool = False, pad_start: int = ITEM_SPACING, pad_end: int = ITEM_SPACING, - scroll_indicator: bool = False, edge_shadows: bool = False): + line_separator: bool = False, pad_start: int = ITEM_SPACING, pad_end: int = ITEM_SPACING): super().__init__() self._items: list[Widget] = [] self._horizontal = horizontal @@ -107,18 +65,11 @@ class Scroller(Widget): self.scroll_panel = GuiScrollPanel2(self._horizontal, handle_out_of_bounds=not self._snap_items) self._scroll_enabled: bool | Callable[[], bool] = True - self._txt_vertical_scroll_indicator = gui_app.texture("icons_mici/settings/vertical_scroll_indicator.png", 40, 80) - self._show_scroll_indicator = scroll_indicator and self._horizontal - self._scroll_indicator = ScrollIndicator() - self._edge_shadows = edge_shadows and self._horizontal + self._txt_scroll_indicator = gui_app.texture("icons_mici/settings/vertical_scroll_indicator.png", 40, 80) for item in items: self.add_widget(item) - @property - def items(self) -> list[Widget]: - return self._items - def set_reset_scroll_at_show(self, scroll: bool): self._reset_scroll_at_show = scroll @@ -142,14 +93,6 @@ class Scroller(Widget): self._items.append(item) item.set_touch_valid_callback(lambda: self.scroll_panel.is_touch_valid() and self.enabled) - def move_item(self, from_index: int, to_index: int) -> None: - if from_index == to_index: - return - if not (0 <= from_index < len(self._items) and 0 <= to_index < len(self._items)): - return - item = self._items.pop(from_index) - self._items.insert(to_index, item) - def set_scrolling_enabled(self, enabled: bool | Callable[[], bool]) -> None: """Set whether scrolling is enabled (does not affect widget enabled state).""" self._scroll_enabled = enabled @@ -300,27 +243,13 @@ class Scroller(Widget): # Draw scroll indicator if SCROLL_BAR and not self._horizontal and len(self._visible_items) > 0: - _real_content_size = self._content_size - self._rect.height + self._txt_vertical_scroll_indicator.height + _real_content_size = self._content_size - self._rect.height + self._txt_scroll_indicator.height scroll_bar_y = -self._scroll_offset / _real_content_size * self._rect.height - scroll_bar_y = min(max(scroll_bar_y, self._rect.y), self._rect.y + self._rect.height - self._txt_vertical_scroll_indicator.height) - rl.draw_texture_ex(self._txt_vertical_scroll_indicator, rl.Vector2(self._rect.x, scroll_bar_y), 0, 1.0, rl.WHITE) + scroll_bar_y = min(max(scroll_bar_y, self._rect.y), self._rect.y + self._rect.height - self._txt_scroll_indicator.height) + rl.draw_texture_ex(self._txt_scroll_indicator, rl.Vector2(self._rect.x, scroll_bar_y), 0, 1.0, rl.WHITE) rl.end_scissor_mode() - if self._edge_shadows: - rl.draw_rectangle_gradient_h(int(self._rect.x), int(self._rect.y), - EDGE_SHADOW_WIDTH, int(self._rect.height), - rl.Color(0, 0, 0, 166), rl.BLANK) - - right_x = int(self._rect.x + self._rect.width - EDGE_SHADOW_WIDTH) - rl.draw_rectangle_gradient_h(right_x, int(self._rect.y), - EDGE_SHADOW_WIDTH, int(self._rect.height), - rl.BLANK, rl.Color(0, 0, 0, 166)) - - if self._show_scroll_indicator and len(self._visible_items) > 0: - self._scroll_indicator.update(self._scroll_offset, self._content_size, self._rect) - self._scroll_indicator.render() - def show_event(self): super().show_event() if self._reset_scroll_at_show: diff --git a/system/ui/widgets/slider.py b/system/ui/widgets/slider.py index e606c5c3..455cdeef 100644 --- a/system/ui/widgets/slider.py +++ b/system/ui/widgets/slider.py @@ -5,19 +5,17 @@ import pyray as rl from openpilot.system.ui.lib.application import gui_app, FontWeight from openpilot.system.ui.widgets import Widget from openpilot.system.ui.widgets.label import UnifiedLabel -from openpilot.common.filter_simple import BounceFilter, FirstOrderFilter +from openpilot.common.filter_simple import FirstOrderFilter class SmallSlider(Widget): HORIZONTAL_PADDING = 8 CONFIRM_DELAY = 0.2 - PRESSED_SCALE = 1.07 - def __init__(self, title: str, confirm_callback: Callable | None = None, shimmer_offset: float = 0.0): + def __init__(self, title: str, confirm_callback: Callable | None = None): # TODO: unify this with BigConfirmationDialogV2 super().__init__() self._confirm_callback = confirm_callback - self._shimmer_offset = shimmer_offset self._font = gui_app.font(FontWeight.DISPLAY) @@ -32,40 +30,29 @@ class SmallSlider(Widget): self._start_x_circle = 0.0 self._scroll_x_circle = 0.0 self._scroll_x_circle_filter = FirstOrderFilter(0, 0.05, 1 / gui_app.target_fps) - self._circle_scale_filter = BounceFilter(1.0, 0.1, 1 / gui_app.target_fps) - self._circle_press_time: float | None = None self._is_dragging_circle = False - self._label = UnifiedLabel(title, font_size=36, font_weight=FontWeight.SEMI_BOLD, text_color=rl.WHITE, + self._label = UnifiedLabel(title, font_size=36, font_weight=FontWeight.MEDIUM, text_color=rl.Color(255, 255, 255, int(255 * 0.65)), alignment=rl.GuiTextAlignment.TEXT_ALIGN_RIGHT, - alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE, line_height=0.9, shimmer=True) + alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE, line_height=0.9) def _load_assets(self): self.set_rect(rl.Rectangle(0, 0, 316 + self.HORIZONTAL_PADDING * 2, 100)) self._bg_txt = gui_app.texture("icons_mici/setup/small_slider/slider_bg.png", 316, 100) self._circle_bg_txt = gui_app.texture("icons_mici/setup/small_slider/slider_red_circle.png", 100, 100) - self._circle_bg_pressed_txt = self._circle_bg_txt self._circle_arrow_txt = gui_app.texture("icons_mici/setup/small_slider/slider_arrow.png", 37, 32) @property def confirmed(self) -> bool: return self._confirmed_time > 0.0 - def show_event(self): - super().show_event() - self.reset() - - def reset(self, reset_shimmer: bool = True): + def reset(self): # reset all slider state self._is_dragging_circle = False self._confirmed_time = 0.0 self._confirm_callback_called = False - self._circle_press_time = None - self._circle_scale_filter.x = 1.0 - if reset_shimmer: - self._label.reset_shimmer(self._shimmer_offset) def set_opacity(self, opacity: float, smooth: bool = False): if smooth: @@ -96,7 +83,6 @@ class SmallSlider(Widget): if rl.check_collision_point_rec(mouse_event.pos, circle_button_rect): self._start_x_circle = mouse_event.pos.x self._is_dragging_circle = True - self._circle_press_time = rl.get_time() elif mouse_event.left_released: # swiped to left @@ -143,9 +129,8 @@ class SmallSlider(Widget): btn_x = bg_txt_x + self._bg_txt.width - self._circle_bg_txt.width + self._scroll_x_circle_filter.x btn_y = self._rect.y + (self._rect.height - self._circle_bg_txt.height) / 2 - label_alpha = int(255 * (1.0 - self.slider_percentage) * self._opacity_filter.x) - if label_alpha > 0: - self._label.set_text_color(rl.Color(255, 255, 255, label_alpha)) + if self._confirmed_time == 0.0 or self._scroll_x_circle > 0: + self._label.set_text_color(rl.Color(255, 255, 255, int(255 * 0.65 * (1.0 - self.slider_percentage) * self._opacity_filter.x))) label_rect = rl.Rectangle( self._rect.x + 20, self._rect.y, @@ -154,24 +139,18 @@ class SmallSlider(Widget): ) self._label.render(label_rect) - circle_pressed = self._is_dragging_circle or self.confirmed or ( - self._circle_press_time is not None and rl.get_time() - self._circle_press_time < 0.075 - ) - circle_bg_txt = self._circle_bg_pressed_txt if circle_pressed else self._circle_bg_txt - scale = self._circle_scale_filter.update(self.PRESSED_SCALE if circle_pressed else 1.0) - scaled_btn_x = btn_x + (self._circle_bg_txt.width * (1 - scale)) / 2 - scaled_btn_y = btn_y + (self._circle_bg_txt.height * (1 - scale)) / 2 - rl.draw_texture_ex(circle_bg_txt, rl.Vector2(scaled_btn_x, scaled_btn_y), 0.0, scale, white) + # circle and arrow + rl.draw_texture_ex(self._circle_bg_txt, rl.Vector2(btn_x, btn_y), 0.0, 1.0, white) - arrow_x = scaled_btn_x + (self._circle_bg_txt.width * scale - self._circle_arrow_txt.width) / 2 - arrow_y = scaled_btn_y + (self._circle_bg_txt.height * scale - self._circle_arrow_txt.height) / 2 + arrow_x = btn_x + (self._circle_bg_txt.width - self._circle_arrow_txt.width) / 2 + arrow_y = btn_y + (self._circle_bg_txt.height - self._circle_arrow_txt.height) / 2 rl.draw_texture_ex(self._circle_arrow_txt, rl.Vector2(arrow_x, arrow_y), 0.0, 1.0, white) class LargerSlider(SmallSlider): - def __init__(self, title: str, confirm_callback: Callable | None = None, green: bool = True, shimmer_offset: float = 0.0): + def __init__(self, title: str, confirm_callback: Callable | None = None, green: bool = True): self._green = green - super().__init__(title, confirm_callback=confirm_callback, shimmer_offset=shimmer_offset) + super().__init__(title, confirm_callback=confirm_callback) def _load_assets(self): self.set_rect(rl.Rectangle(0, 0, 520 + self.HORIZONTAL_PADDING * 2, 115)) @@ -179,7 +158,6 @@ class LargerSlider(SmallSlider): self._bg_txt = gui_app.texture("icons_mici/setup/small_slider/slider_bg_larger.png", 520, 115) circle_fn = "slider_green_rounded_rectangle" if self._green else "slider_black_rounded_rectangle" self._circle_bg_txt = gui_app.texture(f"icons_mici/setup/small_slider/{circle_fn}.png", 180, 115) - self._circle_bg_pressed_txt = self._circle_bg_txt self._circle_arrow_txt = gui_app.texture("icons_mici/setup/small_slider/slider_arrow.png", 64, 55) @@ -187,16 +165,15 @@ class BigSlider(SmallSlider): def __init__(self, title: str, icon: rl.Texture, confirm_callback: Callable | None = None): self._icon = icon super().__init__(title, confirm_callback=confirm_callback) - self._label = UnifiedLabel(title, font_size=48, font_weight=FontWeight.DISPLAY, text_color=rl.WHITE, + self._label = UnifiedLabel(title, font_size=48, font_weight=FontWeight.DISPLAY, text_color=rl.Color(255, 255, 255, int(255 * 0.65)), alignment=rl.GuiTextAlignment.TEXT_ALIGN_RIGHT, alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE, - line_height=0.875, shimmer=True) + line_height=0.875) def _load_assets(self): self.set_rect(rl.Rectangle(0, 0, 520 + self.HORIZONTAL_PADDING * 2, 180)) self._bg_txt = gui_app.texture("icons_mici/buttons/slider_bg.png", 520, 180) self._circle_bg_txt = gui_app.texture("icons_mici/buttons/button_circle.png", 180, 180) - self._circle_bg_pressed_txt = gui_app.texture("icons_mici/buttons/button_circle_hover.png", 180, 180) self._circle_arrow_txt = self._icon @@ -206,5 +183,4 @@ class RedBigSlider(BigSlider): self._bg_txt = gui_app.texture("icons_mici/buttons/slider_bg.png", 520, 180) self._circle_bg_txt = gui_app.texture("icons_mici/buttons/button_circle_red.png", 180, 180) - self._circle_bg_pressed_txt = gui_app.texture("icons_mici/buttons/button_circle_red_hover.png", 180, 180) self._circle_arrow_txt = self._icon diff --git a/uncompiledmodels/driving_policy.onnx b/uncompiledmodels/driving_policy.onnx deleted file mode 100644 index 706c95db..00000000 Binary files a/uncompiledmodels/driving_policy.onnx and /dev/null differ diff --git a/uncompiledmodels/driving_vision.onnx b/uncompiledmodels/driving_vision.onnx deleted file mode 100644 index 902f1dd3..00000000 Binary files a/uncompiledmodels/driving_vision.onnx and /dev/null differ