From 94f93a9f266e6a51d6a79ac092cefd2f7b0b6551 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Tue, 16 Sep 2025 10:05:34 +0200 Subject: [PATCH] ui: Add standstill timer to HUD (#1251) * Add standstill timer to HUD - Introduced a timer displaying elapsed time when the car is at a standstill. - Added settings toggle to enable/disable this feature. - Updated UI elements and related logic to support the standstill timer. * ruff be happy * stop screaming * c stands for not cereal * slight cleanup * a bit more cleanup * unused --------- Co-authored-by: nayan Co-authored-by: Jason Wen --- common/params_keys.h | 1 + .../qt/offroad/settings/visuals_panel.cc | 7 ++++ selfdrive/ui/sunnypilot/qt/onroad/hud.cc | 42 +++++++++++++++++++ selfdrive/ui/sunnypilot/qt/onroad/hud.h | 4 ++ selfdrive/ui/sunnypilot/ui.cc | 2 + selfdrive/ui/sunnypilot/ui_scene.h | 1 + 6 files changed, 57 insertions(+) diff --git a/common/params_keys.h b/common/params_keys.h index 011a3161f..44d25ec41 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -159,6 +159,7 @@ inline static std::unordered_map keys = { {"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}}, {"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}}, {"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}}, // MADS params {"Mads", {PERSISTENT | BACKUP, BOOL, "1"}}, diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc index c3aaf12d2..e19760f2e 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc @@ -35,6 +35,13 @@ VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) { "../assets/offroad/icon_monitoring.png", false, }, + { + "StandstillTimer", + tr("Enable Standstill Timer"), + tr("Show a timer on the HUD when the car is at a standstill."), + "../assets/offroad/icon_monitoring.png", + false, + }, }; // Add regular toggles first diff --git a/selfdrive/ui/sunnypilot/qt/onroad/hud.cc b/selfdrive/ui/sunnypilot/qt/onroad/hud.cc index 9ead933d0..291a669ac 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/hud.cc +++ b/selfdrive/ui/sunnypilot/qt/onroad/hud.cc @@ -75,6 +75,9 @@ void HudRendererSP::updateState(const UIState &s) { latAccelFactorFiltered = ltp.getLatAccelFactorFiltered(); frictionCoefficientFiltered = ltp.getFrictionCoefficientFiltered(); liveValid = ltp.getLiveValid(); + + standstillTimer = s.scene.standstill_timer; + isStandstill = car_state.getStandstill(); } void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) { @@ -94,6 +97,11 @@ void HudRendererSP::draw(QPainter &p, const QRect &surface_rect) { QRect rect_right(surface_rect.right() - (UI_BORDER_SIZE * 2), UI_BORDER_SIZE * 1.5, 184, 170); drawRightDevUI(p, surface_rect.right() - 184 - UI_BORDER_SIZE * 2, UI_BORDER_SIZE * 2 + rect_right.height()); } + + // Standstill Timer + if (standstillTimer) { + drawStandstillTimer(p, surface_rect.right() / 12 * 10, surface_rect.bottom() / 12 * 1.53); + } } } @@ -206,3 +214,37 @@ void HudRendererSP::drawBottomDevUI(QPainter &p, int x, int y) { UiElement altitudeElement = DeveloperUi::getAltitude(gpsAccuracy, altitude); rw += drawBottomDevUIElement(p, rw, y, altitudeElement.value, altitudeElement.label, altitudeElement.units, altitudeElement.color); } + +void HudRendererSP::drawStandstillTimer(QPainter &p, int x, int y) { + if (isStandstill) { + standstillElapsedTime += 1.0 / UI_FREQ; + + int minute = static_cast(standstillElapsedTime / 60); + int second = static_cast(standstillElapsedTime - (minute * 60)); + + // stop sign for standstill timer + const int size = 190; // size + const float angle = M_PI / 8.0; + + QPolygon octagon; + for (int i = 0; i < 8; i++) { + float curr_angle = angle + i * M_PI / 4.0; + int point_x = x + size / 2 * cos(curr_angle); + int point_y = y + size / 2 * sin(curr_angle); + octagon << QPoint(point_x, point_y); + } + + p.setPen(QPen(Qt::white, 6)); + p.setBrush(QColor(255, 90, 81, 200)); // red pastel + p.drawPolygon(octagon); + + QString time_str = QString("%1:%2").arg(minute, 1, 10, QChar('0')).arg(second, 2, 10, QChar('0')); + p.setFont(InterFont(55, QFont::Bold)); + p.setPen(Qt::white); + QRect timerTextRect = p.fontMetrics().boundingRect(QString(time_str)); + timerTextRect.moveCenter({x, y}); + p.drawText(timerTextRect, Qt::AlignCenter, QString(time_str)); + } else { + standstillElapsedTime = 0.0; + } +} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/hud.h b/selfdrive/ui/sunnypilot/qt/onroad/hud.h index 968789bc1..75fc520fc 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/hud.h +++ b/selfdrive/ui/sunnypilot/qt/onroad/hud.h @@ -25,6 +25,7 @@ private: int drawRightDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color); int drawBottomDevUIElement(QPainter &p, int x, int y, const QString &value, const QString &label, const QString &units, QColor &color); void drawBottomDevUI(QPainter &p, int x, int y); + void drawStandstillTimer(QPainter &p, int x, int y); bool lead_status; float lead_d_rel; @@ -53,4 +54,7 @@ private: bool reversing; cereal::CarParams::SteerControlType steerControlType; cereal::CarControl::Actuators::Reader actuators; + bool standstillTimer; + bool isStandstill; + float standstillElapsedTime; }; diff --git a/selfdrive/ui/sunnypilot/ui.cc b/selfdrive/ui/sunnypilot/ui.cc index 1277195df..7b10929bc 100644 --- a/selfdrive/ui/sunnypilot/ui.cc +++ b/selfdrive/ui/sunnypilot/ui.cc @@ -34,6 +34,7 @@ UIStateSP::UIStateSP(QObject *parent) : UIState(parent) { ui_update_params_sp(this); }); param_watcher->addParam("DevUIInfo"); + param_watcher->addParam("StandstillTimer"); } // This method overrides completely the update method from the parent class intentionally. @@ -51,6 +52,7 @@ void UIStateSP::update() { void ui_update_params_sp(UIStateSP *s) { auto params = Params(); s->scene.dev_ui_info = std::atoi(params.get("DevUIInfo").c_str()); + s->scene.standstill_timer = params.getBool("StandstillTimer"); } DeviceSP::DeviceSP(QObject *parent) : Device(parent) { diff --git a/selfdrive/ui/sunnypilot/ui_scene.h b/selfdrive/ui/sunnypilot/ui_scene.h index 93e0cd6c9..c941be675 100644 --- a/selfdrive/ui/sunnypilot/ui_scene.h +++ b/selfdrive/ui/sunnypilot/ui_scene.h @@ -9,4 +9,5 @@ typedef struct UISceneSP : UIScene { int dev_ui_info = 0; + bool standstill_timer = false; } UISceneSP;