diff --git a/common/params.cc b/common/params.cc index 5f7430b..db2d44f 100644 --- a/common/params.cc +++ b/common/params.cc @@ -263,6 +263,8 @@ std::unordered_map keys = { {"LongPitch", PERSISTENT}, {"LowerVolt", PERSISTENT}, {"MapTargetVelocities", PERSISTENT}, + {"Model", PERSISTENT}, + {"ModelList", PERSISTENT}, {"ModelUI", PERSISTENT}, {"MTSCAggressiveness", PERSISTENT}, {"MTSCEnabled", PERSISTENT}, diff --git a/release/files_common b/release/files_common index f792335..9f0277a 100644 --- a/release/files_common +++ b/release/files_common @@ -560,3 +560,4 @@ tinygrad_repo/tinygrad/*.py selfdrive/frogpilot/functions/conditional_experimental_mode.py selfdrive/frogpilot/functions/frogpilot_planner.py selfdrive/frogpilot/functions/map_turn_speed_controller.py +selfdrive/frogpilot/functions/model_switcher.py diff --git a/selfdrive/frogpilot/functions/model_switcher.py b/selfdrive/frogpilot/functions/model_switcher.py new file mode 100644 index 0000000..f7fb8df --- /dev/null +++ b/selfdrive/frogpilot/functions/model_switcher.py @@ -0,0 +1,63 @@ +import hashlib +import os +import shutil +from openpilot.common.params import Params +from openpilot.system.hardware import HARDWARE + +OPENPILOT_PATH = "/data/openpilot" +DESTINATION_PATH = os.path.join(OPENPILOT_PATH, "selfdrive/modeld/models") +MODELS_SOURCE = os.path.join(DESTINATION_PATH, "models") +THNEED_FILE = os.path.join(DESTINATION_PATH, "supercombo.thneed") + +MODEL_NAME = { + 0: "new-delhi", + 1: "blue-diamond-v1", + 2: "blue-diamond-v2", + 3: "farmville", + 4: "new-lemon-pie", +} + +def set_model_list_parameter(params): + """Create a string of all the model names for future comparisons.""" + # Retrieve the previous model list + previous_model_list = params.get("ModelList", encoding='utf-8') + + # Create a new model list + model_list = "".join(MODEL_NAME.values()) + + if previous_model_list != model_list: + # Reset the selected model if the model list changed + params.put_int("Model", 0) + params.put("ModelList", model_list) + params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters"); + +def onnx_already_set(path1, path2): + """Check if the two files are identical by comparing their SHA-256 hashes.""" + with open(path1, 'rb') as f1, open(path2, 'rb') as f2: + return hashlib.sha256(f1.read()).hexdigest() == hashlib.sha256(f2.read()).hexdigest() + +def copy_model_variant(params): + # Get the corresponding supercombo variant name + variant = MODEL_NAME.get(params.get_int("Model"), MODEL_NAME[0]) + + # Copy the variant .onnx file to supercombo.onnx in the destination models folder + onnx_path = os.path.join(MODELS_SOURCE, f"{variant}.onnx") + destination = os.path.join(DESTINATION_PATH, "supercombo.onnx") + + if not onnx_already_set(onnx_path, destination): + # Delete the thneed file + if os.path.exists(THNEED_FILE): + os.remove(THNEED_FILE) + + # Copy over the onnx file + shutil.copy(onnx_path, destination) + + # Reboot + HARDWARE.reboot() + +if __name__ == "__main__": + params = Params() + + set_model_list_parameter(params) + copy_model_variant(params) diff --git a/selfdrive/frogpilot/ui/control_settings.cc b/selfdrive/frogpilot/ui/control_settings.cc index c7ffdca..4216127 100644 --- a/selfdrive/frogpilot/ui/control_settings.cc +++ b/selfdrive/frogpilot/ui/control_settings.cc @@ -31,6 +31,7 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil {"AggressiveAcceleration", "Aggressive Acceleration With Lead", "Increase acceleration aggressiveness when following a lead vehicle from a stop.", ""}, {"StoppingDistance", "Increased Stopping Distance", "Increase the stopping distance for a more comfortable stop.", ""}, + {"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"}, }; @@ -176,6 +177,28 @@ 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 = {"New Delhi (Default)", "Blue Diamond V1", "Blue Diamond V2", "Farmville", "New Lemon Pie"}; + QObject::connect(modelSelectorButton, &FrogPilotButtonIconControl::clicked, this, [this, models]() { + int currentModel = params.getInt("Model"); + QString currentModelLabel = models[currentModel]; + + QString selection = MultiOptionDialog::getSelection(tr("Select a driving model"), models, currentModelLabel, this); + if (!selection.isEmpty()) { + int selectedModel = models.indexOf(selection); + params.putInt("Model", selectedModel); + params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters"); + modelSelectorButton->setValue(selection); + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + } + }); + modelSelectorButton->setValue(models[params.getInt("Model")]); + addItem(modelSelectorButton); + } else { toggle = new ParamControl(param, title, desc, icon, this); } @@ -262,6 +285,7 @@ void FrogPilotControlsPanel::parentToggleClicked() { aggressiveProfile->setVisible(false); conditionalSpeedsImperial->setVisible(false); conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(false); standardProfile->setVisible(false); relaxedProfile->setVisible(false); @@ -272,6 +296,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 473c94b..9286cdb 100644 --- a/selfdrive/frogpilot/ui/control_settings.h +++ b/selfdrive/frogpilot/ui/control_settings.h @@ -22,6 +22,8 @@ private: void updateMetric(); void updateToggles(); + FrogPilotButtonIconControl *modelSelectorButton; + FrogPilotDualParamControl *aggressiveProfile; FrogPilotDualParamControl *conditionalSpeedsImperial; FrogPilotDualParamControl *conditionalSpeedsMetric; diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 4646f96..ba7c4c4 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -199,6 +199,9 @@ def main() -> None: if os.path.exists("/data/openpilot/prebuilt"): os.remove("/data/openpilot/prebuilt") + # Set the desired model on boot + subprocess.run(["python3", "/data/openpilot/selfdrive/frogpilot/functions/model_switcher.py"]) + # Start UI early so prepare can happen in the background if not prepare_only: managed_processes['ui'].start() diff --git a/selfdrive/modeld/models/models/blue-diamond-v1.onnx b/selfdrive/modeld/models/models/blue-diamond-v1.onnx new file mode 100644 index 0000000..e115f36 Binary files /dev/null and b/selfdrive/modeld/models/models/blue-diamond-v1.onnx differ diff --git a/selfdrive/modeld/models/models/blue-diamond-v2.onnx b/selfdrive/modeld/models/models/blue-diamond-v2.onnx new file mode 100644 index 0000000..1cbde1b Binary files /dev/null and b/selfdrive/modeld/models/models/blue-diamond-v2.onnx differ diff --git a/selfdrive/modeld/models/models/farmville.onnx b/selfdrive/modeld/models/models/farmville.onnx new file mode 100644 index 0000000..181c264 Binary files /dev/null and b/selfdrive/modeld/models/models/farmville.onnx differ diff --git a/selfdrive/modeld/models/models/new-delhi.onnx b/selfdrive/modeld/models/models/new-delhi.onnx new file mode 100644 index 0000000..fb7f1dd Binary files /dev/null and b/selfdrive/modeld/models/models/new-delhi.onnx differ diff --git a/selfdrive/modeld/models/models/new-lemon-pie.onnx b/selfdrive/modeld/models/models/new-lemon-pie.onnx new file mode 100644 index 0000000..77f2fc1 Binary files /dev/null and b/selfdrive/modeld/models/models/new-lemon-pie.onnx differ diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index c439298..d3abf66 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -463,7 +463,8 @@ def thermald_thread(end_event, hw_queue) -> None: # Create the prebuilt file if it doesn't exist if not os.path.isfile('/data/openpilot/prebuilt'): - os.system(f"touch {'/data/openpilot/prebuilt'}") + if os.path.exists("/data/openpilot/selfdrive/modeld/models/supercombo.thneed"): + os.system(f"touch {'/data/openpilot/prebuilt'}") def main(): hw_queue = queue.Queue(maxsize=1) diff --git a/selfdrive/ui/qt/home.cc b/selfdrive/ui/qt/home.cc index fb40e94..8957551 100644 --- a/selfdrive/ui/qt/home.cc +++ b/selfdrive/ui/qt/home.cc @@ -217,6 +217,17 @@ OffroadHome::OffroadHome(QWidget* parent) : QFrame(parent) { font-size: 55px; } )"); + + // Set the model name + std::map MODEL_NAME { + {0, "New Delhi"}, + {1, "Blue Diamond V1"}, + {2, "Blue Diamond V2"}, + {3, "Farmville"}, + {4, "New Lemon Pie"}, + }; + + modelName = MODEL_NAME[params.getInt("Model")]; } void OffroadHome::showEvent(QShowEvent *event) { @@ -230,7 +241,7 @@ void OffroadHome::hideEvent(QHideEvent *event) { void OffroadHome::refresh() { 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() + " - " + modelName); 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 e0d31d7..780b8c2 100644 --- a/selfdrive/ui/qt/home.h +++ b/selfdrive/ui/qt/home.h @@ -42,6 +42,7 @@ private: QPushButton* update_notif; // FrogPilot variables + QString modelName; }; class HomeWindow : public QWidget {