diff --git a/common/params.cc b/common/params.cc index 84120e5..e6b2f53 100644 --- a/common/params.cc +++ b/common/params.cc @@ -340,6 +340,7 @@ std::unordered_map keys = { {"RoadEdgesWidth", PERSISTENT}, {"RoadName", PERSISTENT}, {"RoadNameUI", PERSISTENT}, + {"RotatingWheel", PERSISTENT}, {"SchedulePending", PERSISTENT}, {"SearchInput", PERSISTENT}, {"SilentMode", PERSISTENT}, diff --git a/selfdrive/frogpilot/assets/toggle_icons/icon_rotate.png b/selfdrive/frogpilot/assets/toggle_icons/icon_rotate.png new file mode 100644 index 0000000..1503308 Binary files /dev/null and b/selfdrive/frogpilot/assets/toggle_icons/icon_rotate.png differ diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc index b2af00f..724d0f4 100644 --- a/selfdrive/ui/qt/onroad.cc +++ b/selfdrive/ui/qt/onroad.cc @@ -29,6 +29,21 @@ static void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, cons p.setOpacity(1.0); } +static void drawIconRotate(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrush &bg, float opacity, const int angle) { + p.setRenderHint(QPainter::Antialiasing); + p.setOpacity(1.0); // bg dictates opacity of ellipse + p.setPen(Qt::NoPen); + p.setBrush(bg); + p.drawEllipse(center, btn_size / 2, btn_size / 2); + p.save(); + p.translate(center); + p.rotate(-angle); + p.setOpacity(opacity); + p.drawPixmap(-QPoint(img.width() / 2, img.height() / 2), img); + p.setOpacity(1.0); + p.restore(); +} + OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent), scene(uiState()->scene) { QVBoxLayout *main_layout = new QVBoxLayout(this); main_layout->setMargin(UI_BORDER_SIZE); @@ -363,7 +378,15 @@ void ExperimentalButton::updateState(const UIState &s, bool leadInfo) { } // FrogPilot variables + rotatingWheel = scene.rotating_wheel; + y_offset = leadInfo ? 10 : 0; + + // Update the icon so the steering wheel rotates in real time + if (rotatingWheel && steeringAngleDeg != scene.steering_angle_deg) { + steeringAngleDeg = scene.steering_angle_deg; + update(); + } } void ExperimentalButton::paintEvent(QPaintEvent *event) { @@ -371,7 +394,11 @@ void ExperimentalButton::paintEvent(QPaintEvent *event) { QPixmap img = experimental_mode ? experimental_img : engage_img; if (!(scene.show_driver_camera || scene.map_open && scene.full_map)) { - drawIcon(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, QColor(0, 0, 0, 166), (isDown() || !(engageable || scene.always_on_lateral_active)) ? 0.6 : 1.0); + if (rotatingWheel) { + drawIconRotate(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, QColor(0, 0, 0, 166), (isDown() || !(engageable || scene.always_on_lateral_active)) ? 0.6 : 1.0, steeringAngleDeg); + } else { + drawIcon(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, QColor(0, 0, 0, 166), (isDown() || !(engageable || scene.always_on_lateral_active)) ? 0.6 : 1.0); + } } } diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index e56be95..b293cdb 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -77,6 +77,8 @@ private: // FrogPilot variables UIScene &scene; + bool rotatingWheel; + int steeringAngleDeg; int y_offset; }; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 6c71546..71c4c06 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -237,6 +237,9 @@ static void update_state(UIState *s) { if (scene.pedals_on_ui) { scene.standstill = carState.getStandstill(); } + if (scene.rotating_wheel) { + scene.steering_angle_deg = carState.getSteeringAngleDeg(); + } } if (sm.updated("controlsState")) { auto controlsState = sm["controlsState"].getControlsState(); @@ -346,6 +349,8 @@ void ui_update_frogpilot_params(UIState *s) { scene.full_map = quality_of_life_visuals && params.getBool("FullMap"); scene.hide_speed = quality_of_life_visuals && params.getBool("HideSpeed"); scene.hide_speed_ui = scene.hide_speed && params.getBool("HideSpeedUI"); + + scene.rotating_wheel = params.getBool("RotatingWheel"); } void UIState::updateStatus() { diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 8d29556..1868771 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -205,6 +205,7 @@ typedef struct UIScene { bool reverse_cruise; bool reverse_cruise_ui; bool road_name_ui; + bool rotating_wheel; bool show_driver_camera; bool standstill; bool tethering_enabled; @@ -234,6 +235,7 @@ typedef struct UIScene { int desired_follow; int obstacle_distance; int obstacle_distance_stock; + int steering_angle_deg; int stopped_equivalence; QPolygonF track_adjacent_vertices[6];