From 72f09ec9f5a8bd8695c9dc50bd5fe9bfccc3d9b1 Mon Sep 17 00:00:00 2001 From: Discountchubbs <159560811+Discountchubbs@users.noreply.github.com> Date: Thu, 8 May 2025 22:06:45 -0700 Subject: [PATCH] Hyundai: custom longitudinal tuning (#658) * Maybe I was asleep but somehow it worked. * Maybe I was asleep but somehow it worked. * 70/30 split * 60/35 split * 67:33 split * use Sqrt for tiny values to increase factor. Oh, also add a test file. * use Sqrt for tiny values to increase factor. Oh, also add a test file. * use Sqrt for tiny values to increase factor. Oh, also add a test file. * Raise these to restart tests * Raise these to restart tests * Update jerk calculation mimicking j_ego math. * README.md * Update timestep * Fix test * Readability * Lower time * Add higher limits for CANFD * Send these as a floating object. update comments to add TODO msg. * Conditional flags * yes its a little weird but heres why: ` "aReqValue": long_state.accel_value if enabled else a_val` its only to not have merge conflicts with syncs from this file, because if not enabled a_val is already at 0 anyways. * Make it easier to read * Chronological order * Trigger rebuild * This is an internal test on my end. Disregard, for now * fw version for my car... * remove fw version as that was a test * bump submodules * refactor that while passing internal tests * bump safety mutation test * all should match 50 Hz * bump safety mutation test * match stock behavior for accel * do our own clipping * apply upper/lower dynamically * bump test * bump test * Higher lower limit * move desired accel force zero in tuning controller * bump * bump * abs it here * fix logic * make sure it resets to 0, enforced in safety * Test a few things * Higher jerk for VOACC * Elantra specific * raise `off` to stock * bump opendbc test * allow jerk calculations at all times * bump * bump * match aReqVale * we dont need such high accel jerk when above 20m/s. This is cruise control, not a racecar. * 0.45 default long actuator delay * align type hint * add lower jerk multiplier for HYUNDAI_IONIQ * Change min jerk * should be float * Change min jerk * Change min jerk upper * Change max jerk upper * Change max jerk upper * Change max jerk upper * step + threshold + first order filter to smooth * constants * nah * multiplier to 1.5 * step updates for parabolic accel/braking * step updates for parabolic accel/braking * even less * test multiplier * Merge remote-tracking branch 'sunnypilot/opendbc/master-new' into HKG-long-tune * back to default delay for now * update test * update config * update test * update config.py * update test * Remove stoppingDecelRate **No need for this anymore** * multiplier to 1.0 * Variable lower dependency * Variable lower dependency * Variable lower jerk minimum * Variable lower jerk minimum planned_accel -> desired_acel * Revert some scaling * .01 here * .01 here * try even smoother stopping * missed a `tuning` here that instead calls itself to inf. * what is math * Red Diff * Red Diff * bring some back * bring some back * stronger when needed * something simple * simplify more * simplify more * dont use future * whoops * why * reset * Refactor longitudinal controller for better jerk handling Revised `calculate_a_value` and jerk processing logic to improve acceleration and jerk handling, particularly under dynamic conditions. Adjusted test cases to cover the new logic. * Refactor longitudinal controller for better jerk handling Revised `calculate_a_value` and jerk processing logic to improve acceleration and jerk handling, particularly under dynamic conditions. Adjusted test cases to cover the new logic. * Refactor longitudinal controller for better jerk handling Revised `calculate_a_value` and jerk processing logic to improve acceleration and jerk handling, particularly under dynamic conditions. Adjusted test cases to cover the new logic. * Adjust lower_jerk interpolation for improved accuracy * Lowered the acceleration error threshold from -0.01 to -0.001 * Adjust jerk interpolation thresholds for Hyundai tuning. Updated the interpolation range for smaller acceleration errors. * Move it up * -.03 not -.05 * radarUnavailable = higher limit patch * Commit the real change * Updated the interpolation values and logic for lower_jerk to refine acceleration behavior. * Updated the interpolation values and logic for lower_jerk to refine acceleration behavior. * Updated the interpolation values and logic for lower_jerk to refine acceleration behavior. * Updated the interpolation values and logic for lower_jerk to refine acceleration behavior. * THIS. THIS WILL STOP FOR LEADS * Higher for VOACC * Higher for VOACC * Rename `make_jerk` to `calculate_jerk` in test cases. * Adjust jerk tuning for Hyundai longitudinal control Updated the interpolation table for lower jerk values to improve deceleration handling. This adjustment refines control behavior during higher deceleration requests. * Updated the interpolation breakpoint from -0.03 to -0.025 * Adjust longitudinal control jerk tuning for smoother response Updated interpolation values in the jerk tuning logic to improve acceleration smoothing in Hyundai longitudinal control. These changes aim to provide a more consistent and predictable driving experience, particularly during deceleration scenarios. * Handle radar unavailability in longitudinal tuning check * Introduce `toggleDisableMsg` to streamline determining toggle states and descriptions. * `sunnypilot` * `Refactor longitudinal control acceleration and jerk handling` Removed unused `FirstOrderFilter` and simplified acceleration and jerk calculations for improved clarity and maintainability. Adjusted logic to replace redundant return statements, streamline jerk computation, and reduce unnecessary dependencies. * `Refactor longitudinal control acceleration and jerk handling` Removed unused `FirstOrderFilter` and simplified acceleration and jerk calculations for improved clarity and maintainability. Adjusted logic to replace redundant return statements, streamline jerk computation, and reduce unnecessary dependencies. * Simplify test to be straight to the point. * Adjust upper_speed_factor and integrate ramp_update logic * Adjust upper_speed_factor and integrate ramp_update logic * Adjust upper_speed_factor and integrate ramp_update logic * Refine acceleration and jerk tuning logic. * greater than 0 * bump * bring back ramp update for jerk upper * Update opendbc_repo * Revert "Update opendbc_repo" This reverts commit b790387c9080b3a553694fbae850e9aa8bb6e125. * bump * bump * bump * using count seems to work better * Refine jerk tuning logic and expand test coverage * bump vals * fix logic * Adjust jerk tuning parameters for Hyundai longitudinal control * retry lfs check * bump submodule * Fix acceleration blending and enhance test coverage * Update lower_jerk breakpoints * bump * Adjust lower jerk parameters and include accel_cmd condition * Adjust vars * "Adjust Hyundai longitudinal jerk limits and tuning logic" * Adjust jerk limits and tuning logic for better control * Update Hyundai longitudinal tuning and add dynamic jerk logic Refactored longitudinal configuration to include "lookahead" parameters and revised "jerk_limits" for improved tuning flexibility. Implemented dynamic jerk adaptation logic (Gen1) for smoother braking and acceleration transitions. * Adjust Hyundai longitudinal control parameters for tuning * bump to original branch * QSize Policy to stretch toggle to screen size * bump * completely blocked xD * Sunnypilot -> openpilot * Whitespace * Clean up toggle name * Still allow ramp while in standstill for EV * Adjust Kia Niro EV tuning parameters for smoother control * self.cp.flags * bump submodule * bump * Remove ramp for lower desired jerk * update README.md * update README.md * Adjust lookahead_jerk_lower_v values in Hyundai longitudinal config. * update tuning * Update tune one last time to vals from device which are much smoother. * Accel error * bump * fix * rename flag and slight cleanup * start ui stuff * long_state -> tuning * Prep for clean up * small changes * less in main * no longer * format * bump * init panel * expose signal for other panels to interact with * split into its own * unused * move around * actually modify CP_SP * fix offroad transition * rename * back * don't update unless we're looking at it * move around * use min length * do this * whoops * move * bump * bump * this is fine * bump --------- Co-authored-by: Jason Wen Co-authored-by: DevTekVE Co-authored-by: royjr --- common/params_keys.h | 1 + opendbc_repo | 2 +- selfdrive/ui/sunnypilot/SConscript | 1 + .../settings/vehicle/hyundai_settings.cc | 84 +++++++++++++++++++ .../settings/vehicle/hyundai_settings.h | 32 +++++++ .../qt/offroad/settings/vehicle_panel.cc | 25 ++++++ .../qt/offroad/settings/vehicle_panel.h | 14 +++- sunnypilot/selfdrive/car/interfaces.py | 19 ++++- system/manager/manager.py | 1 + 9 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc create mode 100644 selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h diff --git a/common/params_keys.h b/common/params_keys.h index 575dcc2ad..97f23d510 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -164,6 +164,7 @@ inline static std::unordered_map keys = { {"BackupManager_RestoreVersion", PERSISTENT}, // sunnypilot car specific params + {"HyundaiLongitudinalTuning", PERSISTENT}, {"HyundaiRadarTracks", PERSISTENT}, {"HyundaiRadarTracksConfirmed", PERSISTENT}, {"HyundaiRadarTracksPersistent", PERSISTENT}, diff --git a/opendbc_repo b/opendbc_repo index 029bc6abc..95fc30472 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit 029bc6abc43e497fd361bbcbb9efb92e43353c5b +Subproject commit 95fc304727483d0d7f18f7df348d941046e046f2 diff --git a/selfdrive/ui/sunnypilot/SConscript b/selfdrive/ui/sunnypilot/SConscript index 4ff3f7047..82a257523 100644 --- a/selfdrive/ui/sunnypilot/SConscript +++ b/selfdrive/ui/sunnypilot/SConscript @@ -50,6 +50,7 @@ network_src = [ ] vehicle_panel_qt_src = [ + "sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc", "sunnypilot/qt/offroad/settings/vehicle/platform_selector.cc", ] diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc new file mode 100644 index 000000000..08d76f592 --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.cc @@ -0,0 +1,84 @@ +/** + * 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/vehicle/hyundai_settings.h" + +#include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" + +HyundaiSettings::HyundaiSettings(QWidget *parent) : QWidget(parent) { + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); + + ListWidget *list = new ListWidget(this, false); + + std::vector tuning_texts{ tr("Off"), tr("Dynamic"), tr("Predictive") }; + longitudinalTuningToggle = new ButtonParamControlSP( + "HyundaiLongitudinalTuning", + tr("Custom Longitudinal Tuning"), + tr("Select a tuning mode.\n" + "Off: no custom tuning applied.\n" + "Dynamic: on-the-spot adjustments using dynamic calculations.\n" + "Predictive: adjusts based on anticipated ACC variation."), + "", + tuning_texts, + 500 + ); + longitudinalTuningToggle->showDescription(); + longitudinalTuningToggle->setProperty("originalDesc", longitudinalTuningToggle->getDescription()); + list->addItem(longitudinalTuningToggle); + + QObject::connect(uiState(), &UIState::offroadTransition, this, &HyundaiSettings::updateSettings); + + main_layout->addWidget(new ScrollViewSP(list, this)); +} + +QString HyundaiSettings::toggleDisableMsg() const { + if (!has_longitudinal_control) { + return tr("This feature can only be used with openpilot longitudinal control enabled."); + } + + if (!offroad) { + return tr("Enable \"Always Offroad\" in Device panel, or turn vehicle off to select an option."); + } + + return QString(); +} + +void HyundaiSettings::showEvent(QShowEvent *event) { + updateSettings(offroad); +} + +void HyundaiSettings::updateSettings(bool _offroad) { + if (!isVisible()) { + return; + } + + auto cp_bytes = params.get("CarParamsPersistent"); + if (!cp_bytes.empty()) { + AlignedBuffer aligned_buf; + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); + cereal::CarParams::Reader CP = cmsg.getRoot(); + + has_longitudinal_control = hasLongitudinalControl(CP); + + QString longitudinal_tuning_disabled_msg = toggleDisableMsg(); + if (!longitudinal_tuning_disabled_msg.isEmpty()) { + longitudinalTuningToggle->setEnabled(false); + longitudinalTuningToggle->setDescription(longitudinal_tuning_disabled_msg); + } else { + longitudinalTuningToggle->setEnabled(true); + longitudinalTuningToggle->setDescription(longitudinalTuningToggle->property("originalDesc").toString()); + } + + longitudinalTuningToggle->showDescription(); + } else { + has_longitudinal_control = false; + longitudinalTuningToggle->setEnabled(false); + } + + offroad = _offroad; +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h new file mode 100644 index 000000000..3137a0d1b --- /dev/null +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h @@ -0,0 +1,32 @@ +/** + * 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/qt/util.h" +#include "selfdrive/ui/sunnypilot/ui.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/controls.h" + +class HyundaiSettings : public QWidget { + Q_OBJECT + +public: + explicit HyundaiSettings(QWidget *parent = nullptr); + void showEvent(QShowEvent *event) override; + +public slots: + void updateSettings(bool _offroad); + +private: + Params params; + bool offroad = false; + bool has_longitudinal_control = false; + + ButtonParamControlSP *longitudinalTuningToggle = nullptr; + QString toggleDisableMsg() const; +}; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc index cc3e6df18..bc9f645f3 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.cc @@ -7,6 +7,7 @@ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h" #include "selfdrive/ui/sunnypilot/qt/widgets/scrollview.h" VehiclePanel::VehiclePanel(QWidget *parent) : QFrame(parent) { @@ -18,11 +19,16 @@ VehiclePanel::VehiclePanel(QWidget *parent) : QFrame(parent) { vlayout->setContentsMargins(50, 20, 50, 20); platformSelector = new PlatformSelector(); + QObject::connect(platformSelector, &PlatformSelector::refreshPanel, this, &VehiclePanel::updateBrandSettings); list->addItem(platformSelector); ScrollViewSP *scroller = new ScrollViewSP(list, this); vlayout->addWidget(scroller); + hyundaiSettings = new HyundaiSettings(this); + vlayout->addWidget(hyundaiSettings); + hyundaiSettings->setVisible(false); + QObject::connect(uiState(), &UIState::offroadTransition, this, &VehiclePanel::updatePanel); main_layout->addWidget(vehicleScreen); @@ -36,5 +42,24 @@ void VehiclePanel::showEvent(QShowEvent *event) { void VehiclePanel::updatePanel(bool _offroad) { platformSelector->refresh(_offroad); + updateBrandSettings(); + offroad = _offroad; } + +void VehiclePanel::updateBrandSettings() { + if (!isVisible()) { + return; + } + + resetBrandSettings(); + + QString brand = platformSelector->getPlatformBundle("brand").toString(); + if (brand == "hyundai") { + hyundaiSettings->setVisible(true); + } +} + +void VehiclePanel::resetBrandSettings() { + hyundaiSettings->setVisible(false); +} diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h index f6265da7a..5548ff718 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle_panel.h @@ -9,6 +9,7 @@ #include "selfdrive/ui/sunnypilot/qt/offroad/settings/settings.h" +#include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/hyundai_settings.h" #include "selfdrive/ui/sunnypilot/qt/offroad/settings/vehicle/platform_selector.h" class VehiclePanel : public QFrame { @@ -22,8 +23,17 @@ public slots: void updatePanel(bool _offroad); private: + void resetBrandSettings(); + QStackedLayout* main_layout = nullptr; QWidget* vehicleScreen = nullptr; - PlatformSelector *platformSelector = nullptr; - bool offroad; + PlatformSelector* platformSelector = nullptr; + + // brand panels + HyundaiSettings* hyundaiSettings = nullptr; + + bool offroad = false; + +private slots: + void updateBrandSettings(); }; diff --git a/sunnypilot/selfdrive/car/interfaces.py b/sunnypilot/selfdrive/car/interfaces.py index 2c27e960e..f2019f5ed 100644 --- a/sunnypilot/selfdrive/car/interfaces.py +++ b/sunnypilot/selfdrive/car/interfaces.py @@ -11,6 +11,7 @@ from opendbc.car.car_helpers import can_fingerprint from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR from opendbc.car.hyundai.values import HyundaiFlags, DBC as HYUNDAI_DBC +from opendbc.sunnypilot.car.hyundai.longitudinal.helpers import LongitudinalTuningType from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP from openpilot.common.params import Params from openpilot.common.swaglog import cloudlog @@ -25,6 +26,21 @@ def log_fingerprint(CP: structs.CarParams) -> None: else: sentry.capture_fingerprint(CP.carFingerprint, CP.brand) +def _initialize_custom_longitudinal_tuning(CI: CarInterfaceBase, CP: structs.CarParams, CP_SP: structs.CarParamsSP, + params: Params = None) -> None: + if params is None: + params = Params() + + # Hyundai Custom Longitudinal Tuning + if CP.brand == 'hyundai': + hyundai_longitudinal_tuning = int(params.get("HyundaiLongitudinalTuning", encoding="utf8") or 0) + if hyundai_longitudinal_tuning == LongitudinalTuningType.DYNAMIC: + CP_SP.flags |= HyundaiFlagsSP.LONG_TUNING_DYNAMIC.value + if hyundai_longitudinal_tuning == LongitudinalTuningType.PREDICTIVE: + CP_SP.flags |= HyundaiFlagsSP.LONG_TUNING_PREDICTIVE.value + + CP_SP = CI.get_longitudinal_tuning_sp(CP, CP_SP) + def _initialize_neural_network_lateral_control(CI: CarInterfaceBase, CP: structs.CarParams, CP_SP: structs.CarParamsSP, params: Params = None, enabled: bool = False) -> None: @@ -61,10 +77,11 @@ def _initialize_radar_tracks(CP: structs.CarParams, CP_SP: structs.CarParamsSP, CP.radarUnavailable = False -def setup_interfaces(CI: CarInterfaceBase, params: Params = None): +def setup_interfaces(CI: CarInterfaceBase, params: Params = None) -> None: CP = CI.CP CP_SP = CI.CP_SP + _initialize_custom_longitudinal_tuning(CI, CP, CP_SP, params) _initialize_neural_network_lateral_control(CI, CP, CP_SP, params) _initialize_radar_tracks(CP, CP_SP, params) diff --git a/system/manager/manager.py b/system/manager/manager.py index fde85f0f7..90df415a8 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -45,6 +45,7 @@ def manager_init() -> None: ("AutoLaneChangeTimer", "0"), ("AutoLaneChangeBsmDelay", "0"), ("DynamicExperimentalControl", "0"), + ("HyundaiLongitudinalTuning", "0"), ("Mads", "1"), ("MadsMainCruiseAllowed", "1"), ("MadsPauseLateralOnBrake", "0"),