From e244f4fc9878681514a71c103bb227435861ebbe Mon Sep 17 00:00:00 2001 From: FrogAi <91348155+FrogAi@users.noreply.github.com> Date: Sun, 12 May 2024 18:11:40 -0700 Subject: [PATCH] Visuals - Custom Onroad UI - Pedals Being Pressed Display the brake and gas pedals on the onroad UI below the steering wheel icon. --- selfdrive/car/chrysler/carstate.py | 2 + selfdrive/car/honda/carstate.py | 8 +++ selfdrive/car/hyundai/carstate.py | 4 ++ selfdrive/car/subaru/carstate.py | 3 + selfdrive/car/toyota/carstate.py | 2 + selfdrive/car/volkswagen/carstate.py | 8 +++ .../assets/other_images/brake_pedal.png | Bin 0 -> 16157 bytes .../assets/other_images/gas_pedal.png | Bin 0 -> 30556 bytes selfdrive/ui/qt/onroad.cc | 67 +++++++++++++++++- selfdrive/ui/qt/onroad.h | 22 ++++++ selfdrive/ui/ui.cc | 5 ++ selfdrive/ui/ui.h | 5 ++ 12 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 selfdrive/frogpilot/assets/other_images/brake_pedal.png create mode 100644 selfdrive/frogpilot/assets/other_images/gas_pedal.png diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py index f1d1ee5..953704d 100644 --- a/selfdrive/car/chrysler/carstate.py +++ b/selfdrive/car/chrysler/carstate.py @@ -103,6 +103,8 @@ class CarState(CarStateBase): self.button_counter = cp.vl["CRUISE_BUTTONS"]["COUNTER"] # FrogPilot carstate functions + fp_ret.brakeLights = bool(cp.vl["ESP_1"]["BRAKE_PRESSED_ACC"]) + self.lkas_previously_enabled = self.lkas_enabled if self.CP.carFingerprint in RAM_CARS: self.lkas_enabled = cp.vl["Center_Stack_2"]["LKAS_Button"] or cp.vl["Center_Stack_1"]["LKAS_Button"] diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index 9029f43..790cead 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -274,6 +274,14 @@ class CarState(CarStateBase): ret.rightBlindspot = cp_body.vl["BSM_STATUS_RIGHT"]["BSM_ALERT"] == 1 # FrogPilot carstate functions + brake_light_cars = (CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CRV_5G, CAR.ACCORD, CAR.CIVIC_BOSCH, + CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.ACURA_RDX_3G, CAR.HONDA_E) + + if self.CP.carFingerprint in brake_light_cars: + fp_ret.brakeLights = bool(cp.vl["ACC_CONTROL"]['BRAKE_LIGHTS'] != 0 or ret.brake > 0.4) if not self.CP.openpilotLongitudinalControl else bool(ret.brake > 0.4) + elif self.CP.carFingerprint in HONDA_BOSCH and self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS: + fp_ret.brakeLights = bool(cp.vl["ACC_CONTROL"]['BRAKE_LIGHTS'] != 0 or ret.brake > 0.4) if not self.CP.openpilotLongitudinalControl else bool(ret.brake > 0.4) + self.prev_distance_button = self.distance_button self.distance_button = self.cruise_setting == 3 diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py index ff282a8..17a80bf 100644 --- a/selfdrive/car/hyundai/carstate.py +++ b/selfdrive/car/hyundai/carstate.py @@ -186,6 +186,8 @@ class CarState(CarStateBase): self.main_enabled = not self.main_enabled # FrogPilot carstate functions + fp_ret.brakeLights = bool(cp.vl["TCS13"]["BrakeLight"]) + fp_ret.dashboardSpeedLimit = self.calculate_speed_limit(cp, cp_cam) * speed_conv self.prev_distance_button = self.distance_button @@ -282,6 +284,8 @@ class CarState(CarStateBase): else cp_cam.vl["CAM_0x2a4"]) # FrogPilot carstate functions + fp_ret.brakeLights = cp.vl["TCS"]["DriverBraking"] == 1 + fp_ret.dashboardSpeedLimit = self.calculate_speed_limit(cp, cp_cam) * speed_factor self.prev_distance_button = self.distance_button diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py index 8ce62dd..28f75ff 100644 --- a/selfdrive/car/subaru/carstate.py +++ b/selfdrive/car/subaru/carstate.py @@ -128,8 +128,11 @@ class CarState(CarStateBase): # FrogPilot carstate functions if self.car_fingerprint not in PREGLOBAL_CARS: + fp_ret.brakeLights = bool(cp_cam.vl["ES_DashStatus"]["Brake_Lights"]) self.lkas_previously_enabled = self.lkas_enabled self.lkas_enabled = cp_cam.vl["ES_LKAS_State"]["LKAS_Dash_State"] + else: + fp_ret.brakeLights = bool(cp_cam.vl["ES_Brake"]["Cruise_Brake_Lights"]) return ret, fp_ret diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py index 99d9e1e..c7843e2 100644 --- a/selfdrive/car/toyota/carstate.py +++ b/selfdrive/car/toyota/carstate.py @@ -208,6 +208,8 @@ class CarState(CarStateBase): self.distance_button = cp.vl["SDSU"]["FD_BUTTON"] # FrogPilot carstate functions + fp_ret.brakeLights = bool(cp.vl["ESP_CONTROL"]["BRAKE_LIGHTS_ACC"]) + self.cruise_decreased_previously = self.cruise_decreased self.cruise_increased_previously = self.cruise_increased diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py index f42eb86..4bea1aa 100644 --- a/selfdrive/car/volkswagen/carstate.py +++ b/selfdrive/car/volkswagen/carstate.py @@ -151,6 +151,10 @@ class CarState(CarStateBase): self.upscale_lead_car_signal = bool(pt_cp.vl["Kombi_03"]["KBI_Variante"]) self.frame += 1 + + # FrogPilot carstate functions + fp_ret.brakeLights = bool(pt_cp.vl["ESP_05"]['ESP_Status_Bremsdruck']) + return ret, fp_ret def update_pq(self, pt_cp, cam_cp, ext_cp, trans_type, frogpilot_variables): @@ -251,6 +255,10 @@ class CarState(CarStateBase): ret.espDisabled = bool(pt_cp.vl["Bremse_1"]["ESP_Passiv_getastet"]) self.frame += 1 + + # FrogPilot carstate functions + fp_ret.brakeLights = bool(pt_cp.vl["Motor_2"]['Bremstestschalter']) + return ret, fp_ret def update_hca_state(self, hca_status): diff --git a/selfdrive/frogpilot/assets/other_images/brake_pedal.png b/selfdrive/frogpilot/assets/other_images/brake_pedal.png new file mode 100644 index 0000000000000000000000000000000000000000..f4fe0ef461a6c1c7a7a7bc7401c63ed2fe0400e6 GIT binary patch literal 16157 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%0AE>gXH!E|eD&GNU1o5X)f+ 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 c-?wisetMargin(UI_BORDER_SIZE); main_layout->setSpacing(0); + QHBoxLayout *buttons_layout = new QHBoxLayout(); + buttons_layout->setSpacing(0); + experimental_btn = new ExperimentalButton(this); - main_layout->addWidget(experimental_btn, 0, Qt::AlignTop | Qt::AlignRight); + buttons_layout->addWidget(experimental_btn); + + QVBoxLayout *top_right_layout = new QVBoxLayout(); + top_right_layout->setSpacing(0); + top_right_layout->addLayout(buttons_layout); + + pedal_icons = new PedalIcons(this); + top_right_layout->addWidget(pedal_icons, 0, Qt::AlignRight); + + main_layout->addLayout(top_right_layout, 0); + main_layout->setAlignment(top_right_layout, Qt::AlignTop | Qt::AlignRight); map_settings_btn = new MapSettingsButton(this); main_layout->addWidget(map_settings_btn, 0, Qt::AlignBottom | Qt::AlignRight); @@ -970,6 +983,12 @@ void AnnotatedCameraWidget::paintFrogPilotWidgets(QPainter &p) { bottom_layout->setAlignment(distance_btn, (rightHandDM ? Qt::AlignRight : Qt::AlignLeft)); } + bool enablePedalIcons = scene.pedals_on_ui && !bigMapOpen; + pedal_icons->setVisible(enablePedalIcons); + if (enablePedalIcons) { + pedal_icons->updateState(); + } + map_settings_btn_bottom->setEnabled(map_settings_btn->isEnabled()); if (map_settings_btn_bottom->isEnabled()) { map_settings_btn_bottom->setVisible(!hideBottomIcons && !compass); @@ -1153,6 +1172,52 @@ void DistanceButton::paintEvent(QPaintEvent *event) { } } +PedalIcons::PedalIcons(QWidget *parent) : QWidget(parent), scene(uiState()->scene) { + setFixedSize(btn_size, btn_size); + + brake_pedal_img = loadPixmap("../frogpilot/assets/other_images/brake_pedal.png", QSize(img_size, img_size)); + gas_pedal_img = loadPixmap("../frogpilot/assets/other_images/gas_pedal.png", QSize(img_size, img_size)); +} + +void PedalIcons::updateState() { + acceleration = scene.acceleration; + + accelerating = acceleration > 0.25; + decelerating = acceleration < -0.25; + + if (accelerating || decelerating) { + update(); + } +} + +void PedalIcons::paintEvent(QPaintEvent *event) { + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing); + + int totalWidth = 2 * img_size; + int startX = (width() - totalWidth) / 2; + + int brakeX = startX + img_size / 2; + int gasX = startX + img_size; + + float brakeOpacity = 1.0f; + float gasOpacity = 1.0f; + + if (scene.dynamic_pedals_on_ui) { + brakeOpacity = scene.standstill ? 1.0f : decelerating ? std::max(0.25f, std::abs(acceleration)) : 0.25f; + gasOpacity = accelerating ? std::max(0.25f, acceleration) : 0.25f; + } else if (scene.static_pedals_on_ui) { + brakeOpacity = scene.standstill || scene.brake_lights_on || acceleration < -0.5 ? 1.0f : 0.25f; + gasOpacity = !scene.standstill && acceleration > 0 ? 1.0f : 0.25f; + } + + p.setOpacity(brakeOpacity); + p.drawPixmap(brakeX, (height() - img_size) / 2, brake_pedal_img); + + p.setOpacity(gasOpacity); + p.drawPixmap(gasX, (height() - img_size) / 2, gas_pedal_img); +} + void AnnotatedCameraWidget::drawSLCConfirmation(QPainter &p) { p.save(); diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h index f20d34f..6c83430 100644 --- a/selfdrive/ui/qt/onroad.h +++ b/selfdrive/ui/qt/onroad.h @@ -119,6 +119,27 @@ private: QPixmap settings_img; }; +class PedalIcons : public QWidget { + Q_OBJECT + +public: + explicit PedalIcons(QWidget *parent = 0); + void updateState(); + +private: + void paintEvent(QPaintEvent *event) override; + + QPixmap brake_pedal_img; + QPixmap gas_pedal_img; + + UIScene &scene; + + bool accelerating; + bool decelerating; + + float acceleration; +}; + // container window for the NVG UI class AnnotatedCameraWidget : public CameraWidget { Q_OBJECT @@ -169,6 +190,7 @@ private: Compass *compass_img; DistanceButton *distance_btn; + PedalIcons *pedal_icons; QHBoxLayout *bottom_layout; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 1008b60..76105f1 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -223,6 +223,7 @@ static void update_state(UIState *s) { scene.blind_spot_left = carState.getLeftBlindspot(); scene.blind_spot_right = carState.getRightBlindspot(); scene.parked = carState.getGearShifter() == cereal::CarState::GearShifter::PARK; + scene.standstill = carState.getStandstill(); } if (sm.updated("controlsState")) { auto controlsState = sm["controlsState"].getControlsState(); @@ -242,6 +243,7 @@ static void update_state(UIState *s) { } if (sm.updated("frogpilotCarState")) { auto frogpilotCarState = sm["frogpilotCarState"].getFrogpilotCarState(); + scene.brake_lights_on = frogpilotCarState.getBrakeLights(); } if (sm.updated("frogpilotPlan")) { auto frogpilotPlan = sm["frogpilotPlan"].getFrogpilotPlan(); @@ -304,6 +306,9 @@ void ui_update_frogpilot_params(UIState *s) { scene.adjacent_path_metrics = scene.adjacent_path && params.getBool("AdjacentPathMetrics"); scene.blind_spot_path = custom_paths && params.getBool("BlindSpotPath"); scene.compass = custom_onroad_ui && params.getBool("Compass"); + scene.pedals_on_ui = custom_onroad_ui && params.getBool("PedalsOnUI"); + scene.dynamic_pedals_on_ui = scene.pedals_on_ui && params.getBool("DynamicPedalsOnUI"); + scene.static_pedals_on_ui = scene.pedals_on_ui && params.getBool("StaticPedalsOnUI"); scene.disable_smoothing_mtsc = params.getBool("MTSCEnabled") && params.getBool("DisableMTSCSmoothing"); scene.disable_smoothing_vtsc = params.getBool("VisionTurnControl") && params.getBool("DisableVTSCSmoothing"); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 8757d55..4fb458b 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -193,10 +193,12 @@ typedef struct UIScene { bool blind_spot_left; bool blind_spot_path; bool blind_spot_right; + bool brake_lights_on; bool compass; bool conditional_experimental; bool disable_smoothing_mtsc; bool disable_smoothing_vtsc; + bool dynamic_pedals_on_ui; bool enabled; bool experimental_mode; bool experimental_mode_via_screen; @@ -204,6 +206,7 @@ typedef struct UIScene { bool online; bool onroad_distance_button; bool parked; + bool pedals_on_ui; bool reverse_cruise; bool reverse_cruise_ui; bool right_hand_drive; @@ -214,6 +217,8 @@ typedef struct UIScene { bool speed_limit_changed; bool speed_limit_controller; bool speed_limit_overridden; + bool standstill; + bool static_pedals_on_ui; bool tethering_enabled; bool traffic_mode; bool traffic_mode_active;