mirror of
https://github.com/infiniteCable2/openpilot.git
synced 2026-08-02 13:29:28 +08:00
various fixes after upstream sync
This commit is contained in:
+5
-10
@@ -60,16 +60,11 @@ class PIDController:
|
||||
|
||||
|
||||
class MultiplicativeUnwindPID:
|
||||
def __init__(self, k_p, k_i, k_f=0., k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100, min_cmd=1e-10, ki_red_time=1.0):
|
||||
if isinstance(k_p, Number):
|
||||
k_p = [[0], [k_p]]
|
||||
if isinstance(k_i, Number):
|
||||
k_i = [[0], [k_i]]
|
||||
if isinstance(k_d, Number):
|
||||
k_d = [[0], [k_d]]
|
||||
self._k_p = k_p
|
||||
self._k_i = k_i
|
||||
self._k_d = k_d
|
||||
def __init__(self, k_p: Gain, k_i: Gain, k_f=0., k_d: Gain = 0., pos_limit=1e308, neg_limit=-1e308,
|
||||
rate=100, min_cmd=1e-10, ki_red_time=1.0):
|
||||
self._k_p = ([0], [k_p]) if isinstance(k_p, (int, float)) else k_p
|
||||
self._k_i = ([0], [k_i]) if isinstance(k_i, (int, float)) else k_i
|
||||
self._k_d = ([0], [k_d]) if isinstance(k_d, (int, float)) else k_d
|
||||
self.k_f = float(k_f)
|
||||
self.pos_limit = pos_limit
|
||||
self.neg_limit = neg_limit
|
||||
|
||||
@@ -34,7 +34,7 @@ class PT2Filter:
|
||||
|
||||
=> Zeitbereich: y[k] = -a1*y[k-1] - a2*y[k-2] + b0*u[k] + b1*u[k-1] + b2*u[k-2].
|
||||
"""
|
||||
|
||||
|
||||
Ts = dt
|
||||
wd = w0
|
||||
alpha = 2.0 / Ts
|
||||
@@ -66,14 +66,14 @@ class PT2Filter:
|
||||
return (a1d, a2d, b0d, b1d, b2d)
|
||||
|
||||
def sync(self, target: float):
|
||||
steps = compute_saturation_steps(self.w0, self.zeta, self.dt)
|
||||
for i in range(1, steps + 1):
|
||||
update(target)
|
||||
steps = self.compute_saturation_steps(self.w0, self.zeta, self.dt)
|
||||
for _ in range(steps):
|
||||
self.update(target)
|
||||
|
||||
def compute_saturation_steps(self, w0: float, zeta: float, dt: float) -> int:
|
||||
"""
|
||||
Berechnet eine Abschätzung der Schritte, bis der Filter (95% des Endwerts) erreicht ist.
|
||||
|
||||
|
||||
Wir nutzen hier die Abschätzung:
|
||||
T_s = 4 / (zeta * w0)
|
||||
und setzen N = T_s / dt.
|
||||
@@ -103,10 +103,10 @@ class PT2Filter:
|
||||
+ self.b1 * self.u1
|
||||
+ self.b2 * self.u2
|
||||
)
|
||||
|
||||
|
||||
self.y2 = self.y1
|
||||
self.y1 = y
|
||||
self.u2 = self.u1
|
||||
self.u1 = u
|
||||
|
||||
|
||||
return y
|
||||
|
||||
@@ -19,13 +19,11 @@ from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, STEER_ANGLE_SATURATION_THRESHOLD
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_curvature import LatControlCurvature
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_curvature import LatControlCurvature
|
||||
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||
from openpilot.selfdrive.modeld.modeld import LAT_SMOOTH_SECONDS
|
||||
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import get_T_FOLLOW
|
||||
from openpilot.common.pt2 import PT2Filter
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
from openpilot.sunnypilot.selfdrive.controls.controlsd_ext import ControlsExt
|
||||
|
||||
@@ -119,7 +117,7 @@ class Controls(ControlsExt):
|
||||
self.force_rhd_for_bsm = self.params.get_bool("ForceRHDForBSM")
|
||||
self.enable_long_comfort_mode = self.params.get_bool("EnableLongComfortMode")
|
||||
self.disable_car_steer_alerts = self.params.get_bool("DisableCarSteerAlerts")
|
||||
|
||||
|
||||
def state_control(self):
|
||||
CS = self.sm['carState']
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
from openpilot.cereal import log
|
||||
from openpilot.common.pid import MultiplicativeUnwindPID
|
||||
@@ -25,7 +24,7 @@ class LatControlCurvature(LatControl):
|
||||
else:
|
||||
self.pid = None
|
||||
self.kf = 1.
|
||||
|
||||
|
||||
def set_pid_enabled(self, enabled: bool) -> None:
|
||||
self.enable_pid = enabled
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# def reset(self):
|
||||
# super().reset()
|
||||
# self.pid.reset()
|
||||
#
|
||||
#
|
||||
# def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, calibrated_pose, curvature_limited):
|
||||
# pid_log = log.ControlsState.LateralCurvatureState.new_message()
|
||||
# if not active:
|
||||
@@ -35,10 +35,10 @@
|
||||
# actual_curvature = np.interp(CS.vEgo, [2.0, 5.0], [actual_curvature_vm, actual_curvature_pose])
|
||||
#
|
||||
# desired_curvature_corr = desired_curvature - roll_compensation
|
||||
#
|
||||
#
|
||||
# pid_log.error = float(desired_curvature - actual_curvature)
|
||||
# freeze_integrator = steer_limited_by_safety or CS.vEgo < 5 or CS.steeringPressed
|
||||
#
|
||||
#
|
||||
# pid_curvature = self.pid.update(pid_log.error, feedforward=desired_curvature_corr, speed=CS.vEgo,
|
||||
# freeze_integrator=freeze_integrator, override=CS.steeringPressed)
|
||||
#
|
||||
|
||||
@@ -32,7 +32,7 @@ def get_max_accel(v_ego):
|
||||
|
||||
def get_coast_accel(pitch):
|
||||
return np.sin(pitch) * -5.65 - 0.3 # fitted from data using xx/projects/allow_throttle/compute_coast_accel.py
|
||||
|
||||
|
||||
|
||||
def get_lead_distance(radarState):
|
||||
if radarState.leadOne.present and (not radarState.leadTwo.present or radarState.leadOne.dRel < radarState.leadTwo.dRel):
|
||||
@@ -40,7 +40,7 @@ def get_lead_distance(radarState):
|
||||
if radarState.leadTwo.present:
|
||||
return radarState.leadTwo.dRel
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
def limit_accel_in_turns(v_ego, angle_steers, a_target, CP):
|
||||
"""
|
||||
|
||||
@@ -232,7 +232,7 @@ class TestCurvatureDController:
|
||||
def counting(*args, **kwargs):
|
||||
call_count["n"] += 1
|
||||
return original(*args, **kwargs)
|
||||
CurvatureDLookup.interp_curve_value = counting
|
||||
CurvatureDLookup.interp_curve_value = counting # ty: ignore[invalid-assignment]
|
||||
try:
|
||||
# First call: cache miss, calls interp_curve_value once
|
||||
first = controller.get_correction(32e-6, v_ego)
|
||||
|
||||
@@ -550,7 +550,7 @@ class CurvatureEstimator(CurvatureDLookup):
|
||||
self._restore_cached_params()
|
||||
self.update_use_params(force=True)
|
||||
|
||||
cloudlog.info(f"curvatured init brand={self.CP.brand} fingerprint={self.CP.carFingerprint} "
|
||||
cloudlog.info(f"curvatured init brand={self.CP.brand} fingerprint={self.CP.carFingerprint} " +
|
||||
f"steerControlType={self.CP.steerControlType} history={HISTORY:.2f}s")
|
||||
|
||||
@staticmethod
|
||||
@@ -596,8 +596,8 @@ class CurvatureEstimator(CurvatureDLookup):
|
||||
self.use_params = self.enable_curvatured and self.CP.brand in ALLOWED_CARS and \
|
||||
self.CP.steerControlType == car.CarParams.SteerControlType.curvature
|
||||
if self.prev_use_params != self.use_params:
|
||||
cloudlog.info(f"curvatured use_params={self.use_params} toggle={self.enable_curvatured} "
|
||||
f"brand={self.CP.brand} allowed={self.CP.brand in ALLOWED_CARS} "
|
||||
cloudlog.info(f"curvatured use_params={self.use_params} toggle={self.enable_curvatured} " +
|
||||
f"brand={self.CP.brand} allowed={self.CP.brand in ALLOWED_CARS} " +
|
||||
f"steerControlType={self.CP.steerControlType}")
|
||||
self.prev_use_params = self.use_params
|
||||
if not self.use_params:
|
||||
@@ -960,10 +960,10 @@ class CurvatureEstimator(CurvatureDLookup):
|
||||
self.last_status_log_t = t
|
||||
|
||||
checks = sm.all_checks(tracked_services) if valid is None else valid
|
||||
cloudlog.info(f"curvatured status use_params={self.use_params} checks={checks} "
|
||||
f"lag={self.lag:.3f} total_points={int(round(float(self.counts.sum())))} "
|
||||
f"bucket={self.current_bucket} bucket_points={self.current_bucket_points} "
|
||||
f"corr={self.current_correction:.8f} cal={self.calibration_percent(self.counts)} "
|
||||
cloudlog.info(f"curvatured status use_params={self.use_params} checks={checks} " +
|
||||
f"lag={self.lag:.3f} total_points={int(round(float(self.counts.sum())))} " +
|
||||
f"bucket={self.current_bucket} bucket_points={self.current_bucket_points} " +
|
||||
f"corr={self.current_correction:.8f} cal={self.calibration_percent(self.counts)} " +
|
||||
f"invalid={invalid} not_alive={not_alive}")
|
||||
|
||||
|
||||
|
||||
@@ -276,4 +276,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import numpy as np
|
||||
|
||||
from openpilot.cereal import custom
|
||||
from opendbc.car.structs import car
|
||||
|
||||
from opendbc.car.volkswagen.values import CAR
|
||||
@@ -233,7 +234,7 @@ class TestCurvatureEstimator:
|
||||
speed_idx = len(CurvatureDLookup.SPEED_ANCHORS) - 1
|
||||
v_ego = float(CurvatureDLookup.SPEED_ANCHORS[speed_idx])
|
||||
required = CurvatureDLookup.required_support_bucket_count(speed_idx)
|
||||
selected_indices = list(range(0, required - 1)) + [required]
|
||||
selected_indices = list(range(required - 1)) + [required]
|
||||
|
||||
for bucket_idx in selected_indices:
|
||||
desired_curvature = float(CurvatureDLookup.CURVATURE_BUCKET_CENTERS[bucket_idx])
|
||||
@@ -262,7 +263,6 @@ class TestCurvatureEstimator:
|
||||
|
||||
def test_outer_learned_buckets_stay_invalid_for_apply(self):
|
||||
speed_idx = len(CurvatureDLookup.SPEED_ANCHORS) - 1
|
||||
v_ego = float(CurvatureDLookup.SPEED_ANCHORS[speed_idx])
|
||||
outer_idx = len(CurvatureDLookup.CURVATURE_BUCKET_CENTERS) - 1
|
||||
counts = np.zeros(CurvatureDLookup.bucket_shape(), dtype=np.float32)
|
||||
bias = np.zeros(CurvatureDLookup.bucket_shape(), dtype=np.float32)
|
||||
|
||||
@@ -289,4 +289,4 @@ if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Process the --demo argument.')
|
||||
parser.add_argument('--demo', action='store_true', help='A boolean for demo mode.')
|
||||
args = parser.parse_args()
|
||||
main(demo=args.demo)
|
||||
main(demo=args.demo)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from openpilot.cereal import log
|
||||
from openpilot.common.params import Params, UnknownKeyName
|
||||
from openpilot.system.ui.widgets import Widget
|
||||
from openpilot.system.ui.widgets.list_view import toggle_item
|
||||
@@ -16,7 +15,8 @@ DESCRIPTIONS = {
|
||||
"Enables curvature PID post-processing additionally to QFK curvature offset"
|
||||
),
|
||||
"EnableCurvatureD": tr_noop(
|
||||
"Learns speed- and curvature-dependent steering corrections around center for dynamic steering behavior. Experimental and only used on curvature-based steering paths."
|
||||
"Learns speed- and curvature-dependent steering corrections around center for dynamic steering behavior. " +
|
||||
"Experimental and only used on curvature-based steering paths."
|
||||
),
|
||||
"ShowDynamicSteeringLearnerGraph": tr_noop(
|
||||
"Display the current dynamic steering learner fit, marker, and status information in the onroad UI."
|
||||
|
||||
@@ -100,15 +100,15 @@ class SoftwareLayout(Widget):
|
||||
self._version_item.action_item.set_text(current_desc)
|
||||
self._version_item.set_description(current_release_notes)
|
||||
|
||||
# Update download button visibility and state
|
||||
self._download_btn.set_visible(ui_state.is_offroad())
|
||||
self._force_download_btn.set_visible(ui_state.is_offroad())
|
||||
|
||||
updater_state = ui_state.params.get("UpdaterState") or "idle"
|
||||
failed_count = ui_state.params.get("UpdateFailedCount") or 0
|
||||
fetch_available = ui_state.params.get_bool("UpdaterFetchAvailable")
|
||||
update_available = ui_state.params.get_bool("UpdateAvailable")
|
||||
|
||||
# Update download button visibility and state
|
||||
self._download_btn.set_visible(ui_state.is_offroad())
|
||||
self._force_download_btn.set_visible(ui_state.is_offroad() and not update_available)
|
||||
|
||||
if updater_state != "idle":
|
||||
# Updater responded
|
||||
self._waiting_for_updater = False
|
||||
@@ -189,7 +189,7 @@ class SoftwareLayout(Widget):
|
||||
self._force_download_btn.action_item.set_enabled(False)
|
||||
self._waiting_for_updater = True
|
||||
self._waiting_start_ts = time.monotonic()
|
||||
os.system("pkill -SIGUSR2 -f system.updated.updated")
|
||||
subprocess.run("pkill -SIGUSR2 -f openpilot.system.updated.updated", shell=True)
|
||||
|
||||
def _on_select_branch(self):
|
||||
# Get available branches and order
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
from openpilot.cereal import log
|
||||
|
||||
from openpilot.system.ui.widgets.scroller import NavScroller
|
||||
from openpilot.selfdrive.ui.mici.widgets.button import BigParamControl, BigMultiParamToggle
|
||||
from openpilot.selfdrive.ui.mici.widgets.button import BigParamControl
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.selfdrive.ui.layouts.settings.common import restart_needed_callback
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
|
||||
|
||||
@@ -25,7 +22,7 @@ class ICTogglesLayoutMici(NavScroller):
|
||||
enable_accel_bar = BigParamControl("Enable Accel Bar", "ShowAccelBar")
|
||||
enable_curvatured = BigParamControl("Enable Dynamic Steering Learner", "EnableCurvatureD")
|
||||
show_curvatured_graph = BigParamControl("Show Dynamic Steering Learner Graph", "ShowDynamicSteeringLearnerGraph")
|
||||
|
||||
|
||||
self._scroller.add_widgets([
|
||||
enable_curvature_correction,
|
||||
enable_long_comfort_mode,
|
||||
|
||||
@@ -24,11 +24,11 @@ class SettingsLayout(NavScroller):
|
||||
toggles_panel = TogglesLayoutMici()
|
||||
toggles_btn = SettingsBigButton("toggles", "", gui_app.texture("icons_mici/settings.png", 64, 64))
|
||||
toggles_btn.set_click_callback(lambda: gui_app.push_widget(toggles_panel))
|
||||
|
||||
|
||||
ictoggles_panel = ICTogglesLayoutMici()
|
||||
ictoggles_btn = SettingsBigButton("ictoggles", "", gui_app.texture("icons_mici/settings.png", 64, 64))
|
||||
ictoggles_btn.set_click_callback(lambda: gui_app.push_widget(ictoggles_panel))
|
||||
|
||||
|
||||
network_panel = NetworkLayoutMici()
|
||||
network_btn = SettingsBigButton("network", "", gui_app.texture("icons_mici/settings/network/wifi_strength_full.png", 76, 56))
|
||||
network_btn.set_click_callback(lambda: gui_app.push_widget(network_panel))
|
||||
|
||||
@@ -124,7 +124,6 @@ class DynamicSteeringLearnerGraphMici(Widget):
|
||||
lcp = sm["liveCurvatureParameters"]
|
||||
lcp_frame = sm.recv_frame["liveCurvatureParameters"]
|
||||
car_state = sm["carState"]
|
||||
controls_state = sm["controlsState"]
|
||||
|
||||
fit_corrections = np.zeros(CurvatureDLookup.bucket_shape(), dtype=np.float32)
|
||||
fit_valid = np.zeros(CurvatureDLookup.bucket_shape(), dtype=bool)
|
||||
@@ -194,7 +193,8 @@ class DynamicSteeringLearnerGraphMici(Widget):
|
||||
0.0, 1.0,
|
||||
))
|
||||
marker_x = plot_rect.x + marker_alpha * plot_rect.width
|
||||
marker_correction = float(np.interp(abs(desired_curvature), np.abs(self._plot_x), self._cached_fit_curve))
|
||||
center_idx = len(self._plot_x) // 2
|
||||
marker_correction = float(np.interp(abs(desired_curvature), self._plot_x[center_idx:], corrections[center_idx:]))
|
||||
marker_y = self._map_y(plot_rect, marker_correction, min_y, max_y)
|
||||
rl.draw_circle(int(marker_x), int(marker_y), 5, self._marker_glow_color)
|
||||
rl.draw_circle(int(marker_x), int(marker_y), 3, self._marker_color)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import pyray as rl
|
||||
import time
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pyray as rl
|
||||
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.system.ui.lib.application import gui_app, FontWeight
|
||||
@@ -16,19 +17,21 @@ class BatteryPanelConfig:
|
||||
line_height: int = 48 # Basis-Zeilenhöhe
|
||||
label_width: int = 320
|
||||
text_margin: int = 25 # Abstand Label → Wert
|
||||
|
||||
|
||||
|
||||
CONFIG = BatteryPanelConfig()
|
||||
|
||||
|
||||
class BatteryDetails(Widget):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._params = Params()
|
||||
|
||||
|
||||
self._capacity: float = 0.0
|
||||
self._charge: float = 0.0
|
||||
self._soc: float = 0.0
|
||||
self._temperature: float = 0.0
|
||||
self._heaterActive: bool = False
|
||||
self._heater_active: bool = False
|
||||
self._voltage: float = 0.0
|
||||
self._current: float = 0.0
|
||||
self._power: float = 0.0
|
||||
@@ -37,21 +40,23 @@ class BatteryDetails(Widget):
|
||||
self._panel_bg: rl.Color = rl.Color(0, 0, 0, 128)
|
||||
self._label_color: rl.Color = rl.Color(220, 220, 220, 255)
|
||||
self._value_color: rl.Color = rl.Color(255, 255, 255, 255)
|
||||
|
||||
|
||||
self._display_enabled: bool = False
|
||||
self._data_valid: bool = False
|
||||
self._param_update_time: float = 0.0
|
||||
|
||||
|
||||
self._update_params()
|
||||
|
||||
def _update_state(self) -> None:
|
||||
if time.monotonic() - self._param_update_time > 2.0:
|
||||
self._update_params()
|
||||
|
||||
|
||||
if not self._display_enabled:
|
||||
return
|
||||
|
||||
|
||||
sm = ui_state.sm
|
||||
if sm.recv_frame["carState"] < ui_state.started_frame:
|
||||
if (sm.recv_frame["carStateIC"] < ui_state.started_frame or
|
||||
not sm.valid["carStateIC"] or not sm.alive["carStateIC"]):
|
||||
self._reset_values()
|
||||
return
|
||||
|
||||
@@ -66,11 +71,12 @@ class BatteryDetails(Widget):
|
||||
self._voltage = float(battery_data.voltage)
|
||||
self._current = float(battery_data.current)
|
||||
self._power = float(battery_data.power)
|
||||
|
||||
self._data_valid = True
|
||||
|
||||
def _update_params(self) -> None:
|
||||
self._param_update_time = time.monotonic()
|
||||
self._display_enabled = self._params.get_bool("BatteryDetails")
|
||||
|
||||
|
||||
def _reset_values(self) -> None:
|
||||
self._capacity = 0.0
|
||||
self._charge = 0.0
|
||||
@@ -80,9 +86,10 @@ class BatteryDetails(Widget):
|
||||
self._voltage = 0.0
|
||||
self._current = 0.0
|
||||
self._power = 0.0
|
||||
self._data_valid = False
|
||||
|
||||
def _render(self, rect: rl.Rectangle) -> None:
|
||||
if not self._display_enabled:
|
||||
if not self._display_enabled or not self._data_valid:
|
||||
return
|
||||
|
||||
scale = CONFIG.scale_factor
|
||||
@@ -103,7 +110,6 @@ class BatteryDetails(Widget):
|
||||
label_width = CONFIG.label_width
|
||||
text_margin = CONFIG.text_margin
|
||||
column_spacing = panel_width // 2 - 40
|
||||
value_width = column_spacing - label_width - text_margin
|
||||
|
||||
labels = [
|
||||
"Capacity:", "Charge:", "SoC:", "Temperature:",
|
||||
@@ -121,9 +127,7 @@ class BatteryDetails(Widget):
|
||||
f"{self._power:.2f} kW",
|
||||
]
|
||||
|
||||
rl.draw_text_ex
|
||||
|
||||
for i, (label, value) in enumerate(zip(labels, values)):
|
||||
for i, (label, value) in enumerate(zip(labels, values, strict=True)):
|
||||
column = i // 4
|
||||
row = i % 4
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ class DynamicSteeringLearnerGraph(Widget):
|
||||
rl.draw_rectangle_rounded(graph_rect, 0.08, 8, self._panel_bg)
|
||||
|
||||
lcp_frame = sm.recv_frame["liveCurvatureParameters"]
|
||||
controls_state = sm["controlsState"]
|
||||
car_state = sm["carState"]
|
||||
|
||||
fit_corrections = np.zeros(CurvatureDLookup.bucket_shape(), dtype=np.float32)
|
||||
@@ -276,17 +275,17 @@ class DynamicSteeringLearnerGraph(Widget):
|
||||
rl.draw_text_ex(self._font_bold, title, rl.Vector2(text_x, title_y), title_size, 0, self._text_color)
|
||||
|
||||
status_text = (
|
||||
f"live={payload_valid} transport={transport_valid} cal={int(getattr(lcp, 'calPerc', 0))}% "
|
||||
f"live={payload_valid} transport={transport_valid} cal={int(getattr(lcp, 'calPerc', 0))}% " +
|
||||
f"points={int(getattr(lcp, 'totalBucketPoints', 0))}"
|
||||
)
|
||||
rl.draw_text_ex(self._font_medium, status_text, rl.Vector2(text_x, status_y), status_size, 0, self._muted_text_color)
|
||||
|
||||
speed_mix = (
|
||||
f"v={v_ego * 3.6:.0f} km/h mix={CurvatureDLookup.SPEED_ANCHORS[low_idx] * 3.6:.0f}/"
|
||||
f"v={v_ego * 3.6:.0f} km/h mix={CurvatureDLookup.SPEED_ANCHORS[low_idx] * 3.6:.0f}/" +
|
||||
f"{CurvatureDLookup.SPEED_ANCHORS[high_idx] * 3.6:.0f} alpha={alpha:.2f}"
|
||||
)
|
||||
marker_info = (
|
||||
f"k={desired_curvature:.2e} corr={display_correction:.2e} "
|
||||
f"k={desired_curvature:.2e} corr={display_correction:.2e} " +
|
||||
f"bucket=({int(getattr(lcp, 'bucketSpeed', -1))}, {int(getattr(lcp, 'bucketCurvature', -1))})"
|
||||
)
|
||||
rl.draw_text_ex(self._font_medium, speed_mix, rl.Vector2(text_x, footer_y1), footer_size, 0, self._muted_text_color)
|
||||
|
||||
@@ -120,7 +120,9 @@ class SteeringLayout(Widget):
|
||||
def _update_state(self):
|
||||
super()._update_state()
|
||||
|
||||
torque_allowed = ui_state.CP is not None and ui_state.CP.steerControlType not in (car.CarParams.SteerControlType.angle, car.CarParams.SteerControlType.curvature)
|
||||
torque_allowed = (ui_state.CP is not None and
|
||||
ui_state.CP.steerControlType not in (car.CarParams.SteerControlType.angle,
|
||||
car.CarParams.SteerControlType.curvature))
|
||||
if ui_state.CP is not None:
|
||||
mads_main_desc = self._mads_limited_desc if self._mads_settings_layout._mads_limited_settings() else self._mads_full_desc
|
||||
self._mads_toggle.set_description(f"<b>{mads_main_desc}</b><br><br>{self._mads_base_desc}")
|
||||
|
||||
@@ -381,6 +381,14 @@ def build_mici_script(pm: PubMaster, main_layout, script: Script) -> None:
|
||||
def build_tizi_script(pm: PubMaster, main_layout, script: Script) -> None:
|
||||
"""Build the replay script for the tizi layout."""
|
||||
|
||||
def select_settings_panel(panel_name: str) -> None:
|
||||
"""Select a settings panel without relying on stock or sunnypilot sidebar coordinates."""
|
||||
from openpilot.selfdrive.ui.layouts.main import MainState
|
||||
|
||||
settings_layout = main_layout._layouts[MainState.SETTINGS]
|
||||
panel_type = next(panel_type for panel_type in settings_layout._panels if panel_type.name == panel_name)
|
||||
settings_layout.set_current_panel(panel_type)
|
||||
|
||||
def make_home_refresh_setup(fn: Callable) -> Callable:
|
||||
"""Return setup function that calls the given function to modify state and forces an immediate refresh on the home layout."""
|
||||
from openpilot.selfdrive.ui.layouts.main import MainState
|
||||
@@ -457,7 +465,7 @@ def build_tizi_script(pm: PubMaster, main_layout, script: Script) -> None:
|
||||
script.click(2000, 970) # OK
|
||||
|
||||
# === Settings - Network ===
|
||||
script.click(278, 450)
|
||||
script.setup(lambda: select_settings_panel("NETWORK"))
|
||||
# TODO: mock networks
|
||||
script.click(1880, 100) # advanced network settings
|
||||
|
||||
@@ -473,12 +481,12 @@ def build_tizi_script(pm: PubMaster, main_layout, script: Script) -> None:
|
||||
script.click(630, 80) # back from advanced network
|
||||
|
||||
# === Settings - Toggles ===
|
||||
script.click(278, 600)
|
||||
script.setup(lambda: select_settings_panel("TOGGLES"))
|
||||
script.click(1200, 280) # expand experimental mode description
|
||||
|
||||
# === Settings - Software ===
|
||||
script.setup(lambda: setup_update_available(False), wait_after=0) # start with no update available
|
||||
script.click(278, 720) # software
|
||||
script.setup(lambda: select_settings_panel("SOFTWARE"))
|
||||
for _ in range(2):
|
||||
script.click(720, 120) # toggle current release notes
|
||||
script.setup(setup_update_available) # set update available
|
||||
@@ -491,11 +499,11 @@ def build_tizi_script(pm: PubMaster, main_layout, script: Script) -> None:
|
||||
script.click(650, 750) # cancel uninstall
|
||||
|
||||
# === Settings - Firehose ===
|
||||
script.click(278, 845)
|
||||
script.setup(lambda: select_settings_panel("FIREHOSE"))
|
||||
|
||||
# === Settings - Developer (set CarParamsPersistent first) ===
|
||||
script.setup(setup_developer_params, wait_after=0)
|
||||
script.click(278, 950)
|
||||
script.setup(lambda: select_settings_panel("DEVELOPER"))
|
||||
script.click(1930, 470) # SSH keys (keyboard)
|
||||
script.click(1930, 115) # click cancel on keyboard
|
||||
script.click(2000, 960) # toggle alpha long
|
||||
|
||||
@@ -99,7 +99,7 @@ class UIState(UIStateSP):
|
||||
self.is_body: bool | None = None
|
||||
self.CP: car.CarParams | None = None
|
||||
self.light_sensor: float = -1.0
|
||||
|
||||
|
||||
self.dark_mode: bool = False
|
||||
self.onroad_screen_timeout: bool = False
|
||||
self.enable_accel_bar: bool = False
|
||||
@@ -190,11 +190,11 @@ class UIState(UIStateSP):
|
||||
self.status = UIStatus.OVERRIDE
|
||||
else:
|
||||
self.status = UIStatus.ENGAGED if ss.enabled else UIStatus.DISENGAGED
|
||||
|
||||
|
||||
# detect status change
|
||||
self.has_status_change = True if self.status != self._status_prev else False
|
||||
self._status_prev = self.status
|
||||
|
||||
|
||||
# check for alert
|
||||
self.has_alert = True if ss.alertSize != 0 else False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user