IQ.Pilot Release Commit @ dab4674

This commit is contained in:
IQ.Lvbs CI [bot]
2026-08-30 14:49:29 -05:00
parent d42df282ae
commit c9629a3603
19 changed files with 812 additions and 66 deletions

View File

@@ -178,6 +178,14 @@ class IQEvents(EventsBase):
EVENTS_IQ_TYPE = dict[int, dict[str, Alert | AlertCallbackType]]
_GUIDANCE_EVENTS: EVENTS_IQ_TYPE = {
EventNameIQ.lateralEdgeBlocked: {
ET.WARNING: Alert(
"Lane Change Blocked",
"Road edge detected",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
},
EventNameIQ.speedLimitActive: {
ET.WARNING: speed_limit_adjust_alert,
},

View File

@@ -22,19 +22,12 @@ from iqpilot.selfdrive.selfdrived.events import Events, ET
from iqpilot.selfdrive.selfdrived.helpers import ExcessiveActuationCheck
from iqpilot.selfdrive.selfdrived.state import StateMachine
from iqpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert
from iqpilot.selfdrive.longitudinal_settings import get_runtime_personality
from iqpilot.system.version import get_build_metadata
from iqpilot.system.hardware import HARDWARE
from iqpilot.sab.behavior import SteeringAssistanceBehavior
def get_sanitize_int_param(key, min_val, max_val, params):
stored = params.get(key, return_default=True)
bounded = min(max(stored, min_val), max_val)
if bounded != stored:
params.put(key, bounded)
return bounded
from iqpilot.selfdrive.controls.lib.helpers.lane_change import NAV_EXIT_COMMIT_DISTANCE
from iqpilot.vehicle.vehicle import VehicleEvents
from iqpilot.selfdrive.car.gap_button_actions import GapButtonActions
@@ -158,12 +151,7 @@ class SelfdriveD(GapButtonActions):
self.not_running_prev = None
self.wide_cam_faulty = False
self.experimental_mode = False
self.personality = get_sanitize_int_param(
"LongitudinalPersonality",
min(log.LongitudinalPersonality.schema.enumerants.values()),
max(log.LongitudinalPersonality.schema.enumerants.values()),
self.params
)
self.personality = get_runtime_personality(self.params)
self.recalibrating_seen = False
self.state_machine = StateMachine()
self.rk = Ratekeeper(100, print_delay_threshold=None)
@@ -225,6 +213,9 @@ class SelfdriveD(GapButtonActions):
model_data = self._get_model_data_ext()
model_events = []
if model_data.lateralEdgeBlock != custom.IQLateralEdgeBlock.none:
model_events.append(custom.IQOnroadEvent.EventName.lateralEdgeBlocked)
lane_turn_direction = model_data.turnSignalDirection
if lane_turn_direction == TurnDirection.turnLeft:
model_events.append(custom.IQOnroadEvent.EventName.modelTurnLeft)
@@ -783,16 +774,7 @@ class SelfdriveD(GapButtonActions):
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl
# Params can be changed while selfdrived is running. Keep the live value in
# the same valid enum range enforced during startup; otherwise a stale value
# (for example 3) makes the alert callback lookup raise KeyError and kills
# selfdrived.
self.personality = get_sanitize_int_param(
"LongitudinalPersonality",
min(log.LongitudinalPersonality.schema.enumerants.values()),
max(log.LongitudinalPersonality.schema.enumerants.values()),
self.params,
)
self.personality = get_runtime_personality(self.params)
self.nav_exit_lane_change = self._read_nav_exit_lane_change()
self.model_download_pending = self.params.get("ModelManager_DownloadIndex") is not None

View File

@@ -1,6 +1,7 @@
from iqpilot.cereal import car
from iqpilot.selfdrive.selfdrived.selfdrived import _cleanup_startup_params, get_sanitize_int_param
from iqpilot.selfdrive.longitudinal_settings import get_valid_personality
from iqpilot.selfdrive.selfdrived.selfdrived import _cleanup_startup_params
class DummyParams:
@@ -36,5 +37,5 @@ class TestLongitudinalPrefPersistence:
self.value = value
params = ParamsWithInvalidPersonality()
assert get_sanitize_int_param("LongitudinalPersonality", 0, 2, params) == 2
assert get_valid_personality(params) == 2
assert params.value == 2

View File

@@ -0,0 +1,110 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos/
"""
import pytest
from iqpilot.selfdrive.longitudinal_settings import (
LONGITUDINAL_MODE_CHILL,
LONGITUDINAL_MODE_DYNAMIC,
LONGITUDINAL_MODE_STOCK,
PERSONALITY_AGGRESSIVE,
PERSONALITY_RELAXED,
PERSONALITY_STANDARD,
PERSONALITY_VALUES,
apply_longitudinal_mode,
get_follow_distance_state,
get_longitudinal_mode,
get_runtime_personality,
set_valid_personality,
)
class Params:
def __init__(self, personality=PERSONALITY_STANDARD):
self.values = {
"AlphaLongitudinalEnabled": True,
"ExperimentalMode": True,
"IQDynamicMode": True,
"LongitudinalPersonality": personality,
}
self.personality_writes = []
def get(self, key, return_default=False):
return self.values[key]
def get_bool(self, key):
return bool(self.values[key])
def put(self, key, value):
self.values[key] = value
if key == "LongitudinalPersonality":
self.personality_writes.append(value)
def put_bool(self, key, value):
self.values[key] = bool(value)
def test_personality_writer_rejects_stock_value():
params = Params()
with pytest.raises(ValueError):
set_valid_personality(params, 3)
assert params.personality_writes == []
def test_mode_paths_only_write_valid_personalities():
params = Params(PERSONALITY_AGGRESSIVE)
for mode in range(4):
apply_longitudinal_mode(params, mode)
assert all(value in PERSONALITY_VALUES for value in params.personality_writes)
def test_stock_mode_preserves_personality_and_dynamic_restores_it():
params = Params(PERSONALITY_AGGRESSIVE)
apply_longitudinal_mode(params, LONGITUDINAL_MODE_STOCK)
assert get_follow_distance_state(params) == (None, False)
assert get_runtime_personality(params) == PERSONALITY_AGGRESSIVE
assert params.values["LongitudinalPersonality"] == PERSONALITY_AGGRESSIVE
assert params.personality_writes == []
apply_longitudinal_mode(params, LONGITUDINAL_MODE_DYNAMIC)
assert get_longitudinal_mode(params) == LONGITUDINAL_MODE_DYNAMIC
assert get_follow_distance_state(params) == (PERSONALITY_AGGRESSIVE, True)
def test_stock_mode_sanitizes_legacy_stock_personality_value():
params = Params(3)
apply_longitudinal_mode(params, LONGITUDINAL_MODE_STOCK)
assert get_follow_distance_state(params) == (None, False)
assert params.values["LongitudinalPersonality"] == PERSONALITY_RELAXED
assert params.personality_writes == [PERSONALITY_RELAXED]
def test_chill_mode_forces_relaxed_personality():
params = Params(PERSONALITY_AGGRESSIVE)
apply_longitudinal_mode(params, LONGITUDINAL_MODE_CHILL)
assert get_follow_distance_state(params) == (PERSONALITY_RELAXED, False)
assert get_runtime_personality(params) == PERSONALITY_RELAXED
assert params.values["LongitudinalPersonality"] == PERSONALITY_RELAXED
assert params.personality_writes == [PERSONALITY_RELAXED]
def test_dynamic_and_pilot_enable_valid_personality_selection():
params = Params(PERSONALITY_STANDARD)
assert get_follow_distance_state(params) == (PERSONALITY_STANDARD, True)
params.values["IQDynamicMode"] = False
assert get_follow_distance_state(params) == (PERSONALITY_STANDARD, True)