ui: Speed Limit Assist preActive improvements (#1743)

* mici init

* obv

* hybrid

* too soon junior

* make them all flash the same pls

* abstract

* shorter

* also too soon junior

* not so fast
This commit is contained in:
Jason Wen
2026-02-28 15:23:04 -05:00
committed by GitHub
parent 16047e3c3d
commit 3981001f7d
4 changed files with 51 additions and 36 deletions
+36 -25
View File
@@ -6,7 +6,6 @@ See the LICENSE.md file in the root directory for more details.
"""
from dataclasses import dataclass
import math
import pyray as rl
from cereal import custom
@@ -41,9 +40,32 @@ class Colors:
MUTCD_LINES = rl.Color(255, 255, 255, 100)
class SpeedLimitRenderer(Widget):
class SpeedLimitAlertRenderer:
def __init__(self):
super().__init__()
arrow_size = 200
self.arrow_up = gui_app.texture("../../sunnypilot/selfdrive/assets/img_plus_arrow_up.png", arrow_size, arrow_size)
self.arrow_down = gui_app.texture("../../sunnypilot/selfdrive/assets/img_minus_arrow_down.png", arrow_size, arrow_size)
self._pre_active_alpha_filter = FirstOrderFilter(1.0, 0.05, 1 / gui_app.target_fps)
self._pre_active_alert_frame = 0
def update(self):
assist_state = ui_state.sm['longitudinalPlanSP'].speedLimit.assist.state
if assist_state == AssistState.preActive:
self._pre_active_alert_frame += 1
if (self._pre_active_alert_frame % gui_app.target_fps) < (gui_app.target_fps * 0.75):
self._pre_active_alpha_filter.x = 1.0
else:
self._pre_active_alpha_filter.update(0.0)
else:
self._pre_active_alert_frame = 0
self._pre_active_alpha_filter.update(1.0)
class SpeedLimitRenderer(Widget, SpeedLimitAlertRenderer):
def __init__(self):
Widget.__init__(self)
SpeedLimitAlertRenderer.__init__(self)
self.speed_limit = 0.0
self.speed_limit_last = 0.0
@@ -60,7 +82,6 @@ class SpeedLimitRenderer(Widget):
self.speed_limit_ahead_valid = False
self.speed_limit_ahead_frame = 0
self.assist_frame = 0
self.is_cruise_set: bool = False
self.is_cruise_available: bool = True
self.set_speed: float = SET_SPEED_NA
@@ -70,17 +91,13 @@ class SpeedLimitRenderer(Widget):
self.font_bold = gui_app.font(FontWeight.BOLD)
self.font_demi = gui_app.font(FontWeight.SEMI_BOLD)
self.font_norm = gui_app.font(FontWeight.NORMAL)
self._sign_alpha_filter = FirstOrderFilter(1.0, 0.5, 1 / gui_app.target_fps)
arrow_size = 90
self._arrow_up = gui_app.texture("../../sunnypilot/selfdrive/assets/img_plus_arrow_up.png", arrow_size, arrow_size)
self._arrow_down = gui_app.texture("../../sunnypilot/selfdrive/assets/img_minus_arrow_down.png", arrow_size, arrow_size)
@property
def speed_conv(self):
return CV.MS_TO_KPH if ui_state.is_metric else CV.MS_TO_MPH
def update(self):
SpeedLimitAlertRenderer.update(self)
sm = ui_state.sm
if sm.recv_frame["carState"] < ui_state.started_frame:
self.set_speed = SET_SPEED_NA
@@ -143,13 +160,7 @@ class SpeedLimitRenderer(Widget):
sign_rect = rl.Rectangle(x, y, width, UI_CONFIG.set_speed_height + 6 * 2)
if self.speed_limit_assist_state == AssistState.preActive:
self.assist_frame += 1
pulse_value = 0.65 + 0.35 * math.sin(self.assist_frame * math.pi / gui_app.target_fps)
alpha = self._sign_alpha_filter.update(pulse_value)
else:
self.assist_frame = 0
alpha = self._sign_alpha_filter.update(1.0)
alpha = self._pre_active_alpha_filter.x
if ui_state.speed_limit_mode != SpeedLimitMode.off:
self._draw_sign_main(sign_rect, alpha)
@@ -184,19 +195,19 @@ class SpeedLimitRenderer(Widget):
set_speed_rounded = round(self.set_speed)
limit_rounded = round(self.speed_limit_final_last)
bounce_frequency = 2.0 * math.pi / (gui_app.target_fps * 2.5)
bounce_offset = int(20 * math.sin(self.assist_frame * bounce_frequency))
sign_margin = 12
arrow_spacing = int(sign_margin * 1.4)
arrow_x = sign_rect.x + sign_rect.width + arrow_spacing
if set_speed_rounded < limit_rounded:
arrow_y = sign_rect.y + (sign_rect.height - self._arrow_up.height) / 2 + bounce_offset
rl.draw_texture(self._arrow_up, int(arrow_x), int(arrow_y), rl.WHITE)
elif set_speed_rounded > limit_rounded:
arrow_y = sign_rect.y + (sign_rect.height - self._arrow_down.height) / 2 - bounce_offset
rl.draw_texture(self._arrow_down, int(arrow_x), int(arrow_y), rl.WHITE)
icon_alpha = max(0.0, min(self._pre_active_alpha_filter.x * 255.0, 255.0))
if icon_alpha > 0:
color = rl.Color(255, 255, 255, int(icon_alpha))
if set_speed_rounded < limit_rounded:
arrow_y = sign_rect.y + (sign_rect.height - self.arrow_up.height) / 2
rl.draw_texture(self.arrow_up, int(arrow_x), int(arrow_y), color)
elif set_speed_rounded > limit_rounded:
arrow_y = sign_rect.y + (sign_rect.height - self.arrow_down.height) / 2
rl.draw_texture(self.arrow_down, int(arrow_x), int(arrow_y), color)
def _render_vienna(self, rect, val, sub, color, has_limit, alpha=1.0):
center = rl.Vector2(rect.x + rect.width / 2, rect.y + rect.height / 2)
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0f4a0bf26cfd2c64939759d43bee839aadfd017a6f74065095a27b03615e55a4
size 26627
oid sha256:ad42ecaeff96a0a6c1a6db67b01e3c0452566906dd3a7f0336a1010ae854d27b
size 60924
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3e451ff31e9b3f144822ab282b8e47cd5a603ca59ff94bd1849271181b86c6b1
size 29220
oid sha256:1fdea39873f60a0c4b216b75792e826f3633091a72ea2abd05740bd6e4e72089
size 63058
+11 -7
View File
@@ -1,3 +1,9 @@
"""
Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors.
This file is part of sunnypilot and is licensed under the MIT License.
See the LICENSE.md file in the root directory for more details.
"""
import cereal.messaging as messaging
from cereal import log, car, custom
from openpilot.common.constants import CV
@@ -34,7 +40,6 @@ def speed_limit_pre_active_alert(CP: car.CarParams, CS: car.CarState, sm: messag
speed_limit_final_last = sm['longitudinalPlanSP'].speedLimit.resolver.speedLimitFinalLast
speed_limit_final_last_conv = round(speed_limit_final_last * speed_conv)
alert_1_str = ""
alert_2_str = ""
alert_size = AlertSize.none
if CP.openpilotLongitudinalControl and CP.pcmCruise:
@@ -44,13 +49,12 @@ def speed_limit_pre_active_alert(CP: car.CarParams, CS: car.CarState, sm: messag
pcm_long_required_max_set_speed_conv = round(pcm_long_required_max * speed_conv)
speed_unit = "km/h" if metric else "mph"
alert_1_str = "Speed Limit Assist: Activation Required"
alert_2_str = f"Manually change set speed to {pcm_long_required_max_set_speed_conv} {speed_unit} to activate"
alert_size = AlertSize.mid
alert_1_str = f"Speed Limit Assist: set to {pcm_long_required_max_set_speed_conv} {speed_unit} to engage"
alert_size = AlertSize.small
return Alert(
alert_1_str,
alert_2_str,
"",
AlertStatus.normal, alert_size,
Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleLow, .1)
@@ -193,7 +197,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventNameSP.speedLimitActive: {
ET.WARNING: Alert(
"Automatically adjusting to the posted speed limit",
"Auto adjusting to speed limit",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleHigh, 5.),
@@ -213,7 +217,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventNameSP.speedLimitPending: {
ET.WARNING: Alert(
"Automatically adjusting to the last speed limit",
"Auto adjusting to last speed limit",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlertSP.promptSingleHigh, 5.),