IQ.Pilot Release Commit @ 9fe0487

This commit is contained in:
IQ.Lvbs CI [bot]
2026-07-27 01:04:28 -05:00
parent 6edfe55a1e
commit 541e76a873
210 changed files with 992 additions and 504 deletions

View File

@@ -129,7 +129,7 @@ class Car:
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, cached_params,
fixed_fingerprint, init_params_list_iq, is_release_iq)
iqpilot_interfaces.setup_interfaces(self.CI, self.params)
iqpilot_interfaces.apply_iq_car_config(self.CI, self.params)
self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP, self.CI.CP_IQ)
self.CP = self.CI.CP
self.CP_IQ = self.CI.CP_IQ

View File

@@ -39,7 +39,7 @@ class TestCarInterfaces:
car_interface.CP.openpilotLongitudinalControl = False
car_params = car_interface.CP.as_reader()
car_params_iq = car_interface.CP_IQ
iqpilot_interfaces.setup_interfaces(car_interface)
iqpilot_interfaces.apply_iq_car_config(car_interface)
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
cc_sp_msg = FuzzyGenerator.get_random_msg(data.draw, custom.IQCarControl, real_floats=True)

View File

@@ -10,8 +10,8 @@ import numpy as np
from cereal import log, custom # noqa: F401 (custom kept available for downstream imports)
from iqdbc.car import structs
from iqdbc.car.lateral import FRICTION_THRESHOLD, get_friction
from iqdbc.iqpilot.car.interfaces import LatControlInputs
from iqdbc.iqpilot.car.iq_lateral import get_friction as get_friction_in_torque_space
from iqdbc.lvbs.car.interfaces import LatControlInputs
from iqdbc.lvbs.car.iq_lateral import get_friction as get_friction_in_torque_space
from openpilot.common.basedir import BASEDIR
from openpilot.common.constants import ACCELERATION_DUE_TO_GRAVITY
from openpilot.common.filter_simple import FirstOrderFilter

View File

@@ -26,7 +26,7 @@ class TestLatControl:
CP = CarInterface.get_non_essential_params(car_name)
CP_IQ = CarInterface.get_non_essential_params_iq(CP, car_name)
CI = CarInterface(CP, CP_IQ)
iqpilot_interfaces.setup_interfaces(CI)
iqpilot_interfaces.apply_iq_car_config(CI)
CP_IQ = convert_to_capnp(CP_IQ)
VM = VehicleModel(CP)

View File

@@ -17,7 +17,7 @@ def get_controller(car_name):
CP = CarInterface.get_non_essential_params(car_name)
CP_IQ = CarInterface.get_non_essential_params_iq(CP, car_name)
CI = CarInterface(CP, CP_IQ)
iqpilot_interfaces.setup_interfaces(CI)
iqpilot_interfaces.apply_iq_car_config(CI)
CP_IQ = convert_to_capnp(CP_IQ)
VM = VehicleModel(CP)
controller = LatControlTorque(CP.as_reader(), CP_IQ.as_reader(), CI, DT_CTRL)

View File

