diff --git a/common/params.cc b/common/params.cc index 1ea1f39602..871266b7cb 100644 --- a/common/params.cc +++ b/common/params.cc @@ -272,6 +272,7 @@ std::unordered_map keys = { {"Map3DBuildings", PERSISTENT}, {"MaxTimeOffroad", PERSISTENT}, {"NNFF", PERSISTENT}, + {"NNFFCarModel", PERSISTENT}, {"OnroadScreenOff", PERSISTENT}, {"OnroadScreenOffBrightness", PERSISTENT}, {"OnroadScreenOffEvent", PERSISTENT}, diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 7b17487c33..d37f3a8db0 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -160,10 +160,10 @@ def get_nn_model_path(_car, eps_firmware) -> Tuple[Optional[str], float]: else: check_model = _car model_path, max_similarity = check_nn_path(check_model) - if 0.0 <= max_similarity < 0.9: + if _car not in model_path or 0.0 <= max_similarity < 0.9: check_model = _car model_path, max_similarity = check_nn_path(check_model) - if 0.0 <= max_similarity < 0.9: + if _car not in model_path or 0.0 <= max_similarity < 0.9: model_path = None return model_path, max_similarity @@ -268,8 +268,15 @@ class CarInterfaceBase(ABC): eps_firmware = str(next((fw.fwVersion for fw in car_fw if fw.ecu == "eps"), "")) model, similarity_score = get_nn_model_path(candidate, eps_firmware) if model is not None: - ret.lateralTuning.torque.nnModelName = os.path.splitext(os.path.basename(model))[0] + ret.lateralTuning.torque.nnModelName = nn_model_name = os.path.splitext(os.path.basename(model))[0] ret.lateralTuning.torque.nnModelFuzzyMatch = (similarity_score < 0.99) + if 'b\'' in nn_model_name: + nn_model, _ = nn_model_name.split('b\'') + else: + nn_model = nn_model_name + params.put("NNFFCarModel", nn_model) + else: + ret.lateralTuning.torque.nnModelName = "mock" # Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload if not ret.notCar: diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index f65fe831a7..42abc82b91 100755 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -261,7 +261,7 @@ def no_gps_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, m def torque_nn_load_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool, soft_disable_time: int) -> Alert: model_name = CP.lateralTuning.torque.nnModelName - if model_name == "": + if model_name in ("", "mock"): return Alert( "NN Lateral Controller Not Loaded", '⚙️ -> "sunnypilot" for more details', diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index b5d3fcc4b4..a84feda34b 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -80,6 +80,7 @@ def manager_init() -> None: ("LkasToggle", "0"), ("MadsIconToggle", "1"), ("MaxTimeOffroad", "9"), + ("NNFF", "0"), ("OnroadScreenOff", "-2"), ("OnroadScreenOffBrightness", "50"), ("OnroadScreenOffEvent", "1"), diff --git a/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.cc index d467a500f1..447c1e19bb 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.cc +++ b/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.cc @@ -53,18 +53,18 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { tr("Add custom offsets to Camera and Path in sunnypilot."), "../assets/offroad/icon_blank.png", }, - { - "EnforceTorqueLateral", - tr("Enforce Torque Lateral Control"), - tr("Enable this to enforce sunnypilot to steer with Torque lateral control."), - "../assets/offroad/icon_blank.png", - }, { "NNFF", tr("Neural Network Lateral Control (NNLC)"), "", "../assets/offroad/icon_blank.png", }, + { + "EnforceTorqueLateral", + tr("Enforce Torque Lateral Control"), + tr("Enable this to enforce sunnypilot to steer with Torque lateral control."), + "../assets/offroad/icon_blank.png", + }, { "LiveTorque", tr("Enable Self-Tune"), @@ -194,7 +194,7 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { // toggle for offroadTransition when going onroad/offroad std::vector toggleOffroad{ - "EnableMads", "EnforceTorqueLateral", "LiveTorqueRelaxed", "NNFF" + "EnableMads", "EnforceTorqueLateral", "CustomTorqueLateral", "LiveTorqueRelaxed", "NNFF" }; // Controls: Torque - FRICTION @@ -259,6 +259,19 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { } } + connect(toggles["NNFF"], &ToggleControl::toggleFlipped, [=](bool state) { + if (state) { + toggles["EnforceTorqueLateral"]->setEnabled(false); + params.putBool("EnforceTorqueLateral", false); + toggles["EnforceTorqueLateral"]->refresh(); + } else { + toggles["NNFF"]->hideDescription(); + + toggles["EnforceTorqueLateral"]->setEnabled(true); + toggles["EnforceTorqueLateral"]->refresh(); + } + }); + // trigger updateToggles() when toggleFlipped for (const auto& updateToggleName : updateTogglesNames) { if (toggles.find(updateToggleName) != toggles.end()) { @@ -364,6 +377,7 @@ void SunnypilotPanel::hideEvent(QHideEvent *event) { void SunnypilotPanel::updateToggles() { param_watcher->addParam("DynamicLaneProfile"); + param_watcher->addParam("IsOffroad"); if (!isVisible()) { return; @@ -389,6 +403,16 @@ void SunnypilotPanel::updateToggles() { auto reverse_acc = toggles["ReverseAccChange"]; auto slc_toggle = toggles["EnableSlc"]; + auto is_offroad = params.getBool("IsOffroad"); + + // NNLC/NNFF + QString nnff_available_desc = tr("NNLC is currently not available on this platform."); + QString nnff_fuzzy_desc = tr("Match: \"Exact\" is ideal, but \"Fuzzy\" is fine too. Reach out to the sunnypilot team in the #tuning-nnlc channel at the sunnypilot Discord server if there are any issues."); + QString nnff_status_init = tr("⚠️ Start the car to check car compatibility"); + QString nnff_not_loaded = tr("⚠️ NNLC Not Loaded"); + QString nnff_loaded = tr("✅ NNLC Loaded"); + auto _car_model = QString::fromStdString(params.get("NNFFCarModel")); + auto cp_bytes = params.get("CarParamsPersistent"); if (!cp_bytes.empty()) { AlignedBuffer aligned_buf; @@ -397,9 +421,6 @@ void SunnypilotPanel::updateToggles() { // NNLC/NNFF { - QString nnff_available_desc = tr("NNLC is currently not available on this platform."); - QString nnff_fuzzy_desc = tr("([Match = Exact] is ideal, but [Match = Fuzzy] is fine too. Contact @twilsonco in the sunnypilot Discord server if there are any issues.)"); - if (CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE) { enforce_torque_lateral->setEnabled(false); params.remove("EnforceTorqueLateral"); @@ -407,27 +428,17 @@ void SunnypilotPanel::updateToggles() { nnff_toggle->setDescription(nnffDescriptionBuilder(nnff_available_desc)); nnff_toggle->setEnabled(false); params.remove("NNFF"); - } + } else if (nnff_toggle->isToggled()) { + if (CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::TORQUE) { + QString nn_model_name = QString::fromStdString(CP.getLateralTuning().getTorque().getNnModelName()); + QString nn_fuzzy = QString::fromUtf8(CP.getLateralTuning().getTorque().getNnModelFuzzyMatch() ? "Fuzzy" : "Exact"); - else if (nnff_toggle->isToggled()) { - QString nn_model_name = QString::fromStdString(CP.getLateralTuning().getTorque().getNnModelName()); - QString nn_fuzzy = QString::fromUtf8(CP.getLateralTuning().getTorque().getNnModelFuzzyMatch() ? "Fuzzy" : "Exact"); - QString nn_status = nn_model_name == "" ? "⚠️ NNLC Not Loaded " : "✅ NNLC Loaded"; - if (nn_model_name == "") { - nnff_toggle->setDescription(nnffDescriptionBuilder(nn_status + "
Contact @twilsonco in the sunnypilot Discord server and donate logs to get NNLC loaded for your car.")); + nnff_toggle->setDescription(nnffDescriptionBuilder((nn_model_name == "") ? nnff_status_init : + (nn_model_name == "mock") ? (nnff_not_loaded + "
Reach out to the sunnypilot team in the #tuning-nnlc channel at the sunnypilot Discord server and donate logs to get NNLC loaded for your car.") : + (nnff_loaded + " | Match = " + nn_fuzzy + " | " + _car_model + "

" + nnff_fuzzy_desc))); + enforce_torque_lateral->setEnabled(false); } else { - int has_eps = nn_model_name.indexOf("b'"); - if (has_eps != -1) { - QString _car = nn_model_name.left(has_eps); - QString _eps = nn_model_name.mid(has_eps); - nnff_toggle->setDescription(nnffDescriptionBuilder(nn_status + " | Match = " + nn_fuzzy + " | " + _car + "
EPS: " + _eps + "
" + nnff_fuzzy_desc)); - } else { - nnff_toggle->setDescription(nnffDescriptionBuilder(nn_status + " | Match = " + nn_fuzzy + "
" + nn_model_name + "
" + nnff_fuzzy_desc)); - } - } - - if (nnff_toggle->getDescription() != nnff_description) { - nnff_toggle->showDescription(); + nnff_toggle->setDescription(nnffDescriptionBuilder(nnff_status_init)); } } else { nnff_toggle->setDescription(nnff_description); @@ -457,23 +468,30 @@ void SunnypilotPanel::updateToggles() { reverse_acc->setEnabled(false); slc_toggle->setEnabled(false); slcSettings->setEnabled(false); - nnff_toggle->setDescription(nnff_description); + + nnff_toggle->setDescription(nnff_toggle->isToggled() ? nnffDescriptionBuilder(nnff_status_init) : nnff_description); + } + + if (nnff_toggle->getDescription() != nnff_description) { + nnff_toggle->showDescription(); } // toggle names to update when EnforceTorqueLateral is flipped std::vector torqueLateralGroup{"CustomTorqueLateral", "LiveTorque", "LiveTorqueRelaxed", "TorquedOverride"}; for (const auto& torqueLateralToggle : torqueLateralGroup) { if (toggles.find(torqueLateralToggle) != toggles.end()) { - toggles[torqueLateralToggle]->setVisible(enforce_torque_lateral->isToggled()); - toggles[torqueLateralToggle]->setEnabled(!nnff_toggle->isToggled()); + if (nnff_toggle->isToggled()) { + toggles[torqueLateralToggle]->setVisible(false); + toggles[torqueLateralToggle]->setEnabled(false); + } } } - // toggle names to update when CustomTorqueLateral is flipped - std::vector customTorqueGroup{friction, lat_accel_factor}; - for (const auto& customTorqueControl : customTorqueGroup) { - customTorqueControl->setVisible(custom_torque_lateral->isToggled()); - customTorqueControl->setEnabled(!nnff_toggle->isToggled()); + for (const auto& torqueLateralToggle : torqueLateralGroup) { + if (toggles.find(torqueLateralToggle) != toggles.end()) { + toggles[torqueLateralToggle]->setVisible(enforce_torque_lateral->isToggled()); + toggles[torqueLateralToggle]->setEnabled(enforce_torque_lateral->isToggled()); + } } if (enforce_torque_lateral->isToggled()) { @@ -482,13 +500,18 @@ void SunnypilotPanel::updateToggles() { } else { params.putBool("LiveTorque", false); params.putBool("CustomTorqueLateral", false); - for (const auto& customTorqueControl : customTorqueGroup) { - customTorqueControl->setVisible(false); - } } - m_tsc->setVisible(false); // TODO: temporarily disable M-TSC until the reimplementation is in place. Remove this line to re-enable the toggle. - m_tsc->setEnabled(false); // TODO: temporarily disable M-TSC until the reimplementation is in place. Remove this line to re-enable the toggle. + // toggle names to update when CustomTorqueLateral is flipped + std::vector customTorqueGroup{friction, lat_accel_factor}; + for (const auto& customTorqueControl : customTorqueGroup) { + customTorqueControl->setVisible(!(nnff_toggle->isToggled() || !custom_torque_lateral->isToggled())); + customTorqueControl->setEnabled(!(nnff_toggle->isToggled() || !custom_torque_lateral->isToggled())); + } + + toggles["CustomTorqueLateral"]->setEnabled(is_offroad); + toggles["LiveTorque"]->setEnabled(is_offroad); + toggles["LiveTorqueRelaxed"]->setEnabled(is_offroad); } TorqueFriction::TorqueFriction() : SPOptionControl ( diff --git a/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h b/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h index 5f9919ea50..2a0b1b4734 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h +++ b/selfdrive/ui/qt/offroad/sunnypilot/sunnypilot_settings.h @@ -65,7 +65,7 @@ private: const QString nnff_description = QString("%1
" "%2") .arg(tr("Formerly known as \"NNFF\", this replaces the lateral \"torque\" controller with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy.")) - .arg(tr("Contact @twilsonco in the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported.")); + .arg(tr("Reach out to the sunnypilot team in the #tuning-nnlc channel at the sunnypilot Discord server with feedback, or to provide log data for your car if your car is currently unsupported.")); QString nnffDescriptionBuilder(const QString &custom_description) { QString description = "" + custom_description + "

" + nnff_description;