diff --git a/common/params.cc b/common/params.cc index 89ea211..2b6962c 100644 --- a/common/params.cc +++ b/common/params.cc @@ -291,6 +291,7 @@ std::unordered_map keys = { {"ManualUpdateInitiated", CLEAR_ON_MANAGER_START}, {"MapTargetLatA", PERSISTENT}, {"MapTargetVelocities", PERSISTENT}, + {"Model", PERSISTENT}, {"ModelUI", PERSISTENT}, {"MTSCAggressiveness", PERSISTENT}, {"MTSCCurvatureCheck", PERSISTENT}, diff --git a/selfdrive/frogpilot/functions/frogpilot_functions.py b/selfdrive/frogpilot/functions/frogpilot_functions.py index 2581a3f..4ca2841 100644 --- a/selfdrive/frogpilot/functions/frogpilot_functions.py +++ b/selfdrive/frogpilot/functions/frogpilot_functions.py @@ -7,6 +7,8 @@ from openpilot.system.hardware import HARDWARE params_memory = Params("/dev/shm/params") +DEFAULT_MODEL = "los-angeles" + CITY_SPEED_LIMIT = 25 CRUISING_SPEED = 5 # Roughly the speed cars go when not touching the gas while in drive PROBABILITY = 0.6 # 60% chance of condition being true diff --git a/selfdrive/frogpilot/ui/control_settings.cc b/selfdrive/frogpilot/ui/control_settings.cc index 2a3bf87..6f56e64 100644 --- a/selfdrive/frogpilot/ui/control_settings.cc +++ b/selfdrive/frogpilot/ui/control_settings.cc @@ -33,6 +33,8 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil {"AggressiveAcceleration", "Aggressive Acceleration With Lead", "Increase acceleration aggressiveness when following a lead vehicle from a stop.", ""}, {"StoppingDistance", "Increase Stop Distance Behind Lead", "Increase the stopping distance for a more comfortable stop from lead vehicles.", ""}, + {"Model", "Model Selector", "Choose your preferred openpilot model.", "../assets/offroad/icon_calibration.png"}, + {"MTSCEnabled", "Map Turn Speed Control", "Slow down for anticipated curves detected by your downloaded maps.", "../frogpilot/assets/toggle_icons/icon_speed_map.png"}, {"DisableMTSCSmoothing", "Disable MTSC UI Smoothing", "Disables the smoothing for the requested speed in the onroad UI.", ""}, {"MTSCCurvatureCheck", "Model Curvature Detection Failsafe", "Only trigger MTSC when the model detects a curve in the road. Purely used as a failsafe to prevent false positives. Leave this off if you never experience false positives.", ""}, @@ -219,6 +221,34 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil } else if (param == "StoppingDistance") { toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, std::map(), this, false, " feet"); + } else if (param == "Model") { + modelSelectorButton = new FrogPilotButtonIconControl(title, tr("SELECT"), desc, icon); + QStringList models = {"los-angeles", "certified-herbalist", "duck-amigo", "recertified-herbalist"}; + QStringList modelLabels = {"Los Angeles (Default)", "Certified Herbalist", "Duck Amigo", "Recertified Herbalist"}; + QObject::connect(modelSelectorButton, &FrogPilotButtonIconControl::clicked, this, [this, models, modelLabels]() { + QString selection = MultiOptionDialog::getSelection(tr("Select a driving model"), modelLabels, "", this); + + if (!selection.isEmpty()) { + int selectedModelIndex = modelLabels.indexOf(selection); + QString selectedModelValue = models[selectedModelIndex]; + params.put("Model", selectedModelValue.toStdString()); + modelSelectorButton->setValue(selection); + if (FrogPilotConfirmationDialog::yesorno("Do you want to start with a fresh calibration for the newly selected model?", this)) { + params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters"); + } + if (started) { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::soft_reboot(); + } + } + } + }); + int initialModelIndex = models.indexOf(QString::fromStdString(params.get("Model"))); + QString initialModelLabel = modelLabels[initialModelIndex]; + modelSelectorButton->setValue(initialModelLabel); + addItem(modelSelectorButton); + } else if (param == "MTSCEnabled") { FrogPilotParamManageControl *mtscToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); QObject::connect(mtscToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { @@ -356,6 +386,7 @@ void FrogPilotControlsPanel::parentToggleClicked() { aggressiveProfile->setVisible(false); conditionalSpeedsImperial->setVisible(false); conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(false); standardProfile->setVisible(false); relaxedProfile->setVisible(false); @@ -370,6 +401,7 @@ void FrogPilotControlsPanel::hideSubToggles() { aggressiveProfile->setVisible(false); conditionalSpeedsImperial->setVisible(false); conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(true); standardProfile->setVisible(false); relaxedProfile->setVisible(false); diff --git a/selfdrive/frogpilot/ui/control_settings.h b/selfdrive/frogpilot/ui/control_settings.h index d89bfde..c69a8d8 100644 --- a/selfdrive/frogpilot/ui/control_settings.h +++ b/selfdrive/frogpilot/ui/control_settings.h @@ -29,6 +29,8 @@ private: void updateState(const UIState &s); void updateToggles(); + FrogPilotButtonIconControl *modelSelectorButton; + FrogPilotDualParamControl *aggressiveProfile; FrogPilotDualParamControl *conditionalSpeedsImperial; FrogPilotDualParamControl *conditionalSpeedsMetric; diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 3365b81..41edf9a 100644 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -12,6 +12,7 @@ from typing import List, Tuple, Union from cereal import log import cereal.messaging as messaging import openpilot.selfdrive.sentry as sentry +from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params, ParamKeyType from openpilot.common.text_window import TextWindow from openpilot.system.hardware import HARDWARE, PC @@ -24,6 +25,7 @@ from openpilot.system.version import is_dirty, get_commit, get_version, get_orig get_normalized_origin, terms_version, training_version, \ is_tested_branch, is_release_branch, get_commit_date +from openpilot.selfdrive.frogpilot.functions.frogpilot_functions import DEFAULT_MODEL def manager_init() -> None: @@ -62,6 +64,16 @@ def manager_init() -> None: ####################################################################### + # Check if the currently selected model still exists + current_model = params.get("Model", encoding='utf-8') + + if current_model != DEFAULT_MODEL: + models_folder = os.path.join(BASEDIR, 'selfdrive/modeld/models/models') + model_exists = current_model in [os.path.splitext(file)[0] for file in os.listdir(models_folder)] + + if not model_exists: + params.remove("Model") + default_params: List[Tuple[str, Union[str, bytes]]] = [ ("CompletedTrainingVersion", "0"), ("DisengageOnAccelerator", "0"), diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 8a12fb9..9d13f68 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -24,11 +24,15 @@ from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_ from openpilot.selfdrive.modeld.constants import ModelConstants from openpilot.selfdrive.modeld.models.commonmodel_pyx import ModelFrame, CLContext +from openpilot.selfdrive.frogpilot.functions.frogpilot_functions import DEFAULT_MODEL + PROCESS_NAME = "selfdrive.modeld.modeld" SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') +MODEL_NAME = Params().get("Model", encoding='utf-8') + MODEL_PATHS = { - ModelRunner.THNEED: Path(__file__).parent / 'models/supercombo.thneed', + ModelRunner.THNEED: Path(__file__).parent / ('models/supercombo.thneed' if MODEL_NAME == DEFAULT_MODEL else f'models/models/{MODEL_NAME}.thneed'), ModelRunner.ONNX: Path(__file__).parent / 'models/supercombo.onnx'} METADATA_PATH = Path(__file__).parent / 'models/supercombo_metadata.pkl' diff --git a/selfdrive/modeld/models/models/certified-herbalist.thneed b/selfdrive/modeld/models/models/certified-herbalist.thneed new file mode 100644 index 0000000..05dc7d5 Binary files /dev/null and b/selfdrive/modeld/models/models/certified-herbalist.thneed differ diff --git a/selfdrive/modeld/models/models/duck-amigo.thneed b/selfdrive/modeld/models/models/duck-amigo.thneed new file mode 100644 index 0000000..08b167c Binary files /dev/null and b/selfdrive/modeld/models/models/duck-amigo.thneed differ diff --git a/selfdrive/modeld/models/models/recertified-herbalist.thneed b/selfdrive/modeld/models/models/recertified-herbalist.thneed new file mode 100644 index 0000000..0604008 Binary files /dev/null and b/selfdrive/modeld/models/models/recertified-herbalist.thneed differ diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index b1e695f..2c5f81d 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -217,6 +217,14 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { font-size: 55px; } )"); + + // Set the model name + MODEL_NAME = { + {"los-angeles", "Los Angeles"}, + {"certified-herbalist", "Certified Herbalist"}, + {"duck-amigo", "Duck Amigo"}, + {"recertified-herbalist", "Recertified Herbalist"}, + }; } void OffroadHome::showEvent(QShowEvent *event) { @@ -229,8 +237,10 @@ void OffroadHome::hideEvent(QHideEvent *event) { } void OffroadHome::refresh() { + QString model = QString::fromStdString(params.get("Model")); + date->setText(QLocale(uiState()->language.mid(5)).toString(QDateTime::currentDateTime(), "dddd, MMMM d")); - version->setText(getBrand() + " v" + getVersion().left(14).trimmed()); + version->setText(getBrand() + " v" + getVersion().left(14).trimmed() + " - " + MODEL_NAME[model]); bool updateAvailable = update_widget->refresh(); int alerts = alerts_widget->refresh(); diff --git a/selfdrive/ui/qt/home.h b/selfdrive/ui/qt/home.h index 9623a87..b3f02cf 100644 --- a/selfdrive/ui/qt/home.h +++ b/selfdrive/ui/qt/home.h @@ -42,6 +42,7 @@ private: QPushButton* update_notif; // FrogPilot variables + std::map MODEL_NAME; }; class HomeWindow : public QWidget {