@@ -9,7 +9,7 @@ from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.lib.multilang import tr, tr_noop
if gui_app.iqpilot_ui():
from openpilot.system.ui.iqpilot.widgets.list_view import toggle_item
from openpilot.system.ui.iqwidgets.widgets.list_view import toggle_item
# Description constants
DESCRIPTIONS = {

View File

@@ -21,7 +21,7 @@ from openpilot.system.ui.widgets.option_dialog import MultiOptionDialog
from openpilot.system.ui.widgets.scroller_tici import Scroller
if gui_app.iqpilot_ui():
from openpilot.system.ui.iqpilot.widgets.list_view import button_item
from openpilot.system.ui.iqwidgets.widgets.list_view import button_item
# Description constants
DESCRIPTIONS = {

View File

@@ -12,7 +12,7 @@ from openpilot.system.ui.widgets.option_dialog import MultiOptionDialog
from openpilot.system.ui.widgets.scroller_tici import Scroller
if gui_app.iqpilot_ui():
from openpilot.system.ui.iqpilot.widgets.list_view import button_item
from openpilot.system.ui.iqwidgets.widgets.list_view import button_item
# TODO: remove this. updater fails to respond on startup if time is not correct
UPDATED_TIMEOUT = 10 # seconds to wait for updated to respond
@@ -237,7 +237,7 @@ class SoftwareLayout(Widget):
def _on_auth_branch(self):
# Collect username then token; store encrypted and signal the updater to
# re-check (refreshing the available-branch list for private repos).
from openpilot.system.ui.iqpilot.widgets.list_view import open_text_prompt
from openpilot.system.ui.iqwidgets.widgets.list_view import open_text_prompt
from openpilot.common import git_creds
creds = git_creds.get_credentials()

View File

@@ -10,8 +10,8 @@ from openpilot.system.ui.widgets import DialogResult
from openpilot.selfdrive.ui.ui_state import ui_state
if gui_app.iqpilot_ui():
from openpilot.system.ui.iqpilot.widgets.list_view import toggle_item
from openpilot.system.ui.iqpilot.widgets.list_view import multiple_button_item
from openpilot.system.ui.iqwidgets.widgets.list_view import toggle_item
from openpilot.system.ui.iqwidgets.widgets.list_view import multiple_button_item
from openpilot.iqpilot.ui.layouts.settings.iq_dynamic import IQDynamicLayout
PERSONALITY_TO_INT = log.LongitudinalPersonality.schema.enumerants

View File

@@ -10,7 +10,7 @@ import pyray as rl
from cereal import custom
from openpilot.system.ui.iqpilot.widgets.helpers.glyphs import draw_star
from openpilot.system.ui.iqwidgets.widgets.helpers.glyphs import draw_star
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.application import gui_app

View File

@@ -99,6 +99,32 @@ class ForgetButton(Widget):
rl.draw_texture_ex(self._trash_txt, (trash_x, trash_y), 0, 1.0, rl.WHITE)
class DisconnectButton(Widget):
MARGIN = 12
RADIUS = 42
# the only round button art is the destructive red one, and dropping a connection is not destructive
BG = rl.Color(56, 56, 61, 255)
BG_PRESSED = rl.Color(84, 84, 90, 255)
def __init__(self, disconnect_network: Callable):
super().__init__()
self._disconnect_network = disconnect_network
self._slash_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_slash.png", 38, 38)
self.set_rect(rl.Rectangle(0, 0, 84 + self.MARGIN * 2, 84 + self.MARGIN * 2))
def _handle_mouse_release(self, mouse_pos: MousePos):
super()._handle_mouse_release(mouse_pos)
dlg = BigConfirmationDialog("slide to\ndisconnect", gui_app.texture("icons_mici/settings/network/wifi_strength_slash.png", 54, 54),
self._disconnect_network)
gui_app.push_widget(dlg)
def _render(self, _):
center = rl.Vector2(self._rect.x + self._rect.width / 2, self._rect.y + self._rect.height / 2)
rl.draw_circle_v(center, self.RADIUS, self.BG_PRESSED if self.is_pressed else self.BG)
rl.draw_texture_ex(self._slash_txt, (center.x - self._slash_txt.width / 2, center.y - self._slash_txt.height / 2),
0, 1.0, rl.WHITE)
class WifiButton(BigButton):
LABEL_PADDING = 98
LABEL_WIDTH = 402 - 98 - 28
@@ -111,9 +137,11 @@ class WifiButton(BigButton):
self._connecting_ssid = connecting_ssid
self._wifi_icon = WifiIcon(network)
self._forget_btn = ForgetButton(self._forget_network)
self._disconnect_btn = DisconnectButton(self._disconnect_network)
self._check_txt = gui_app.texture("icons_mici/setup/driver_monitoring/dm_check.png", 32, 32)
self._network_missing = False
self._network_forgetting = False
self._network_disconnecting = False
self._wrong_password = False
@property
@@ -142,9 +170,18 @@ class WifiButton(BigButton):
self._network_forgetting = True
self._wifi_manager.forget_connection(self._network.ssid)
def _disconnect_network(self):
if self._network_disconnecting:
return
self._network_disconnecting = True
self._wifi_manager.disconnect_connection(self._network.ssid)
def on_forgotten(self):
self._network_forgetting = False
def on_disconnected(self):
self._network_disconnecting = False
def set_network_missing(self, missing: bool):
self._network_missing = missing
self._wifi_icon.set_network_missing(missing)
@@ -171,31 +208,44 @@ class WifiButton(BigButton):
@property
def _show_forget_btn(self) -> bool:
if self._is_tethering or self._network_forgetting:
if self._is_tethering or self._network_forgetting or self._show_disconnect_btn:
return False
return (self._is_saved and not self._wrong_password) or self._is_connecting
@property
def _show_disconnect_btn(self) -> bool:
# 402 units of row cannot hold both buttons plus the status word, so the slot is contextual:
# disconnect while connected, forget once it is only saved
if self._is_tethering or self._network_forgetting or self._network_disconnecting:
return False
return self._is_connected
def _handle_mouse_release(self, mouse_pos: MousePos):
if self._show_forget_btn and rl.check_collision_point_rec(mouse_pos, self._forget_btn.rect):
return
if self._show_disconnect_btn and rl.check_collision_point_rec(mouse_pos, self._disconnect_btn.rect):
return
super()._handle_mouse_release(mouse_pos)
def _get_label_font_size(self):
return 48
def set_touch_valid_callback(self, touch_callback: Callable[[], bool]) -> None:
super().set_touch_valid_callback(lambda: touch_callback() and not self._forget_btn.is_pressed)
super().set_touch_valid_callback(lambda: touch_callback() and not self._forget_btn.is_pressed and not self._disconnect_btn.is_pressed)
self._forget_btn.set_touch_valid_callback(touch_callback)
self._disconnect_btn.set_touch_valid_callback(touch_callback)
def _update_state(self):
super()._update_state()
if any((self._network_missing, self._is_connecting, self._is_connected, self._network_forgetting,
self._network.security_type == SecurityType.UNSUPPORTED)):
self._network_disconnecting, self._network.security_type == SecurityType.UNSUPPORTED)):
self.set_enabled(False)
self._sub_label.set_color(rl.Color(255, 255, 255, int(255 * 0.585)))
self._sub_label.set_font_weight(FontWeight.ROMAN)
if self._network_forgetting:
self.set_value("forgetting...")
elif self._network_disconnecting:
self.set_value("disconnecting...")
elif self._is_connecting:
self.set_value("starting..." if self._is_tethering else "connecting...")
elif self._is_connected:
@@ -219,9 +269,10 @@ class WifiButton(BigButton):
if self.value:
sub_label_x = self._rect.x + self.LABEL_HORIZONTAL_PADDING
label_y = btn_y + self._rect.height - self.LABEL_VERTICAL_PADDING
sub_label_w = self.SUB_LABEL_WIDTH - (self._forget_btn.rect.width if self._show_forget_btn else 0)
sub_label_w = self.SUB_LABEL_WIDTH - (self._forget_btn.rect.width if self._show_forget_btn else 0) \
- (self._disconnect_btn.rect.width if self._show_disconnect_btn else 0)
sub_label_height = self._sub_label.get_content_height(sub_label_w)
if self._is_connected and not self._network_forgetting:
if self._is_connected and not self._network_forgetting and not self._network_disconnecting:
check_y = int(label_y - sub_label_height + (sub_label_height - self._check_txt.height) / 2)
rl.draw_texture_ex(self._check_txt, rl.Vector2(sub_label_x, check_y), 0.0, 1.0, rl.Color(255, 255, 255, int(255 * 0.9 * 0.65)))
sub_label_x += self._check_txt.width + 14
@@ -230,11 +281,19 @@ class WifiButton(BigButton):
self._wifi_icon.render(rl.Rectangle(self._rect.x + 30, btn_y + 30, self._wifi_icon.rect.width, self._wifi_icon.rect.height))
btn_right = self._rect.x + self._rect.width
if self._show_forget_btn:
self._forget_btn.render(rl.Rectangle(
self._rect.x + self._rect.width - self._forget_btn.rect.width,
btn_right - self._forget_btn.rect.width,
btn_y + self._rect.height - self._forget_btn.rect.height,
self._forget_btn.rect.width, self._forget_btn.rect.height))
btn_right -= self._forget_btn.rect.width
if self._show_disconnect_btn:
self._disconnect_btn.render(rl.Rectangle(
btn_right - self._disconnect_btn.rect.width,
btn_y + self._rect.height - self._disconnect_btn.rect.height,
self._disconnect_btn.rect.width, self._disconnect_btn.rect.height))
class ScanningButton(BigButton):
@@ -298,6 +357,9 @@ class WifiUIMici(NavScroller):
def _on_disconnected(self):
self._connecting = None
for btn in self._scroller.items:
if isinstance(btn, WifiButton):
btn.on_disconnected()
def _on_forgotten(self, ssid=None):
self._connecting = None

