diff --git a/openpilot/common/pid.py b/openpilot/common/pid.py index b5bb0e00b..f2765fdd7 100644 --- a/openpilot/common/pid.py +++ b/openpilot/common/pid.py @@ -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 diff --git a/openpilot/common/pt2.py b/openpilot/common/pt2.py index 14270619f..070586835 100644 --- a/openpilot/common/pt2.py +++ b/openpilot/common/pt2.py @@ -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 diff --git a/openpilot/selfdrive/controls/controlsd.py b/openpilot/selfdrive/controls/controlsd.py index 62755531e..ac2e0dea9 100644 --- a/openpilot/selfdrive/controls/controlsd.py +++ b/openpilot/selfdrive/controls/controlsd.py @@ -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'] diff --git a/openpilot/selfdrive/controls/lib/latcontrol_curvature.py b/openpilot/selfdrive/controls/lib/latcontrol_curvature.py index 05c40a130..5ea185c87 100644 --- a/openpilot/selfdrive/controls/lib/latcontrol_curvature.py +++ b/openpilot/selfdrive/controls/lib/latcontrol_curvature.py @@ -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 diff --git a/openpilot/selfdrive/controls/lib/latcontrol_curvature_pid_backup.py b/openpilot/selfdrive/controls/lib/latcontrol_curvature_pid_backup.py index 50eb23bf5..9dfeb4239 100644 --- a/openpilot/selfdrive/controls/lib/latcontrol_curvature_pid_backup.py +++ b/openpilot/selfdrive/controls/lib/latcontrol_curvature_pid_backup.py @@ -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) # diff --git a/openpilot/selfdrive/controls/lib/longitudinal_planner.py b/openpilot/selfdrive/controls/lib/longitudinal_planner.py index 19caae7a8..d2454103c 100644 --- a/openpilot/selfdrive/controls/lib/longitudinal_planner.py +++ b/openpilot/selfdrive/controls/lib/longitudinal_planner.py @@ -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): """ diff --git a/openpilot/selfdrive/controls/tests/test_curvatured.py b/openpilot/selfdrive/controls/tests/test_curvatured.py index d0f86509b..cbea511b6 100644 --- a/openpilot/selfdrive/controls/tests/test_curvatured.py +++ b/openpilot/selfdrive/controls/tests/test_curvatured.py @@ -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) diff --git a/openpilot/selfdrive/locationd/curvatured.py b/openpilot/selfdrive/locationd/curvatured.py index 4d0f2b724..f96fb9c8e 100644 --- a/openpilot/selfdrive/locationd/curvatured.py +++ b/openpilot/selfdrive/locationd/curvatured.py @@ -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}") diff --git a/openpilot/selfdrive/locationd/paramsd.py b/openpilot/selfdrive/locationd/paramsd.py index e6c1ff7b4..c1088a818 100755 --- a/openpilot/selfdrive/locationd/paramsd.py +++ b/openpilot/selfdrive/locationd/paramsd.py @@ -276,4 +276,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/openpilot/selfdrive/locationd/test/test_curvatured.py b/openpilot/selfdrive/locationd/test/test_curvatured.py index 62145f20d..bc40ea0bb 100644 --- a/openpilot/selfdrive/locationd/test/test_curvatured.py +++ b/openpilot/selfdrive/locationd/test/test_curvatured.py @@ -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) diff --git a/openpilot/selfdrive/locationd/torqued.py b/openpilot/selfdrive/locationd/torqued.py index a1010ca55..1d4aa8bc3 100755 --- a/openpilot/selfdrive/locationd/torqued.py +++ b/openpilot/selfdrive/locationd/torqued.py @@ -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) \ No newline at end of file + main(demo=args.demo) diff --git a/openpilot/selfdrive/ui/layouts/settings/ictoggles.py b/openpilot/selfdrive/ui/layouts/settings/ictoggles.py index b8d9566fa..bb8159ddd 100644 --- a/openpilot/selfdrive/ui/layouts/settings/ictoggles.py +++ b/openpilot/selfdrive/ui/layouts/settings/ictoggles.py @@ -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." diff --git a/openpilot/selfdrive/ui/layouts/settings/software.py b/openpilot/selfdrive/ui/layouts/settings/software.py index 41badce55..ab8cf6fb4 100644 --- a/openpilot/selfdrive/ui/layouts/settings/software.py +++ b/openpilot/selfdrive/ui/layouts/settings/software.py @@ -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 diff --git a/openpilot/selfdrive/ui/mici/layouts/settings/ictoggles.py b/openpilot/selfdrive/ui/mici/layouts/settings/ictoggles.py index 0bd78042a..a2ad07d01 100644 --- a/openpilot/selfdrive/ui/mici/layouts/settings/ictoggles.py +++ b/openpilot/selfdrive/ui/mici/layouts/settings/ictoggles.py @@ -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, diff --git a/openpilot/selfdrive/ui/mici/layouts/settings/settings.py b/openpilot/selfdrive/ui/mici/layouts/settings/settings.py index c27a89fd5..c0e00e449 100644 --- a/openpilot/selfdrive/ui/mici/layouts/settings/settings.py +++ b/openpilot/selfdrive/ui/mici/layouts/settings/settings.py @@ -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)) diff --git a/openpilot/selfdrive/ui/mici/onroad/dynamic_steering_learner_graph.py b/openpilot/selfdrive/ui/mici/onroad/dynamic_steering_learner_graph.py index 2bc312d8c..074c2711c 100644 --- a/openpilot/selfdrive/ui/mici/onroad/dynamic_steering_learner_graph.py +++ b/openpilot/selfdrive/ui/mici/onroad/dynamic_steering_learner_graph.py @@ -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) diff --git a/openpilot/selfdrive/ui/onroad/battery_details.py b/openpilot/selfdrive/ui/onroad/battery_details.py index 8b936c6b4..ebdebde69 100644 --- a/openpilot/selfdrive/ui/onroad/battery_details.py +++ b/openpilot/selfdrive/ui/onroad/battery_details.py @@ -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 diff --git a/openpilot/selfdrive/ui/onroad/dynamic_steering_learner_graph.py b/openpilot/selfdrive/ui/onroad/dynamic_steering_learner_graph.py index 2055d8019..36b84b1ab 100644 --- a/openpilot/selfdrive/ui/onroad/dynamic_steering_learner_graph.py +++ b/openpilot/selfdrive/ui/onroad/dynamic_steering_learner_graph.py @@ -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) diff --git a/openpilot/selfdrive/ui/sunnypilot/layouts/settings/steering.py b/openpilot/selfdrive/ui/sunnypilot/layouts/settings/steering.py index 008d8c791..796196962 100644 --- a/openpilot/selfdrive/ui/sunnypilot/layouts/settings/steering.py +++ b/openpilot/selfdrive/ui/sunnypilot/layouts/settings/steering.py @@ -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"{mads_main_desc}

{self._mads_base_desc}") diff --git a/openpilot/selfdrive/ui/tests/diff/replay_script.py b/openpilot/selfdrive/ui/tests/diff/replay_script.py index 109f32e47..ebfb6d5f7 100644 --- a/openpilot/selfdrive/ui/tests/diff/replay_script.py +++ b/openpilot/selfdrive/ui/tests/diff/replay_script.py @@ -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 diff --git a/openpilot/selfdrive/ui/ui_state.py b/openpilot/selfdrive/ui/ui_state.py index db1f6d17e..5221af953 100644 --- a/openpilot/selfdrive/ui/ui_state.py +++ b/openpilot/selfdrive/ui/ui_state.py @@ -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