raylib: implement calibration description (#36300)

* this is all cursor

* also cursor

* inline reset calib

* calib desc

* way better

* huh

* clean up

* rcvr

* stash changes to change params

* Revert "stash changes to change params"

This reverts commit ee998f04c4.
pull/36301/head
Shane Smiskol 4 days ago committed by GitHub
parent ddbbcc6f5d
commit f04ee80452
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      selfdrive/ui/layouts/settings/developer.py
  2. 84
      selfdrive/ui/layouts/settings/device.py
  3. 8
      system/ui/widgets/confirm_dialog.py
  4. 8
      system/ui/widgets/list_view.py

@ -70,8 +70,6 @@ class DeveloperLayout(Widget):
callback=self._on_alpha_long_enabled, callback=self._on_alpha_long_enabled,
) )
self._alpha_long_toggle.set_description(self._alpha_long_toggle.description + " Changing this setting will restart openpilot if the car is powered on.")
items = [ items = [
self._adb_toggle, self._adb_toggle,
self._ssh_toggle, self._ssh_toggle,

@ -1,8 +1,11 @@
import os import os
import json import json
import math
from cereal import messaging, log
from openpilot.common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.ui.onroad.driver_camera_dialog import DriverCameraDialog from openpilot.selfdrive.ui.onroad.driver_camera_dialog import DriverCameraDialog
from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.selfdrive.ui.layouts.onboarding import TrainingGuide from openpilot.selfdrive.ui.layouts.onboarding import TrainingGuide
@ -20,10 +23,7 @@ from openpilot.system.ui.widgets.scroller import Scroller
DESCRIPTIONS = { DESCRIPTIONS = {
'pair_device': "Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.", 'pair_device': "Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer.",
'driver_camera': "Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off)", 'driver_camera': "Preview the driver facing camera to ensure that driver monitoring has good visibility. (vehicle must be off)",
'reset_calibration': ( 'reset_calibration': "openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down.",
"openpilot requires the device to be mounted within 4° left or right and within 5° " +
"up or 9° down. openpilot is continuously calibrating, resetting is rarely required."
),
'review_guide': "Review the rules, features, and limitations of openpilot", 'review_guide': "Review the rules, features, and limitations of openpilot",
} }
@ -49,12 +49,15 @@ class DeviceLayout(Widget):
self._pair_device_btn = button_item("Pair Device", "PAIR", DESCRIPTIONS['pair_device'], callback=self._pair_device) self._pair_device_btn = button_item("Pair Device", "PAIR", DESCRIPTIONS['pair_device'], callback=self._pair_device)
self._pair_device_btn.set_visible(lambda: not ui_state.prime_state.is_paired()) self._pair_device_btn.set_visible(lambda: not ui_state.prime_state.is_paired())
self._reset_calib_btn = button_item("Reset Calibration", "RESET", DESCRIPTIONS['reset_calibration'], callback=self._reset_calibration_prompt)
self._reset_calib_btn.set_description_opened_callback(self._update_calib_description)
items = [ items = [
text_item("Dongle ID", dongle_id), text_item("Dongle ID", dongle_id),
text_item("Serial", serial), text_item("Serial", serial),
self._pair_device_btn, self._pair_device_btn,
button_item("Driver Camera", "PREVIEW", DESCRIPTIONS['driver_camera'], callback=self._show_driver_camera, enabled=ui_state.is_offroad), button_item("Driver Camera", "PREVIEW", DESCRIPTIONS['driver_camera'], callback=self._show_driver_camera, enabled=ui_state.is_offroad),
button_item("Reset Calibration", "RESET", DESCRIPTIONS['reset_calibration'], callback=self._reset_calibration_prompt), self._reset_calib_btn,
button_item("Review Training Guide", "REVIEW", DESCRIPTIONS['review_guide'], self._on_review_training_guide), button_item("Review Training Guide", "REVIEW", DESCRIPTIONS['review_guide'], self._on_review_training_guide),
regulatory_btn := button_item("Regulatory", "VIEW", callback=self._on_regulatory), regulatory_btn := button_item("Regulatory", "VIEW", callback=self._on_regulatory),
button_item("Change Language", "CHANGE", callback=self._show_language_selection, enabled=ui_state.is_offroad), button_item("Change Language", "CHANGE", callback=self._show_language_selection, enabled=ui_state.is_offroad),
@ -95,19 +98,68 @@ class DeviceLayout(Widget):
gui_app.set_modal_overlay(alert_dialog("Disengage to Reset Calibration")) gui_app.set_modal_overlay(alert_dialog("Disengage to Reset Calibration"))
return return
dialog = ConfirmDialog("Are you sure you want to reset calibration?", "Reset") def reset_calibration(result: int):
gui_app.set_modal_overlay(dialog, callback=self._reset_calibration) # Check engaged again in case it changed while the dialog was open
if ui_state.engaged or result != DialogResult.CONFIRM:
return
def _reset_calibration(self, result: int): self._params.remove("CalibrationParams")
if ui_state.engaged or result != DialogResult.CONFIRM: self._params.remove("LiveTorqueParameters")
return self._params.remove("LiveParameters")
self._params.remove("LiveParametersV2")
self._params.remove("LiveDelay")
self._params.put_bool("OnroadCycleRequested", True)
self._update_calib_description()
self._params.remove("CalibrationParams") dialog = ConfirmDialog("Are you sure you want to reset calibration?", "Reset")
self._params.remove("LiveTorqueParameters") gui_app.set_modal_overlay(dialog, callback=reset_calibration)
self._params.remove("LiveParameters")
self._params.remove("LiveParametersV2") def _update_calib_description(self):
self._params.remove("LiveDelay") desc = DESCRIPTIONS['reset_calibration']
self._params.put_bool("OnroadCycleRequested", True)
calib_bytes = self._params.get("CalibrationParams")
if calib_bytes:
try:
calib = messaging.log_from_bytes(calib_bytes, log.Event).liveCalibration
if calib.calStatus != log.LiveCalibrationData.Status.uncalibrated:
pitch = math.degrees(calib.rpyCalib[1])
yaw = math.degrees(calib.rpyCalib[2])
desc += f" Your device is pointed {abs(pitch):.1f}° {'down' if pitch > 0 else 'up'} and {abs(yaw):.1f}° {'left' if yaw > 0 else 'right'}."
except Exception:
cloudlog.exception("invalid CalibrationParams")
lag_perc = 0
lag_bytes = self._params.get("LiveDelay")
if lag_bytes:
try:
lag_perc = messaging.log_from_bytes(lag_bytes, log.Event).liveDelay.calPerc
except Exception:
cloudlog.exception("invalid LiveDelay")
if lag_perc < 100:
desc += f"<br><br>Steering lag calibration is {lag_perc}% complete."
else:
desc += "<br><br>Steering lag calibration is complete."
torque_bytes = self._params.get("LiveTorqueParameters")
if torque_bytes:
try:
torque = messaging.log_from_bytes(torque_bytes, log.Event).liveTorqueParameters
# don't add for non-torque cars
if torque.useParams:
torque_perc = torque.calPerc
if torque_perc < 100:
desc += f" Steering torque response calibration is {torque_perc}% complete."
else:
desc += " Steering torque response calibration is complete."
except Exception:
cloudlog.exception("invalid LiveTorqueParameters")
desc += "<br><br>"
desc += ("openpilot is continuously calibrating, resetting is rarely required. " +
"Resetting calibration will restart openpilot if the car is powered on.")
self._reset_calib_btn.set_description(desc)
def _reboot_prompt(self): def _reboot_prompt(self):
if ui_state.engaged: if ui_state.engaged:

@ -78,12 +78,12 @@ class ConfirmDialog(Widget):
self._confirm_button.render(confirm_button) self._confirm_button.render(confirm_button)
self._cancel_button.render(cancel_button) self._cancel_button.render(cancel_button)
else: else:
centered_button_x = dialog_rect.x + (dialog_rect.width - button_width) / 2 full_button_width = dialog_rect.width - 2 * MARGIN
centered_confirm_button = rl.Rectangle(centered_button_x, button_y, button_width, BUTTON_HEIGHT) full_confirm_button = rl.Rectangle(dialog_rect.x + MARGIN, button_y, full_button_width, BUTTON_HEIGHT)
self._confirm_button.render(centered_confirm_button) self._confirm_button.render(full_confirm_button)
return self._dialog_result return self._dialog_result
def alert_dialog(message: str, button_text: str = "OK"): def alert_dialog(message: str, button_text: str = "Ok"):
return ConfirmDialog(message, button_text, cancel_text="") return ConfirmDialog(message, button_text, cancel_text="")

@ -268,6 +268,7 @@ class ListItem(Widget):
self._description = description self._description = description
self.description_visible = description_visible self.description_visible = description_visible
self.callback = callback self.callback = callback
self.description_opened_callback: Callable | None = None
self.action_item = action_item self.action_item = action_item
self.set_rect(rl.Rectangle(0, 0, ITEM_BASE_WIDTH, ITEM_BASE_HEIGHT)) self.set_rect(rl.Rectangle(0, 0, ITEM_BASE_WIDTH, ITEM_BASE_HEIGHT))
@ -280,6 +281,9 @@ class ListItem(Widget):
# Cached properties for performance # Cached properties for performance
self._prev_description: str | None = self.description self._prev_description: str | None = self.description
def set_description_opened_callback(self, callback: Callable) -> None:
self.description_opened_callback = callback
def set_touch_valid_callback(self, touch_callback: Callable[[], bool]) -> None: def set_touch_valid_callback(self, touch_callback: Callable[[], bool]) -> None:
super().set_touch_valid_callback(touch_callback) super().set_touch_valid_callback(touch_callback)
if self.action_item: if self.action_item:
@ -302,6 +306,10 @@ class ListItem(Widget):
if self.description: if self.description:
self.description_visible = not self.description_visible self.description_visible = not self.description_visible
# do callback first in case receiver changes description
if self.description_visible and self.description_opened_callback is not None:
self.description_opened_callback()
content_width = int(self._rect.width - ITEM_PADDING * 2) content_width = int(self._rect.width - ITEM_PADDING * 2)
self._rect.height = self.get_item_height(self._font, content_width) self._rect.height = self.get_item_height(self._font, content_width)

Loading…
Cancel
Save