203 lines
6.9 KiB
Python
203 lines
6.9 KiB
Python
"""
|
|
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
|
"""
|
|
from collections.abc import Callable
|
|
|
|
import pyray as rl
|
|
|
|
from iqpilot.common.params import Params
|
|
from iqpilot.selfdrive.ui.ui_state import ui_state
|
|
from iqpilot.system.ui.lib.multilang import tr
|
|
from iqpilot.system.ui.iqwidgets.widgets.list_view import IQListItem, IQToggleAction, SafeIQToggleAction
|
|
from iqpilot.system.ui.iqwidgets.widgets.list_view import OptionControl
|
|
from iqpilot.system.ui.widgets import Widget
|
|
from iqpilot.system.ui.widgets.network import NavButton
|
|
from iqpilot.system.ui.widgets.scroller_tici import Scroller
|
|
from iqdbc.car.volkswagen.values import CAR, VolkswagenFlags
|
|
|
|
|
|
def _toggle_item(title: str, description: str, param: str) -> IQListItem:
|
|
return IQListItem(
|
|
title=lambda t=title: tr(t),
|
|
description=lambda d=description: tr(d),
|
|
action_item=IQToggleAction(
|
|
initial_state=Params().get_bool(param),
|
|
callback=lambda state, p=param: Params().put_bool(p, state),
|
|
param=param,
|
|
),
|
|
)
|
|
|
|
|
|
def _safe_toggle_item(title: str, description: str, param: str, default_on: bool = True) -> IQListItem:
|
|
return IQListItem(
|
|
title=lambda t=title: tr(t),
|
|
description=lambda d=description: tr(d),
|
|
action_item=SafeIQToggleAction(
|
|
param=param,
|
|
default_on=default_on,
|
|
),
|
|
)
|
|
|
|
|
|
def _option_item(title: str, description: str, param: str, minimum: int, maximum: int,
|
|
step: int = 1, label_callback=None, use_float_scaling: bool = False) -> IQListItem:
|
|
return IQListItem(
|
|
title=lambda t=title: tr(t),
|
|
description=lambda d=description: tr(d),
|
|
action_item=OptionControl(
|
|
param=param,
|
|
min_value=minimum,
|
|
max_value=maximum,
|
|
value_change_step=step,
|
|
use_float_scaling=use_float_scaling,
|
|
label_callback=label_callback,
|
|
),
|
|
)
|
|
|
|
|
|
class IQDynamicLayout(Widget):
|
|
def __init__(self, back_btn_callback: Callable):
|
|
super().__init__()
|
|
self._params = Params()
|
|
self._back_button = NavButton(tr("Back"))
|
|
self._back_button.set_click_callback(back_btn_callback)
|
|
|
|
items = self._initialize_items()
|
|
self._scroller = Scroller(items, line_separator=True, spacing=0)
|
|
|
|
@staticmethod
|
|
def _is_pq() -> bool:
|
|
bundle = ui_state.params.get("CarPlatformBundle")
|
|
if bundle:
|
|
platform = bundle.get("platform")
|
|
if platform:
|
|
try:
|
|
return bool(CAR[platform].config.flags & VolkswagenFlags.PQ)
|
|
except (KeyError, AttributeError):
|
|
return False
|
|
elif ui_state.CP:
|
|
return bool(ui_state.CP.flags & VolkswagenFlags.PQ)
|
|
return False
|
|
|
|
def _initialize_items(self):
|
|
ms_to_mph = 2.23694
|
|
|
|
def speed_label(value: float | int) -> str:
|
|
try:
|
|
speed_ms = float(value)
|
|
except (TypeError, ValueError):
|
|
return "-- mph"
|
|
return f"{int(round(speed_ms * ms_to_mph))} mph"
|
|
|
|
def distance_label(value: float | int) -> str:
|
|
try:
|
|
distance_m = float(value)
|
|
except (TypeError, ValueError):
|
|
return "-- m"
|
|
if self._params.get_bool("IsMetric"):
|
|
return f"{distance_m:.1f} m"
|
|
return f"{distance_m * 3.28084:.0f} ft"
|
|
|
|
def seconds_label(value: float | int) -> str:
|
|
try:
|
|
seconds = float(value)
|
|
except (TypeError, ValueError):
|
|
return "--.-s"
|
|
return f"{seconds:.1f}s"
|
|
|
|
self._blend_radar_toggle = _toggle_item(
|
|
"Blend IQ.Pilot + Stock ACC Radar",
|
|
"VW PQ only. Keep the factory ACC radar engaged and use its acceleration as IQ.Dynamic's ACC "
|
|
"(chill) command, while IQ.Pilot still owns blended/e2e control for low speed, stops, and traffic.",
|
|
"IQDynamicBlendStockRadar",
|
|
)
|
|
self._pq_only_items = [self._blend_radar_toggle]
|
|
|
|
return [
|
|
self._blend_radar_toggle,
|
|
_toggle_item(
|
|
"IQ.Dynamic Curves",
|
|
"Allow IQ.Dynamic to enter blended control for curves and strong vision slowdown cues.",
|
|
"IQDynamicConditionalCurves",
|
|
),
|
|
_toggle_item(
|
|
"IQ.Dynamic Slower Lead",
|
|
"Allow IQ.Dynamic to switch toward blended control when a slower lead vehicle is detected.",
|
|
"IQDynamicConditionalSlowerLead",
|
|
),
|
|
_toggle_item(
|
|
"IQ.Dynamic Stopped Lead",
|
|
"Allow IQ.Dynamic to react more aggressively when a lead vehicle is nearly stopped.",
|
|
"IQDynamicConditionalStoppedLead",
|
|
),
|
|
_toggle_item(
|
|
"IQ.Dynamic Model Stops",
|
|
"Allow IQ.Dynamic to switch toward blended control for stop-sign and stop-light style vision stops.",
|
|
"IQDynamicConditionalModelStops",
|
|
),
|
|
_toggle_item(
|
|
"IQ.Dynamic SLC Fallback",
|
|
"Allow IQ.Dynamic to request blended control when Speed Limit Controller has no usable target.",
|
|
"IQDynamicConditionalSLCFallback",
|
|
),
|
|
_option_item(
|
|
"IQ.Dynamic Low Speed",
|
|
"Below this speed, IQ.Dynamic prefers blended control when no lead is present.",
|
|
"IQDynamicConditionalSpeed",
|
|
500, 3500, step=50,
|
|
use_float_scaling=True,
|
|
label_callback=speed_label,
|
|
),
|
|
_toggle_item(
|
|
"IQ Force Stops",
|
|
"Bring the car to a complete stop for stop signs and stop lights, and feather the brake in the final meters of "
|
|
"every stop so it settles gently instead of rocking on its suspension. Yields full braking authority when a lead "
|
|
"is close. Override with the accelerator.",
|
|
"IQForceStops",
|
|
),
|
|
_option_item(
|
|
"IQ.Dynamic Lead Speed",
|
|
"Below this speed, IQ.Dynamic prefers blended control even with a tracked lead.",
|
|
"IQDynamicConditionalLeadSpeed",
|
|
500, 4000, step=50,
|
|
use_float_scaling=True,
|
|
label_callback=speed_label,
|
|
),
|
|
_option_item(
|
|
"IQ.Dynamic Model Stop Time",
|
|
"Sets the vision stop prediction time horizon used by IQ.Dynamic and IQ Force Stops. Shorter values react later. Longer values react earlier.",
|
|
"IQDynamicModelStopTime",
|
|
100, 600,
|
|
step=25,
|
|
use_float_scaling=True,
|
|
label_callback=seconds_label,
|
|
),
|
|
_option_item(
|
|
"IQ.Dynamic Min Force Stop Length",
|
|
"When IQ Force Stops is enabled, keep at least this much stopping distance in the force-stop ramp. Set to 0 to disable the minimum.",
|
|
"IQDynamicMinimumForceStopLength",
|
|
0, 5000,
|
|
step=50,
|
|
use_float_scaling=True,
|
|
label_callback=distance_label,
|
|
),
|
|
]
|
|
|
|
def _render(self, rect: rl.Rectangle):
|
|
is_pq = self._is_pq()
|
|
for item in self._pq_only_items:
|
|
item.set_visible(is_pq)
|
|
|
|
self._back_button.set_position(self._rect.x, self._rect.y + 20)
|
|
self._back_button.render()
|
|
content_rect = rl.Rectangle(
|
|
rect.x,
|
|
rect.y + self._back_button.rect.height + 40,
|
|
rect.width,
|
|
rect.height - self._back_button.rect.height - 40,
|
|
)
|
|
self._scroller.render(content_rect)
|
|
|
|
def show_event(self):
|
|
self._scroller.show_event()
|