View File

@@ -89,7 +89,7 @@ class ModelRenderer(Widget, IQModelRenderer):
self._path_offset_z = HEIGHT_INIT[0]
self._counter = -1
self._camera_offset = ui_state.params.get("CameraOffset", return_default=True) if ui_state.active_bundle else 0.0
self._ambient_dots = ui_state.params.get_bool("AmbientTrackDots")
self._ambient_dots = bool(ui_state.params.get("AmbientTrackDots", return_default=True))
# Initialize ModelPoints objects
self._path = ModelPoints()
self._lane_lines = [ModelPoints() for _ in range(4)]
@@ -143,7 +143,7 @@ class ModelRenderer(Widget, IQModelRenderer):
if self._counter % 60 == 0:
self._camera_offset = ui_state.params.get("CameraOffset", return_default=True) if ui_state.active_bundle else 0.0
self._ambient_dots = ui_state.params.get_bool("AmbientTrackDots")
self._ambient_dots = bool(ui_state.params.get("AmbientTrackDots", return_default=True))
self._counter += 1
if sm.updated['carParams']:
@@ -456,18 +456,17 @@ class ModelRenderer(Widget, IQModelRenderer):
draw_polygon(self._rect, self._path.projected_points, gradient=gradient)
def _draw_vision_dots(self):
src = rl.Rectangle(0, 0, self._lead_orb.width, self._lead_orb.height)
for dot in self._vision_dots:
a = dot.alpha
if a <= 0.02:
continue
x, y, r = int(dot.x), int(dot.y), dot.radius
if dot.rgb is None:
r = dot.radius
dest = rl.Rectangle(dot.x, dot.y, r * 2.0, r * 2.0)
rl.draw_texture_pro(self._lead_orb, src, dest, rl.Vector2(r, r), 0.0, rl.Color(255, 255, 255, int(90 * a)))
# soft teal glow, brighter in the center fading to transparent at the edge
rl.draw_circle_gradient(x, y, r, rl.Color(120, 235, 225, int(165 * a)), rl.Color(0, 150, 150, 0))
else:
rl.draw_circle(int(dot.x), int(dot.y), dot.radius, rl.Color(dot.rgb[0], dot.rgb[1], dot.rgb[2], int(200 * a)))
rl.draw_circle_lines(int(dot.x), int(dot.y), dot.radius, rl.Color(255, 255, 255, int(160 * a)))
rl.draw_circle_gradient(x, y, r, rl.Color(dot.rgb[0], dot.rgb[1], dot.rgb[2], int(210 * a)),
rl.Color(dot.rgb[0], dot.rgb[1], dot.rgb[2], 0))
def _draw_track_dots(self):
src = rl.Rectangle(0, 0, self._lead_orb.width, self._lead_orb.height)