diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 65d2f5588e..e8f1b7eb8b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,11 @@ * @sunnypilot/dev-internal /.github/ @devtekve @sunnyhaibin -/release/ci/ @devtekve @sunnyhaibin \ No newline at end of file +/release/ci/ @devtekve @sunnyhaibin +/tinygrad_repo @devtekve @Discountchubbs +/tinygrad/ @devtekve @Discountchubbs +/selfdrive/controls/lib/longitudinal_planner.py @devtekve @Discountchubbs +/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py @devtekve @Discountchubbs +/selfdrive/modeld/ @devtekve @Discountchubbs +/sunnypilot/model* @devtekve @Discountchubbs +/sunnypilot/sunnylink/ @devtekve +/system/athena/ @devtekve \ No newline at end of file diff --git a/common/params_keys.h b/common/params_keys.h index 1b4c6953c0..e411398455 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -71,7 +71,7 @@ inline static std::unordered_map keys = { {"LastPowerDropDetected", CLEAR_ON_MANAGER_START}, {"LastUpdateException", CLEAR_ON_MANAGER_START}, {"LastUpdateTime", PERSISTENT}, - {"LiveDelay", PERSISTENT}, + {"LiveDelay", PERSISTENT | BACKUP}, {"LiveParameters", PERSISTENT}, {"LiveParametersV2", PERSISTENT}, {"LiveTorqueParameters", PERSISTENT | DONT_LOG}, @@ -133,6 +133,7 @@ inline static std::unordered_map keys = { {"CarPlatformBundle", PERSISTENT}, {"EnableGithubRunner", PERSISTENT | BACKUP}, {"MaxTimeOffroad", PERSISTENT | BACKUP}, + {"Brightness", PERSISTENT | BACKUP}, {"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION}, {"OffroadMode", CLEAR_ON_MANAGER_START}, {"OffroadMode_Status", CLEAR_ON_MANAGER_START}, @@ -170,6 +171,10 @@ inline static std::unordered_map keys = { {"HyundaiLongitudinalTuning", PERSISTENT}, {"DynamicExperimentalControl", PERSISTENT}, + {"BlindSpot", PERSISTENT | BACKUP}, + + // model panel params + {"LagdToggle", PERSISTENT | BACKUP}, // mapd {"MapdVersion", PERSISTENT}, diff --git a/opendbc_repo b/opendbc_repo index 68d6cbddbf..bd447a9cec 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit 68d6cbddbf47fe3071fade55b5075f67674bb3b3 +Subproject commit bd447a9cecd999a8dbc8fc51712c81a532bd14d5 diff --git a/selfdrive/ui/sunnypilot/SConscript b/selfdrive/ui/sunnypilot/SConscript index 4be9d33653..de7f3efbc5 100644 --- a/selfdrive/ui/sunnypilot/SConscript +++ b/selfdrive/ui/sunnypilot/SConscript @@ -24,6 +24,7 @@ qt_src = [ "sunnypilot/qt/offroad/settings/lateral_panel.cc", "sunnypilot/qt/offroad/settings/longitudinal_panel.cc", "sunnypilot/qt/offroad/settings/max_time_offroad.cc", + "sunnypilot/qt/offroad/settings/brightness.cc", "sunnypilot/qt/offroad/settings/models_panel.cc", "sunnypilot/qt/offroad/settings/osm_panel.cc", "sunnypilot/qt/offroad/settings/settings.cc", diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc new file mode 100644 index 0000000000..ffd3ce1d8b --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.cc @@ -0,0 +1,50 @@ +/** + * 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. + */ + +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h" + +// Map of Brightness Options +const QMap Brightness::brightness_options = { + {"0", "1"}, // Auto (Dark) + {"1", "0"}, // Auto + {"2", "10"}, + {"3", "20"}, + {"4", "30"}, + {"5", "40"}, + {"6", "50"}, + {"7", "60"}, + {"8", "70"}, + {"9", "80"}, + {"10", "90"}, + {"11", "100"} +}; + +Brightness::Brightness() : OptionControlSP( + "Brightness", + tr("Brightness"), + tr("Overrides the brightness of the device."), + "../assets/offroad/icon_blank.png", + {0, 11}, 1, true, &brightness_options) { + + refresh(); +} + +void Brightness::refresh() { + const int brightness = QString::fromStdString(params.get("Brightness")).toInt(); + + QString label; + if (brightness == 1) { + label = tr("Auto (Dark)"); + } else if (brightness == 0) { + label = tr("Auto"); + } else { + const int value = brightness; + label = QString("%1").arg(value); + } + + setLabel(label); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h new file mode 100644 index 0000000000..20d0a291d9 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h @@ -0,0 +1,25 @@ +/** + * 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. + */ + +#pragma once + +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +class Brightness : public OptionControlSP { + Q_OBJECT + +public: + static const QMap brightness_options; + + Brightness(); + void refresh(); + +private: + Params params; +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc index e6855c4b4e..a2c7414460 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.cc @@ -80,6 +80,11 @@ DevicePanelSP::DevicePanelSP(SettingsWindowSP *parent) : DevicePanel(parent) { connect(maxTimeOffroad, &OptionControlSP::updateLabels, maxTimeOffroad, &MaxTimeOffroad::refresh); addItem(maxTimeOffroad); + // Brightness + brightness = new Brightness(); + connect(brightness, &OptionControlSP::updateLabels, brightness, &Brightness::refresh); + addItem(brightness); + addItem(device_grid_layout); // offroad mode and power buttons diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h index 7b7412a739..e83801dd29 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/device_panel.h @@ -8,6 +8,7 @@ #pragma once #include "selfdrive/ui/sunnypilot/qt/offroad/settings/max_time_offroad.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/brightness.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" #include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" @@ -25,6 +26,7 @@ private: std::map buttons; PushButtonSP *offroadBtn; MaxTimeOffroad *maxTimeOffroad; + Brightness *brightness; const QString alwaysOffroadStyle = R"( PushButtonSP { diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc index d33cb550ce..2d7367de1c 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc @@ -24,13 +24,30 @@ ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) { currentModelLblBtn = new ButtonControlSP(tr("Current Model"), tr("SELECT"), current_model); currentModelLblBtn->setValue(current_model); - connect(currentModelLblBtn, &ButtonControlSP::clicked, this, &ModelsPanel::handleCurrentModelLblBtnClicked); + connect(currentModelLblBtn, &ButtonControlSP::clicked, [=]() { + + InputDialog d(tr("Search Model"), this, tr("Enter search keywords, or leave blank to list all models."), false); + d.setMinLength(0); + const int ret = d.exec(); + if (ret) { + handleCurrentModelLblBtnClicked(d.text()); + } + + }); + connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { is_onroad = !offroad; updateLabels(); }); connect(uiStateSP(), &UIStateSP::uiUpdate, this, &ModelsPanel::updateLabels); list->addItem(currentModelLblBtn); + + // LiveDelay toggle + list->addItem(new ParamControlSP("LagdToggle", + tr("Live Learning Steer Delay"), + tr("Enable this for the car to learn and adapt its steering response time. " + "Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience."), + "../assets/offroad/icon_shell.png")); } @@ -127,7 +144,7 @@ void ModelsPanel::updateModelManagerState() { * @brief Handles the model bundle selection button click * Displays available bundles, allows selection, and initiates download */ -void ModelsPanel::handleCurrentModelLblBtnClicked() { +void ModelsPanel::handleCurrentModelLblBtnClicked(const QString &query) { currentModelLblBtn->setEnabled(false); currentModelLblBtn->setValue(tr("Fetching models...")); @@ -135,13 +152,14 @@ void ModelsPanel::handleCurrentModelLblBtnClicked() { QMap index_to_bundle; const auto bundles = model_manager.getAvailableBundles(); for (const auto &bundle: bundles) { - index_to_bundle.insert(bundle.getIndex(), QString::fromStdString(bundle.getDisplayName())); + std::string bundleStr = std::string(bundle.getDisplayName()) + " $SNAME$ " + std::string(bundle.getInternalName()); + index_to_bundle.insert(bundle.getIndex(), QString::fromStdString(bundleStr)); } // Sort bundles by index in descending order QStringList bundleNames; // Add "Default" as the first option - bundleNames.append(tr("Use Default")); + bundleNames.append(DEFAULT_MODEL); auto indices = index_to_bundle.keys(); std::sort(indices.begin(), indices.end(), std::greater()); @@ -149,17 +167,31 @@ void ModelsPanel::handleCurrentModelLblBtnClicked() { bundleNames.append(index_to_bundle[index]); } + QStringList filteredBundleNames = searchFromList(query, bundleNames); + currentModelLblBtn->setValue(GetActiveModelName()); + if (filteredBundleNames.isEmpty()) { + ConfirmationDialog::alert(tr("No model found for keywords: %1").arg(query), this); + return; + } + + for (const QString &bundleName: filteredBundleNames) { + int index = bundleName.indexOf("$SNAME$"); + if (index != -1) { + filteredBundleNames.replace(filteredBundleNames.indexOf(bundleName), bundleName.left(index).trimmed()); + } + } + const QString selectedBundleName = MultiOptionDialog::getSelection( - tr("Select a Model"), bundleNames, GetActiveModelName(), this); + tr("Select a Model"), filteredBundleNames, GetActiveModelName(), this); if (selectedBundleName.isEmpty() || !canContinueOnMeteredDialog()) { return; } // Handle "Stock" selection differently - if (selectedBundleName == tr("Use Default")) { + if (selectedBundleName == DEFAULT_MODEL) { params.remove("ModelManager_ActiveBundle"); currentModelLblBtn->setValue(tr("Default")); showResetParamsDialog(); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h index 4ba526651e..ee6a74a666 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.h @@ -7,6 +7,7 @@ #pragma once +#include "selfdrive/ui/sunnypilot/qt/util.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" class ModelsPanel : public QWidget { @@ -30,7 +31,7 @@ private: // UI update related methods void updateLabels(); - void handleCurrentModelLblBtnClicked(); + void handleCurrentModelLblBtnClicked(const QString &query); void handleBundleDownloadProgress(); void showResetParamsDialog(); cereal::ModelManagerSP::Reader model_manager; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc index cf9729be18..0d42bd74f4 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.cc @@ -8,5 +8,63 @@ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h" VisualsPanel::VisualsPanel(QWidget *parent) : QWidget(parent) { + param_watcher = new ParamWatcher(this); + connect(param_watcher, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { + paramsRefresh(); + }); + + main_layout = new QStackedLayout(this); + ListWidgetSP *list = new ListWidgetSP(this, false); + sunnypilotScreen = new QWidget(this); + QVBoxLayout* vlayout = new QVBoxLayout(sunnypilotScreen); + vlayout->setContentsMargins(50, 20, 50, 20); + + std::vector > toggle_defs{ + { + "BlindSpot", + tr("Show Blind Spot Warnings"), + tr("Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported."), + "../assets/offroad/icon_monitoring.png", + false, + }, + }; + + for (auto &[param, title, desc, icon, needs_restart] : toggle_defs) { + auto toggle = new ParamControlSP(param, title, desc, icon, this); + + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + + if (needs_restart && !locked) { + toggle->setDescription(toggle->getDescription() + tr(" Changing this setting will restart openpilot if the car is powered on.")); + + QObject::connect(uiState(), &UIState::engagedChanged, [toggle](bool engaged) { + toggle->setEnabled(!engaged); + }); + + QObject::connect(toggle, &ParamControlSP::toggleFlipped, [=](bool state) { + params.putBool("OnroadCycleRequested", true); + }); + } + + list->addItem(toggle); + toggles[param.toStdString()] = toggle; + param_watcher->addParam(param); + } + + sunnypilotScroller = new ScrollViewSP(list, this); + vlayout->addWidget(sunnypilotScroller); + + main_layout->addWidget(sunnypilotScreen); +} + +void VisualsPanel::paramsRefresh() { + if (!isVisible()) { + return; + } + + for (auto toggle : toggles) { + toggle.second->refresh(); + } } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h index 9f58104c4e..42e0688957 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/visuals_panel.h @@ -8,6 +8,9 @@ #pragma once #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +class ScrollViewSP; class VisualsPanel : public QWidget { Q_OBJECT @@ -15,4 +18,13 @@ class VisualsPanel : public QWidget { public: explicit VisualsPanel(QWidget *parent = nullptr); + void paramsRefresh(); + +protected: + QStackedLayout* main_layout = nullptr; + QWidget* sunnypilotScreen = nullptr; + ScrollViewSP *sunnypilotScroller = nullptr; + Params params; + std::map toggles; + ParamWatcher * param_watcher; }; diff --git a/selfdrive/ui/sunnypilot/qt/onroad/model.cc b/selfdrive/ui/sunnypilot/qt/onroad/model.cc index 617b64f58e..af0177c344 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/model.cc +++ b/selfdrive/ui/sunnypilot/qt/onroad/model.cc @@ -6,3 +6,47 @@ */ #include "selfdrive/ui/sunnypilot/qt/onroad/model.h" + + +void ModelRendererSP::update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) { + ModelRenderer::update_model(model, lead); + const auto &model_position = model.getPosition(); + const auto &lane_lines = model.getLaneLines(); + float max_distance = std::clamp(*(model_position.getX().end() - 1), MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); + int max_idx = get_path_length_idx(lane_lines[0], max_distance); + // update blindspot vertices + float max_distance_barrier = 100; + int max_idx_barrier = std::min(max_idx, get_path_length_idx(lane_lines[0], max_distance_barrier)); + mapLineToPolygon(model.getLaneLines()[1], 0.2, -0.05, &left_blindspot_vertices, max_idx_barrier); + mapLineToPolygon(model.getLaneLines()[2], 0.2, -0.05, &right_blindspot_vertices, max_idx_barrier); +} + +void ModelRendererSP::drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, const QRect &surface_rect) { + auto *s = uiState(); + auto &sm = *(s->sm); + bool blindspot = Params().getBool("BlindSpot"); + + if (blindspot) { + bool left_blindspot = sm["carState"].getCarState().getLeftBlindspot(); + bool right_blindspot = sm["carState"].getCarState().getRightBlindspot(); + + //painter.setBrush(QColor::fromRgbF(1.0, 0.0, 0.0, 0.4)); // Red with alpha for blind spot + + if (left_blindspot && !left_blindspot_vertices.isEmpty()) { + QLinearGradient gradient(0, 0, surface_rect.width(), 0); // Horizontal gradient from left to right + gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha + gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha + painter.setBrush(gradient); + painter.drawPolygon(left_blindspot_vertices); + } + + if (right_blindspot && !right_blindspot_vertices.isEmpty()) { + QLinearGradient gradient(surface_rect.width(), 0, 0, 0); // Horizontal gradient from right to left + gradient.setColorAt(0.0, QColor(255, 165, 0, 102)); // Orange with alpha + gradient.setColorAt(1.0, QColor(255, 255, 0, 102)); // Yellow with alpha + painter.setBrush(gradient); + painter.drawPolygon(right_blindspot_vertices); + } + } + ModelRenderer::drawPath(painter, model, surface_rect.height()); +} diff --git a/selfdrive/ui/sunnypilot/qt/onroad/model.h b/selfdrive/ui/sunnypilot/qt/onroad/model.h index 8569e58f66..24404f32f0 100644 --- a/selfdrive/ui/sunnypilot/qt/onroad/model.h +++ b/selfdrive/ui/sunnypilot/qt/onroad/model.h @@ -12,4 +12,11 @@ class ModelRendererSP : public ModelRenderer { public: ModelRendererSP() = default; + +private: + void update_model(const cereal::ModelDataV2::Reader &model, const cereal::RadarState::LeadData::Reader &lead) override; + void drawPath(QPainter &painter, const cereal::ModelDataV2::Reader &model, const QRect &rect) override; + + QPolygonF left_blindspot_vertices; + QPolygonF right_blindspot_vertices; }; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 06208638db..c9dc70cdff 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -80,8 +80,12 @@ void UIState::updateStatus() { status = STATUS_OVERRIDE; } else { if (mads.getAvailable()) { - if (mads.getEnabled()) { - status = ss.getEnabled() ? STATUS_ENGAGED : STATUS_LAT_ONLY; + if (mads.getEnabled() && ss.getEnabled()) { + status = STATUS_ENGAGED; + } else if (mads.getEnabled()) { + status = STATUS_LAT_ONLY; + } else if (ss.getEnabled()) { + status = STATUS_LONG_ONLY; } else { status = STATUS_DISENGAGED; } @@ -167,6 +171,8 @@ void Device::resetInteractiveTimeout(int timeout) { } void Device::updateBrightness(const UIState &s) { + int brightness; + int brightness_override = QString::fromStdString(Params().get("Brightness")).toInt(); float clipped_brightness = offroad_brightness; if (s.scene.started && s.scene.light_sensor >= 0) { clipped_brightness = s.scene.light_sensor; @@ -178,11 +184,19 @@ void Device::updateBrightness(const UIState &s) { clipped_brightness = std::pow((clipped_brightness + 16.0) / 116.0, 3.0); } - // Scale back to 10% to 100% - clipped_brightness = std::clamp(100.0f * clipped_brightness, 10.0f, 100.0f); + if (brightness_override == 1) { + clipped_brightness = std::clamp(100.0f * clipped_brightness, 1.0f, 100.0f); // Scale back to 1% to 100% + } else if (brightness_override == 0) { + clipped_brightness = std::clamp(100.0f * clipped_brightness, 10.0f, 100.0f); // Scale back to 10% to 100% + } + } + + if (brightness_override == 0 || brightness_override == 1) { + brightness = brightness_filter.update(clipped_brightness); + } else { + brightness = brightness_override; } - int brightness = brightness_filter.update(clipped_brightness); if (!awake) { brightness = 0; } diff --git a/sunnypilot/modeld/modeld.py b/sunnypilot/modeld/modeld.py index 2ac3f5700e..d4bd96ff66 100755 --- a/sunnypilot/modeld/modeld.py +++ b/sunnypilot/modeld/modeld.py @@ -25,6 +25,7 @@ from openpilot.sunnypilot.modeld.parse_model_outputs import Parser from openpilot.sunnypilot.modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState from openpilot.sunnypilot.modeld.constants import ModelConstants, Plan from openpilot.sunnypilot.models.helpers import get_active_bundle, get_model_path, load_metadata, prepare_inputs, load_meta_constants +from openpilot.sunnypilot.models.modeld_lagd import ModeldLagd from openpilot.sunnypilot.modeld.models.commonmodel_pyx import ModelFrame, CLContext @@ -201,8 +202,9 @@ def main(demo=False): cloudlog.info("modeld got CarParams: %s", CP.brand) + modeld_lagd = ModeldLagd() + # Enable lagd support for sunnypilot modeld - steer_delay = sm["liveDelay"].lateralDelay + model.LAT_SMOOTH_SECONDS long_delay = CP.longitudinalActuatorDelay + model.LONG_SMOOTH_SECONDS prev_action = log.ModelDataV2.Action() @@ -246,6 +248,8 @@ def main(demo=False): v_ego = sm["carState"].vEgo is_rhd = sm["driverMonitoringState"].isRHD frame_id = sm["roadCameraState"].frameId + steer_delay = modeld_lagd.lagd_main(CP, sm, model) + if sm.updated["liveCalibration"] and sm.seen['roadCameraState'] and sm.seen['deviceState']: device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32) dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['roadCameraState'].sensor))] diff --git a/sunnypilot/modeld_v2/modeld.py b/sunnypilot/modeld_v2/modeld.py index 4c8acafcad..fe322f462e 100755 --- a/sunnypilot/modeld_v2/modeld.py +++ b/sunnypilot/modeld_v2/modeld.py @@ -23,6 +23,7 @@ from openpilot.sunnypilot.modeld_v2.models.commonmodel_pyx import DrivingModelFr from openpilot.sunnypilot.modeld_v2.meta_helper import load_meta_constants from openpilot.sunnypilot.models.helpers import get_active_bundle +from openpilot.sunnypilot.models.modeld_lagd import ModeldLagd from openpilot.sunnypilot.models.runners.helpers import get_model_runner PROCESS_NAME = "selfdrive.modeld.modeld" @@ -238,6 +239,9 @@ def main(demo=False): CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams) cloudlog.info("modeld got CarParams: %s", CP.brand) + + modeld_lagd = ModeldLagd() + # TODO Move smooth seconds to action function long_delay = CP.longitudinalActuatorDelay + model.LONG_SMOOTH_SECONDS prev_action = log.ModelDataV2.Action() @@ -282,7 +286,7 @@ def main(demo=False): is_rhd = sm["driverMonitoringState"].isRHD frame_id = sm["roadCameraState"].frameId v_ego = max(sm["carState"].vEgo, 0.) - steer_delay = sm["liveDelay"].lateralDelay + model.LAT_SMOOTH_SECONDS + steer_delay = modeld_lagd.lagd_main(CP, sm, model) if sm.updated["liveCalibration"] and sm.seen['roadCameraState'] and sm.seen['deviceState']: device_from_calib_euler = np.array(sm["liveCalibration"].rpyCalib, dtype=np.float32) dc = DEVICE_CAMERAS[(str(sm['deviceState'].deviceType), str(sm['roadCameraState'].sensor))] diff --git a/sunnypilot/models/modeld_lagd.py b/sunnypilot/models/modeld_lagd.py new file mode 100644 index 0000000000..9e538123a8 --- /dev/null +++ b/sunnypilot/models/modeld_lagd.py @@ -0,0 +1,26 @@ +""" +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. +""" +from openpilot.common.params import Params +from openpilot.common.swaglog import cloudlog + + +class ModeldLagd: + def __init__(self): + self.params = Params() + + def lagd_main(self, CP, sm, model): + if self.params.get_bool("LagdToggle"): + lateral_delay = sm["liveDelay"].lateralDelay + lat_smooth = model.LAT_SMOOTH_SECONDS + result = lateral_delay + lat_smooth + cloudlog.debug(f"LAGD USING LIVE DELAY: {lateral_delay:.3f} + {lat_smooth:.3f} = {result:.3f}") + return result + steer_actuator_delay = CP.steerActuatorDelay + lat_smooth = model.LAT_SMOOTH_SECONDS + result = (steer_actuator_delay + 0.2) + lat_smooth + cloudlog.debug(f"LAGD USING STEER ACTUATOR: {steer_actuator_delay:.3f} + 0.2 + {lat_smooth:.3f} = {result:.3f}") + return result diff --git a/sunnypilot/selfdrive/assets/images/spinner_sunnypilot.png b/sunnypilot/selfdrive/assets/images/spinner_sunnypilot.png new file mode 100644 index 0000000000..edc5c6e5c2 --- /dev/null +++ b/sunnypilot/selfdrive/assets/images/spinner_sunnypilot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9dbacb55581a5ea8cbcd5cea0560ec21d96ac7185463a40fff0f81bebf044ffa +size 23187 diff --git a/system/manager/manager.py b/system/manager/manager.py index 4493b87301..7c53483714 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -46,16 +46,19 @@ def manager_init() -> None: sunnypilot_default_params: list[tuple[str, str | bytes]] = [ ("AutoLaneChangeTimer", "0"), ("AutoLaneChangeBsmDelay", "0"), + ("BlindSpot", "0"), ("BlinkerMinLateralControlSpeed", "20"), # MPH or km/h ("BlinkerPauseLateralControl", "0"), ("DynamicExperimentalControl", "0"), ("HyundaiLongitudinalTuning", "0"), + ("LagdToggle", "1"), ("Mads", "1"), ("MadsMainCruiseAllowed", "1"), ("MadsSteeringMode", "0"), ("MadsUnifiedEngagementMode", "1"), ("MapdVersion", f"{VERSION}"), ("MaxTimeOffroad", "1800"), + ("Brightness", "0"), ("ModelManager_LastSyncTime", "0"), ("ModelManager_ModelsCache", ""), ("NeuralNetworkLateralControl", "0"), diff --git a/system/ui/spinner.py b/system/ui/spinner.py index 3825f1300d..ed605885b0 100755 --- a/system/ui/spinner.py +++ b/system/ui/spinner.py @@ -8,6 +8,8 @@ from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.window import BaseWindow from openpilot.system.ui.text import wrap_text +from openpilot.system.ui.sunnypilot.lib.application import gui_app_sp + # Constants PROGRESS_BAR_WIDTH = 1000 PROGRESS_BAR_HEIGHT = 20 @@ -25,7 +27,7 @@ def clamp(value, min_value, max_value): class SpinnerRenderer: def __init__(self): - self._comma_texture = gui_app.texture("images/spinner_comma.png", TEXTURE_SIZE, TEXTURE_SIZE) + self._comma_texture = gui_app_sp.sp_texture("images/spinner_sunnypilot.png", TEXTURE_SIZE, TEXTURE_SIZE) self._spinner_texture = gui_app.texture("images/spinner_track.png", TEXTURE_SIZE, TEXTURE_SIZE, alpha_premultiply=True) self._rotation = 0.0 self._progress: int | None = None diff --git a/system/ui/sunnypilot/lib/application.py b/system/ui/sunnypilot/lib/application.py new file mode 100644 index 0000000000..10227ce9fd --- /dev/null +++ b/system/ui/sunnypilot/lib/application.py @@ -0,0 +1,21 @@ +from openpilot.system.ui.lib.application import GuiApplication +from importlib.resources import as_file, files + +ASSETS_DIR_SP = files("openpilot.sunnypilot.selfdrive").joinpath("assets") + +class GuiApplicationSP(GuiApplication): + + def __init__(self, width: int, height: int): + super().__init__(width, height) + + def sp_texture(self, asset_path: str, width: int, height: int, alpha_premultiply=False, keep_aspect_ratio=True): + cache_key = f"{asset_path}_{width}_{height}_{alpha_premultiply}{keep_aspect_ratio}" + if cache_key in self._textures: + return self._textures[cache_key] + + with as_file(ASSETS_DIR_SP.joinpath(asset_path)) as fspath: + texture_obj = self._load_texture_from_image(fspath.as_posix(), width, height, alpha_premultiply, keep_aspect_ratio) + self._textures[cache_key] = texture_obj + return texture_obj + +gui_app_sp = GuiApplicationSP(2160, 1080)