1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-24 16:55:24 +03:00

Merge pull request #1598 from IvoFPV/addtuningsliders

Add tuning sliders
This commit is contained in:
Michael Keller 2019-09-07 23:11:36 +12:00 committed by GitHub
commit fe08a7833e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 951 additions and 33 deletions

View file

@ -1,10 +1,12 @@
.tab-pid_tuning .profile .helpicon,
.tab-pid_tuning .rate_profile .helpicon {
.tab-pid_tuning .rate_profile .helpicon,
.tab-pid_tuning .pid_titlebar .helpicon {
background-image: url(../../images/icons/cf_icon_info_grey.svg);
opacity: 0.4;
}
.tab-pid_tuning .profile .helpicon:hover,
.tab-pid_tuning .rate_profile .helpicon:hover {
.tab-pid_tuning .rate_profile .helpicon:hover,
.tab-pid_tuning .pid_titlebar .helpicon:hover {
opacity: 1;
}
@ -221,6 +223,12 @@
border: 1px solid #9c9c9c;
}
.tab-pid_tuning .sliderLabels th {
background: #414443;
color: white;
border-right: solid 1px #9c9c9c;
}
.tab-pid_tuning input:disabled,
.tab-pid_tuning .cf input:disabled,
.tab-pid_tuning select:disabled,

View file

@ -740,6 +740,129 @@
width: 120px;
}
.tab-pid_tuning .tuningSlider {
-webkit-appearance: none;
width: calc(100% - 14px);
height: 15px;
border: none;
outline: none;
opacity: 0.8;
transition: opacity .2s;
margin: 7px;
background: none;
}
.tab-pid_tuning .tuningSlider:hover {
opacity: 1;
}
.tab-pid_tuning .tuningSlider::-webkit-slider-runnable-track {
-webkit-appearance: none;
background: rgba(0,255,0);
border: solid 1px silver;
border-radius: 4px;
background: linear-gradient(90deg, rgb(167, 255, 204) 0%, rgb(187, 252, 255) 50%, rgb(255, 90, 23) 100%);
height: 15px;
}
.tab-pid_tuning .tuningSlider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 23px;
height: 23px;
border-radius: 50%;
background: #ffbb2a;
border: solid 1px #828885;
cursor: pointer;
position: relative;
bottom: 5px;
}
.tab-pid_tuning .sliderLabels tr {
border-bottom: 1px solid #ccc;
}
.tab-pid_tuning .sliderLabels tr:last-child {
border-bottom: none;
}
.tab-pid_tuning .sliderLabels tr td:first-child {
text-align: right;
width: 20%;
}
.tab-pid_tuning .subtab-filter .sliderLabels tr td:first-child {
width: 10%;
}
.tab-pid_tuning .sliderLabels tr td:nth-child(2) {
text-align: center;
width: 30px;
}
.tab-pid_tuning .sliderLabels tr td:last-child {
width: 30px;
}
.tab-pid_tuning .tuningPIDSliders .pid_titlebar th,
.tab-pid_tuning .tuningFilterSliders .pid_titlebar th {
text-align: center;
}
.tab-pid_tuning .tuningPIDSliders .pid_titlebar th:first-child {
width: 20%;
border-right: none;
}
.tab-pid_tuning .tuningFilterSliders .pid_titlebar th:first-child {
width: 10%;
border-right: none;
}
.tab-pid_tuning .tuningPIDSliders .pid_titlebar th:nth-child(2),
.tab-pid_tuning .tuningFilterSliders .pid_titlebar th:nth-child(2) {
width: 30px;
}
.tab-pid_tuning .tuningPIDSliders .pid_titlebar th:last-child,
.tab-pid_tuning .tuningFilterSliders .pid_titlebar th:last-child {
width: 30px;
}
.tab-pid_tuning .slidersHighWarning,
.tab-pid_tuning .slidersFilterHighWarning {
background: #ff8a67;
border: 1px solid red;
font-weight: bold;
font-size: 12px;
}
.tab-pid_tuning .note-button td:nth-child(n) {
padding-left: 7px;
padding-right: 7px;
text-align: center;
}
.tab-pid_tuning .note-button td:first-child {
width: 75%;
border-right: none;
}
.tab-pid_tuning .note-button .regular-button {
display: block;
overflow-wrap: break-word;
margin: 2px;
}
.tab-pid_tuning .sliderLabels span {
color: black;
font-size: 12px;
}
.tab-pid_tuning .subtab-filter .sliderLabels input {
width: calc(100% - 14px);
box-sizing: content-box;
}
.tab-pid_tuning .subtab-rates {
display: flex;
flex-flow: row wrap;
@ -760,7 +883,7 @@
}
.tab-pid_tuning .subtab-pid .cf_column {
min-width: 470px;
min-width: 472px;
flex: 1;
}
@ -789,3 +912,13 @@
width: 100%;
}
}
.tab-pid_tuning .pid_titlebar .name-helpicon-flex {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
}
.tab-pid_tuning .pid_titlebar .name-helpicon-flex .helpicon {
margin-right: 0;
}

344
src/js/TuningSliders.js Normal file
View file

@ -0,0 +1,344 @@
'use strict';
var TuningSliders = {
MasterSliderValue: 1,
PDRatioSliderValue: 1,
PDGainSliderValue: 1,
ResponseSliderValue: 1,
pidSlidersUnavailable: false,
gyroFilterSliderValue: 1,
dtermFilterSliderValue: 1,
filterGyroSliderUnavailable: false,
filterDTermSliderUnavailable: false,
dMinFeatureEnabled: true,
defaultPDRatio: 0,
PID_DEFAULT: [],
FILTER_DEFAULT: {},
cachedPidSliderValues: false,
cachedGyroSliderValues: false,
cachedDTermSliderValues: false,
};
TuningSliders.initialize = function() {
this.PID_DEFAULT = FC.getPidDefaults();
this.FILTER_DEFAULT = FC.getFilterDefaults();
this.setDMinFeatureEnabled($('#dMinSwitch').is(':checked'));
this.initPidSlidersPosition();
this.initGyroFilterSliderPosition();
this.initDTermFilterSliderPosition();
// after refresh cached values are not available
this.cachedPidSliderValues = false;
this.cachedGyroSliderValues = false;
this.cachedDTermSliderValues = false;
this.updatePidSlidersDisplay();
this.updateFilterSlidersDisplay();
};
TuningSliders.setDMinFeatureEnabled = function(dMinFeatureEnabled) {
this.dMinFeatureEnabled = dMinFeatureEnabled;
if (this.dMinFeatureEnabled) {
this.defaultPDRatio = this.PID_DEFAULT[0] / this.PID_DEFAULT[2];
} else {
this.defaultPDRatio = this.PID_DEFAULT[0] / this.PID_DEFAULT[3];
}
};
TuningSliders.scaleSliderValue = function(value) {
if (value > 1) {
return Math.round(((value - 1) * 2 + 1) * 10) / 10;
} else {
return value;
}
};
TuningSliders.downscaleSliderValue = function(value) {
if (value > 1) {
return (value - 1) / 2 + 1;
} else {
return value;
}
};
TuningSliders.initPidSlidersPosition = function() {
// used to estimate PID slider positions based on PIDF values, and set respective slider position
// provides only an estimation due to limitation of feature without firmware support, to be improved in later versions
this.MasterSliderValue = Math.round(PIDs[2][0] / this.PID_DEFAULT[10] * 10) / 10;
this.PDRatioSliderValue = Math.round(PIDs[0][0] / PIDs[0][2] / this.defaultPDRatio * 10) / 10;
if (this.dMinFeatureEnabled) {
this.PDGainSliderValue = Math.round(ADVANCED_TUNING.dMinRoll / this.MasterSliderValue / this.PID_DEFAULT[3] * 10) / 10;
} else {
this.PDGainSliderValue = Math.round(PIDs[0][2] / this.MasterSliderValue / this.PID_DEFAULT[3] * 10) / 10;
}
this.ResponseSliderValue = Math.round(ADVANCED_TUNING.feedforwardRoll / this.MasterSliderValue / this.PID_DEFAULT[4] * 10) / 10;
$('output[name="tuningMasterSlider-number"]').val(this.MasterSliderValue);
$('output[name="tuningPDRatioSlider-number"]').val(this.PDRatioSliderValue);
$('output[name="tuningPDGainSlider-number"]').val(this.PDGainSliderValue);
$('output[name="tuningResponseSlider-number"]').val(this.ResponseSliderValue);
$('#tuningMasterSlider').val(this.downscaleSliderValue(this.MasterSliderValue));
$('#tuningPDRatioSlider').val(this.downscaleSliderValue(this.PDRatioSliderValue));
$('#tuningPDGainSlider').val(this.downscaleSliderValue(this.PDGainSliderValue));
$('#tuningResponseSlider').val(this.downscaleSliderValue(this.ResponseSliderValue));
};
TuningSliders.initGyroFilterSliderPosition = function() {
this.gyroFilterSliderValue = Math.round((FILTER_CONFIG.gyro_lowpass_dyn_min_hz + FILTER_CONFIG.gyro_lowpass2_hz) /
(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz + this.FILTER_DEFAULT.gyro_lowpass2_hz) * 100) / 100;
$('output[name="tuningGyroFilterSlider-number"]').val(this.gyroFilterSliderValue);
$('#tuningGyroFilterSlider').val(this.downscaleSliderValue(this.gyroFilterSliderValue));
};
TuningSliders.initDTermFilterSliderPosition = function() {
this.dtermFilterSliderValue = Math.round((FILTER_CONFIG.dterm_lowpass_dyn_min_hz + FILTER_CONFIG.dterm_lowpass_dyn_max_hz + FILTER_CONFIG.dterm_lowpass2_hz) /
(this.FILTER_DEFAULT.dterm_lowpass_dyn_min_hz + this.FILTER_DEFAULT.dterm_lowpass_dyn_max_hz + this.FILTER_DEFAULT.dterm_lowpass2_hz) * 100) / 100;
$('output[name="tuningDTermFilterSlider-number"]').val(this.dtermFilterSliderValue);
$('#tuningDTermFilterSlider').val(this.downscaleSliderValue(this.dtermFilterSliderValue));
};
TuningSliders.resetPidSliders = function() {
if (!this.cachedPidSliderValues) {
$('#tuningMasterSlider').val(1);
$('#tuningPDRatioSlider').val(1);
$('#tuningPDGainSlider').val(1);
$('#tuningResponseSlider').val(1);
this.MasterSliderValue = 1;
this.PDRatioSliderValue = 1;
this.PDGainSliderValue = 1;
this.ResponseSliderValue = 1;
}
this.calculateNewPids();
this.updatePidSlidersDisplay();
};
TuningSliders.resetGyroFilterSlider = function() {
if (!this.cachedGyroSliderValues) {
$('#tuningGyroFilterSlider').val(1);
this.gyroFilterSliderValue = 1;
}
this.calculateNewGyroFilters();
this.updateFilterSlidersDisplay();
};
TuningSliders.resetDTermFilterSlider = function() {
if (!this.cachedDTermSliderValues) {
$('#tuningDTermFilterSlider').val(1);
this.dtermFilterSliderValue = 1;
}
this.calculateNewDTermFilters();
this.updateFilterSlidersDisplay();
};
TuningSliders.updatePidSlidersDisplay = function() {
// check if pid values changed manually by saving current values, doing the slider based calculation, and comaparing
// if values before and after calculation, if all of them are equal the values haven't been changed manually
// and the sliders are shown, otherwise sliders are grayed out and centered
const WARNING_P_GAIN = 110;
const WARNING_I_GAIN = 120;
const WARNING_DMAX_GAIN = 70;
const WARNING_DMIN_GAIN = 40;
this.pidSlidersUnavailable = false;
let currentPIDs = [];
PID_names.forEach(function(elementPid, indexPid) {
let searchRow = $('.pid_tuning .' + elementPid + ' input');
searchRow.each(function (indexInput) {
if (indexPid < 3 && indexInput < 5) {
currentPIDs.push($(this).val());
}
});
});
this.calculateNewPids();
PID_names.forEach(function(elementPid, indexPid) {
let searchRow = $('.pid_tuning .' + elementPid + ' input');
searchRow.each(function (indexInput) {
if (indexPid < 3 && indexInput < 5) {
if (currentPIDs[indexPid * 5 + indexInput] != $(this).val()) {
TuningSliders.pidSlidersUnavailable = true;
}
$(this).val(currentPIDs[indexPid * 5 + indexInput]);
}
});
});
if ($('input[id="useIntegratedYaw"]').is(':checked')) {
this.pidSlidersUnavailable = true;
}
if (this.pidSlidersUnavailable) {
$('.tuningPIDSliders').hide();
$('.slidersDisabled').show();
} else {
$('.tuningPIDSliders').show();
$('.slidersDisabled').hide();
this.cachedPidSliderValues = true;
}
if ((PIDs[1][0] > WARNING_P_GAIN || PIDs[1][1] > WARNING_I_GAIN || PIDs[1][2] > WARNING_DMAX_GAIN || ADVANCED_TUNING.dMinPitch > WARNING_DMIN_GAIN) && !this.pidSlidersUnavailable) {
$('.slidersHighWarning').show();
} else {
$('.slidersHighWarning').hide();
}
};
TuningSliders.updateFilterSlidersDisplay = function() {
// check if filters changed manually by comapring current value and those based on slider position
// if equal filter slider is shown, otherwise it is grayed out and centered
const WARNING_FILTER_GAIN = 1.4;
this.filterGyroSliderUnavailable = false;
this.filterDTermSliderUnavailable = false;
if ($('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val() != Math.round(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz * this.gyroFilterSliderValue) ||
$('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val() != Math.round(this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz * this.gyroFilterSliderValue) ||
$('.pid_filter select[name="gyroLowpassDynType"]').val() != this.FILTER_DEFAULT.gyro_lowpass_type ||
$('.pid_filter input[name="gyroLowpass2Frequency"]').val() != Math.round(this.FILTER_DEFAULT.gyro_lowpass2_hz * this.gyroFilterSliderValue) ||
$('.pid_filter select[name="gyroLowpass2Type"]').val() != this.FILTER_DEFAULT.gyro_lowpass2_type) {
$('.tuningFilterSliders .sliderLabels tr:first-child').hide();
this.filterGyroSliderUnavailable = true;
} else {
$('.tuningFilterSliders .sliderLabels tr:first-child').show()
this.cachedGyroSliderValues = true;
}
if ($('.pid_filter input[name="dtermLowpassDynMinFrequency"]').val() != Math.round(this.FILTER_DEFAULT.dterm_lowpass_dyn_min_hz * this.dtermFilterSliderValue) ||
$('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').val() != Math.round(this.FILTER_DEFAULT.dterm_lowpass_dyn_max_hz * this.dtermFilterSliderValue) ||
$('.pid_filter select[name="dtermLowpassDynType"]').val() != this.FILTER_DEFAULT.dterm_lowpass_type ||
$('.pid_filter input[name="dtermLowpass2Frequency"]').val() != Math.round(this.FILTER_DEFAULT.dterm_lowpass2_hz * this.dtermFilterSliderValue) ||
$('.pid_filter select[name="dtermLowpass2Type"]').val() != this.FILTER_DEFAULT.dterm_lowpass2_type) {
$('.tuningFilterSliders .sliderLabels tr:last-child').hide();
this.filterDTermSliderUnavailable = true;
} else {
$('.tuningFilterSliders .sliderLabels tr:last-child').show();
this.cachedDTermSliderValues = true;
}
if (this.filterGyroSliderUnavailable && this.filterDTermSliderUnavailable) {
$('.tuningFilterSliders').hide();
} else {
$('.tuningFilterSliders').show();
}
if (this.filterGyroSliderUnavailable || this.filterDTermSliderUnavailable) {
$('.slidersFilterDisabled').show();
} else {
$('.slidersFilterDisabled').hide();
}
if ((this.gyroFilterSliderValue >= WARNING_FILTER_GAIN && !this.filterGyroSliderUnavailable) || (this.dtermFilterSliderValue >= WARNING_FILTER_GAIN && !this.filterDTermSliderUnavailable)) {
$('.slidersFilterHighWarning').show();
} else {
$('.slidersFilterHighWarning').hide();
}
};
TuningSliders.calculateNewPids = function() {
// this is the main calculation for PID sliders, inputs are in form of slider position values
// values get set both into forms and their respective variables
if (this.dMinFeatureEnabled) {
//dmin
ADVANCED_TUNING.dMinRoll = Math.round(this.PID_DEFAULT[3] * this.PDGainSliderValue);
ADVANCED_TUNING.dMinPitch = Math.round(this.PID_DEFAULT[8] * this.PDGainSliderValue);
// dmax
PIDs[0][2] = Math.round(this.PID_DEFAULT[2] * this.PDGainSliderValue);
PIDs[1][2] = Math.round(this.PID_DEFAULT[7] * this.PDGainSliderValue);
} else {
ADVANCED_TUNING.dMinRoll = 0;
ADVANCED_TUNING.dMinPitch = 0;
PIDs[0][2] = Math.round(this.PID_DEFAULT[3] * this.PDGainSliderValue);
PIDs[1][2] = Math.round(this.PID_DEFAULT[8] * this.PDGainSliderValue);
}
// p
PIDs[0][0] = Math.round(PIDs[0][2] * this.defaultPDRatio * this.PDRatioSliderValue);
PIDs[1][0] = Math.round(PIDs[1][2] * this.defaultPDRatio * this.PDRatioSliderValue);
// ff
ADVANCED_TUNING.feedforwardRoll = Math.round(this.PID_DEFAULT[4] * this.ResponseSliderValue);
ADVANCED_TUNING.feedforwardPitch = Math.round(this.PID_DEFAULT[9] * this.ResponseSliderValue);
ADVANCED_TUNING.feedforwardYaw = Math.round(this.PID_DEFAULT[14] * ((this.ResponseSliderValue - 1) / 3 + 1));
// master slider part
// these are not calculated anywhere other than master slider multiplier therefore set at default before every calculation
PIDs[0][1] = this.PID_DEFAULT[1];
PIDs[1][1] = this.PID_DEFAULT[6];
PIDs[2][1] = this.PID_DEFAULT[11];
// yaw p,d, dmin
PIDs[2][0] = this.PID_DEFAULT[10];
PIDs[2][2] = this.PID_DEFAULT[12];
ADVANCED_TUNING.dMinYaw = this.PID_DEFAULT[13];
//master slider multiplication, max value 200 for main PID values
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
PIDs[j][i] = Math.min(Math.round(PIDs[j][i] * this.MasterSliderValue), 200);
}
}
ADVANCED_TUNING.feedforwardRoll = Math.round(ADVANCED_TUNING.feedforwardRoll * this.MasterSliderValue);
ADVANCED_TUNING.feedforwardPitch = Math.round(ADVANCED_TUNING.feedforwardPitch * this.MasterSliderValue);
ADVANCED_TUNING.feedforwardYaw = Math.round(ADVANCED_TUNING.feedforwardYaw * this.MasterSliderValue);
if (this.dMinFeatureEnabled) {
ADVANCED_TUNING.dMinRoll = Math.round(ADVANCED_TUNING.dMinRoll * this.MasterSliderValue);
ADVANCED_TUNING.dMinPitch = Math.round(ADVANCED_TUNING.dMinPitch * this.MasterSliderValue);
ADVANCED_TUNING.dMinYaw = Math.round(ADVANCED_TUNING.dMinYaw * this.MasterSliderValue);
}
$('output[name="tuningMasterSlider-number"]').val(this.MasterSliderValue);
$('output[name="tuningPDRatioSlider-number"]').val(this.PDRatioSliderValue);
$('output[name="tuningPDGainSlider-number"]').val(this.PDGainSliderValue);
$('output[name="tuningResponseSlider-number"]').val(this.ResponseSliderValue);
// updates values in forms
PID_names.forEach(function(elementPid, indexPid) {
let searchRow = $('.pid_tuning .' + elementPid + ' input');
searchRow.each(function (indexInput) {
if (indexPid < 3) {
$(this).val(PIDs[indexPid][indexInput]);
}
});
});
$('.pid_tuning input[name="dMinRoll"]').val(ADVANCED_TUNING.dMinRoll);
$('.pid_tuning input[name="dMinPitch"]').val(ADVANCED_TUNING.dMinPitch);
$('.pid_tuning input[name="dMinYaw"]').val(ADVANCED_TUNING.dMinYaw);
$('.pid_tuning .ROLL input[name="f"]').val(ADVANCED_TUNING.feedforwardRoll);
$('.pid_tuning .PITCH input[name="f"]').val(ADVANCED_TUNING.feedforwardPitch);
$('.pid_tuning .YAW input[name="f"]').val(ADVANCED_TUNING.feedforwardYaw);
};
TuningSliders.calculateNewGyroFilters = function() {
// calculate, set and display new values in forms based on slider position
FILTER_CONFIG.gyro_lowpass_dyn_min_hz = Math.round(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz * this.gyroFilterSliderValue);
FILTER_CONFIG.gyro_lowpass_dyn_max_hz = Math.round(this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz * this.gyroFilterSliderValue);
FILTER_CONFIG.gyro_lowpass2_hz = Math.round(this.FILTER_DEFAULT.gyro_lowpass2_hz * this.gyroFilterSliderValue);
FILTER_CONFIG.gyro_lowpass_type = this.FILTER_DEFAULT.gyro_lowpass_type;
FILTER_CONFIG.gyro_lowpass2_type = this.FILTER_DEFAULT.gyro_lowpass2_type;
$('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val(FILTER_CONFIG.gyro_lowpass_dyn_min_hz);
$('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val(FILTER_CONFIG.gyro_lowpass_dyn_max_hz);
$('.pid_filter input[name="gyroLowpass2Frequency"]').val(FILTER_CONFIG.gyro_lowpass2_hz);
$('.pid_filter select[name="gyroLowpassDynType').val(FILTER_CONFIG.gyro_lowpass_type);
$('.pid_filter select[name="gyroLowpass2Type').val(FILTER_CONFIG.gyro_lowpass2_type);
$('output[name="tuningGyroFilterSlider-number"]').val(this.gyroFilterSliderValue);
};
TuningSliders.calculateNewDTermFilters = function() {
// calculate, set and display new values in forms based on slider position
FILTER_CONFIG.dterm_lowpass_dyn_min_hz = Math.round(this.FILTER_DEFAULT.dterm_lowpass_dyn_min_hz * this.dtermFilterSliderValue);
FILTER_CONFIG.dterm_lowpass_dyn_max_hz = Math.round(this.FILTER_DEFAULT.dterm_lowpass_dyn_max_hz * this.dtermFilterSliderValue);
FILTER_CONFIG.dterm_lowpass2_hz = Math.round(this.FILTER_DEFAULT.dterm_lowpass2_hz * this.dtermFilterSliderValue);
FILTER_CONFIG.dterm_lowpass_type = this.FILTER_DEFAULT.dterm_lowpass_type;
FILTER_CONFIG.dterm_lowpass2_type = this.FILTER_DEFAULT.dterm_lowpass2_type;
$('.pid_filter input[name="dtermLowpassDynMinFrequency"]').val(FILTER_CONFIG.dterm_lowpass_dyn_min_hz);
$('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').val(FILTER_CONFIG.dterm_lowpass_dyn_max_hz);
$('.pid_filter input[name="dtermLowpass2Frequency"]').val(FILTER_CONFIG.dterm_lowpass2_hz);
$('.pid_filter select[name="dtermLowpassDynType').val(FILTER_CONFIG.dterm_lowpass_type);
$('.pid_filter select[name="dtermLowpass2Type').val(FILTER_CONFIG.dterm_lowpass2_type);
$('output[name="tuningDTermFilterSlider-number"]').val(this.dtermFilterSliderValue);
};

View file

@ -64,6 +64,7 @@ var VTXTABLE_BAND;
var VTXTABLE_POWERLEVEL;
var MULTIPLE_MSP;
var DEFAULT;
var DEFAULT_PIDS;
var FC = {
resetState: function () {
@ -559,6 +560,12 @@ var FC = {
dterm_notch_hz: 260,
yaw_lowpass_hz: 100,
};
DEFAULT_PIDS = [
42, 85, 35, 20, 90,
46, 90, 38, 22, 95,
30, 90, 0, 0, 90,
];
},
getHardwareName: function () {
@ -633,7 +640,27 @@ var FC = {
versionFilterDefaults.dterm_lowpass_type = FC.FILTER_TYPE_FLAGS.BIQUAD;
versionFilterDefaults.dterm_lowpass2_hz = 150;
versionFilterDefaults.dterm_lowpass2_type = FC.FILTER_TYPE_FLAGS.BIQUAD;
}
if (semver.gte(CONFIG.apiVersion, "1.42.0")) {
versionFilterDefaults.gyro_lowpass_hz = 200;
versionFilterDefaults.gyro_lowpass_dyn_min_hz = 200;
versionFilterDefaults.gyro_lowpass_dyn_max_hz = 500;
versionFilterDefaults.gyro_lowpass_type = FC.FILTER_TYPE_FLAGS.PT1;
versionFilterDefaults.gyro_lowpass2_hz = 250;
versionFilterDefaults.gyro_lowpass2_type = FC.FILTER_TYPE_FLAGS.PT1;
versionFilterDefaults.dterm_lowpass_hz = 150;
versionFilterDefaults.dterm_lowpass_dyn_min_hz = 70;
versionFilterDefaults.dterm_lowpass_dyn_max_hz = 170;
versionFilterDefaults.dterm_lowpass_type = FC.FILTER_TYPE_FLAGS.PT1;
versionFilterDefaults.dterm_lowpass2_hz = 150;
versionFilterDefaults.dterm_lowpass2_type = FC.FILTER_TYPE_FLAGS.PT1;
}
}
return versionFilterDefaults;
},
getPidDefaults: function() {
var versionPidDefaults = DEFAULT_PIDS;
// if defaults change they should go here
return versionPidDefaults;
},
};

View file

@ -271,8 +271,6 @@ TABS.pid_tuning.initialize = function (callback) {
var feedforwardTransitionNumberElement = $('input[name="feedforwardTransition-number"]');
feedforwardTransitionNumberElement.val(ADVANCED_TUNING.feedforwardTransition / 100);
$('.helpicon[i18n_title="pidTuningPidTuningTip"]').hide();
// AntiGravity Mode
var antiGravityModeSelect = $('.antigravity select[id="antiGravityMode"]');
antiGravityModeSelect.change(function () {
@ -300,7 +298,6 @@ TABS.pid_tuning.initialize = function (callback) {
// Feedforward column
$('#pid_main tr :nth-child(6)').hide();
$('.helpicon[i18n_title="pidTuningPidTuningTipFeedforward"]').hide();
$('#pid-tuning .feedforwardTransition').hide();
}
@ -354,11 +351,9 @@ TABS.pid_tuning.initialize = function (callback) {
$('.pid_filter input[name="dynamicNotchQ"]').val(FILTER_CONFIG.dyn_notch_q);
$('.pid_filter input[name="dynamicNotchMinHz"]').val(FILTER_CONFIG.dyn_notch_min_hz);
$('.helpicon[i18n_title="pidTuningPidTuningTipFeedforward"]').hide();
} else {
$('.itermRelaxCutoff').hide();
$('.dynamicNotch').hide();
$('.helpicon[i18n_title="pidTuningPidTuningTipDMin"]').hide();
}
$('input[id="useIntegratedYaw"]').change(function() {
@ -413,18 +408,14 @@ TABS.pid_tuning.initialize = function (callback) {
$('.dminGroup .suboption').show();
$('#pid_main tr :nth-child(5)').show();
$('#pid_main .pid_titlebar2 th').attr('colspan', 6);
$('.helpicon[i18n_title="pidTuningPidTuningTipFeedforward"]').hide();
$('.helpicon[i18n_title="pidTuningPidTuningTipDMin"]').show();
} else {
$('.pid_tuning input[name="dMinRoll"]').val(0);
$('.pid_tuning input[name="dMinPitch"]').val(0);
$('.pid_tuning input[name="dMinYaw"]').val(0);
$('.dminGroup .suboption').hide();
$('.dMinDisabledNote').show();
$('.dminGroup .suboption').hide();
$('#pid_main tr :nth-child(5)').hide();
$('#pid_main .pid_titlebar2 th').attr('colspan', 5);
$('.helpicon[i18n_title="pidTuningPidTuningTipFeedforward"]').show();
$('.helpicon[i18n_title="pidTuningPidTuningTipDMin"]').hide();
}
});
dMinSwitch.change();
@ -1413,6 +1404,152 @@ TABS.pid_tuning.initialize = function (callback) {
$('.copyrateprofilebtn').hide();
}
if (semver.gte(CONFIG.apiVersion, "1.42.0")) {
// filter and tuning sliders
TuningSliders.initialize();
$('#dMinSwitch').change(function() {
TuningSliders.setDMinFeatureEnabled($(this).is(':checked'));
// switch dmin and dmax values on dmin on/off if sliders available
if (!TuningSliders.pidSlidersUnavailable) {
if (TuningSliders.dMinFeatureEnabled) {
ADVANCED_TUNING.dMinRoll = PIDs[0][2];
ADVANCED_TUNING.dMinPitch = PIDs[1][2];
ADVANCED_TUNING.dMinYaw = PIDs[2][2];
} else {
PIDs[0][2] = ADVANCED_TUNING.dMinRoll;
PIDs[1][2] = ADVANCED_TUNING.dMinPitch;
PIDs[2][2] = ADVANCED_TUNING.dMinYaw;
}
TuningSliders.calculateNewPids();
}
});
// integrated yaw doesn't work with sliders therefore sliders are disabled
$('input[id="useIntegratedYaw"]').change(() => TuningSliders.updatePidSlidersDisplay());
// pid sliders inputs
$('#tuningMasterSlider, #tuningPDRatioSlider, #tuningPDGainSlider, #tuningResponseSlider').on('input', function() {
const slider = $(this);
// adjust step for more smoothness above 1x
if (slider.val() >= 1) {
slider.attr('step', 0.05);
} else {
slider.attr('step', 0.1);
}
const scaledValue = TuningSliders.scaleSliderValue(slider.val());
if (slider.is('#tuningMasterSlider')) {
TuningSliders.MasterSliderValue = scaledValue;
} else if (slider.is('#tuningPDRatioSlider')) {
TuningSliders.PDRatioSliderValue = scaledValue;
} else if (slider.is('#tuningPDGainSlider')) {
TuningSliders.PDGainSliderValue = scaledValue;
} else if (slider.is('#tuningResponseSlider')) {
TuningSliders.ResponseSliderValue = scaledValue;
}
TuningSliders.calculateNewPids();
});
$('#tuningMasterSlider, #tuningPDRatioSlider, #tuningPDGainSlider, #tuningResponseSlider').mousedown(function() {
// adjust step for more smoothness above 1x on mousedown
const slider = $(this);
if (slider.val() >= 1) {
slider.attr('step', 0.05);
} else {
slider.attr('step', 0.1);
}
});
$('#tuningMasterSlider, #tuningPDRatioSlider, #tuningPDGainSlider, #tuningResponseSlider').mouseup(function() {
// readjust dmin maximums
$('.pid_tuning .ROLL input[name="d"]').change();
$('.pid_tuning .PITCH input[name="d"]').change();
$('.pid_tuning .YAW input[name="d"]').change();
TuningSliders.updatePidSlidersDisplay();
});
// reset to middle with double click
$('#tuningMasterSlider, #tuningPDRatioSlider, #tuningPDGainSlider, #tuningResponseSlider').dblclick(function() {
const slider = $(this);
slider.val(1);
if (slider.is('#tuningMasterSlider')) {
TuningSliders.MasterSliderValue = 1;
} else if (slider.is('#tuningPDRatioSlider')) {
TuningSliders.PDRatioSliderValue = 1;
} else if (slider.is('#tuningPDGainSlider')) {
TuningSliders.PDGainSliderValue = 1;
} else if (slider.is('#tuningResponseSlider')) {
TuningSliders.ResponseSliderValue = 1;
}
TuningSliders.calculateNewPids();
TuningSliders.updatePidSlidersDisplay();
});
// enable PID sliders button
$('a.buttonPidTuningSliders').click(function() {
// if values were previously changed manually and then sliders are reactivated, reset pids to previous valid values if available, else default
TuningSliders.resetPidSliders();
// disable integrated yaw when enabling sliders
if ($('input[id="useIntegratedYaw"]').is(':checked')) {
$('input[id="useIntegratedYaw"]').prop('checked', true).click();
}
});
// filter slider inputs
$('#tuningGyroFilterSlider, #tuningDTermFilterSlider').on('input', function() {
const slider = $(this);
const scaledValue = TuningSliders.scaleSliderValue(slider.val());
if (slider.is('#tuningGyroFilterSlider')) {
TuningSliders.gyroFilterSliderValue = scaledValue;
TuningSliders.calculateNewGyroFilters();
} else if (slider.is('#tuningDTermFilterSlider')) {
TuningSliders.dtermFilterSliderValue = scaledValue;
TuningSliders.calculateNewDTermFilters();
}
});
$('#tuningGyroFilterSlider, #tuningDTermFilterSlider').mouseup(function() {
TuningSliders.updateFilterSlidersDisplay();
});
// reset to middle with double click
$('#tuningGyroFilterSlider, #tuningDTermFilterSlider').dblclick(function() {
const slider = $(this);
slider.val(1);
if (slider.is('#tuningGyroFilterSlider')) {
TuningSliders.gyroFilterSliderValue = 1;
TuningSliders.calculateNewGyroFilters();
} else if (slider.is('#tuningDTermFilterSlider')) {
TuningSliders.dtermFilterSliderValue = 1;
TuningSliders.calculateNewDTermFilters();
}
TuningSliders.updateFilterSlidersDisplay();
});
// enable PID sliders button
$('a.buttonFilterTuningSliders').click(function() {
if (TuningSliders.filterGyroSliderUnavailable) {
// update switchery dynamically based on defaults
$('input[id="gyroLowpassDynEnabled"]').prop('checked', false).click();
$('input[id="gyroLowpassEnabled"]').prop('checked', true).click();
$('input[id="gyroLowpass2Enabled"]').prop('checked', false).click();
TuningSliders.resetGyroFilterSlider();
}
if (TuningSliders.filterDTermSliderUnavailable) {
$('input[id="dtermLowpassDynEnabled"]').prop('checked', false).click();
$('input[id="dtermLowpassEnabled"]').prop('checked', true).click();
$('input[id="dtermLowpass2Enabled"]').prop('checked', false).click();
TuningSliders.resetDTermFilterSlider();
}
});
// update on pid table inputs
$('#pid_main input').on('input', () => TuningSliders.updatePidSlidersDisplay());
// update on filter value or type changes
$('.pid_filter input, .pid_filter select').on('input', () => TuningSliders.updateFilterSlidersDisplay());
// update on filter switch changes
$('.inputSwitch input').change(() => TuningSliders.updateFilterSlidersDisplay());
} else {
$('.tuningPIDSliders').hide();
$('.slidersDisabled').hide();
$('.slidersHighWarning').hide();
$('.tuningFilterSliders').hide();
$('.slidersFilterDisabled').hide();
$('.slidersFilterHighWarning').hide();
}
if (semver.gte(CONFIG.apiVersion, "1.16.0")) {
$('#pid-tuning .delta select').change(function() {
self.setDirty(true);

View file

@ -172,6 +172,7 @@
<script type="text/javascript" src="./js/CliAutoComplete.js"></script>
<script type="text/javascript" src="./js/DarkTheme.js"></script>
<script type="text/javascript" src="./js/ConfigInserter.js"></script>
<script type="text/javascript" src="./js/TuningSliders.js"></script>
<title i18n="windowTitle"></title>
</head>
<body>

View file

@ -71,23 +71,48 @@
<div class="note dMinDisabledNote">
<p i18n="pidTuningDMinDisabledNote"></p>
</div>
<div class="note slidersHighWarning">
<p i18n="pidTuningSliderHighWarning"></p>
</div>
<div class="gui_box grey">
<table id="pid_main" class="pid_tuning">
<tr class="pid_titlebar">
<th class="name"></th>
<th class="proportional" i18n="pidTuningProportional"></th>
<th class="integral" i18n="pidTuningIntegral"></th>
<th class="derivative" i18n="pidTuningDerivative"></th>
<th class="dmin" i18n="pidTuningDMin"></th>
<th class="feedforward" i18n="pidTuningFeedforward"></th>
<th class="proportional">
<div class="name-helpicon-flex">
<div i18n="pidTuningProportional"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningProportionalHelp"></div>
</div>
</th>
<th class="integral">
<div class="name-helpicon-flex">
<div i18n="pidTuningIntegral"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningIntegralHelp"></div>
</div>
</th>
<th class="derivative">
<div class="name-helpicon-flex">
<div i18n="pidTuningDerivative"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningDerivativeHelp"></div>
</div>
</th>
<th class="dmin">
<div class="name-helpicon-flex">
<div i18n="pidTuningDMin"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningDMinHelp"></div>
</div>
</th>
<th class="feedforward">
<div class="name-helpicon-flex">
<div i18n="pidTuningFeedforward"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningFeedforwardHelp"></div>
</div>
</th>
</tr>
<tr class="pid_titlebar2">
<th colspan="6">
<div class="pid_mode">
<div i18n="pidTuningBasic" style="float:left;"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningPidTuningTip"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningPidTuningTipFeedforward"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningPidTuningTipDMin"></div>
</div>
</th>
</tr>
@ -132,6 +157,89 @@
</table>
</div>
<div class="gui_box slidersDisabled">
<table class="note-button">
<td i18n="pidTuningSlidersDisabled"></td>
<td>
<a href="#" class="buttonPidTuningSliders regular-button" i18n="pidTuningSliderEnableButton"></a>
</td>
</table>
</div>
<!-- TUNING SLIDERS-->
<div class="gui_box grey topspacer tuningPIDSliders">
<table class="pid_titlebar">
<tr>
<th></th>
<th></th>
<th i18n="pidTuningSliderLow"></th>
<th i18n="pidTuningSliderDefault"></th>
<th i18n="pidTuningSliderHigh"></th>
<th>
<div class="helpicon cf_tip" i18n_title="pidTuningPidSlidersHelp"></div>
</th>
</tr>
</table>
<table class="sliderLabels">
<tr>
<td>
<span i18n="pidTuningMasterSlider"/>
</td>
<td>
<output type="number" name="tuningMasterSlider-number"></output>
</td>
<td colspan="3">
<input type="range" min="0.5" max="1.5" step="0.05" class="tuningSlider" id="tuningMasterSlider" />
</td>
<td>
<div class="helpicon cf_tip" i18n_title="pidTuningMasterSliderHelp"></div>
</td>
</tr>
<tr>
<td>
<span i18n="pidTuningPDRatioSlider"/>
</td>
<td>
<output type="number" name="tuningPDRatioSlider-number"></output>
</td>
<td colspan="3">
<input type="range" min="0.5" max="1.5" step="0.05" class="tuningSlider" id="tuningPDRatioSlider" />
</td>
<td>
<div class="helpicon cf_tip" i18n_title="pidTuningPDRatioSliderHelp"></div>
</td>
</tr>
<tr>
<td>
<span i18n="pidTuningPDGainSlider"/>
</td>
<td>
<output type="number" name="tuningPDGainSlider-number"></output>
</td>
<td colspan="3">
<input type="range" min="0.5" max="1.5" step="0.05" class="tuningSlider" id="tuningPDGainSlider" />
</td>
<td>
<div class="helpicon cf_tip" i18n_title="pidTuningPDGainSliderHelp"></div>
</td>
</tr>
<tr>
<td>
<span i18n="pidTuningResponseSlider"/>
</td>
<td>
<output type="number" name="tuningResponseSlider-number"></output>
</td>
<td colspan="3">
<input type="range" min="0.5" max="1.5" step="0.05" class="tuningSlider" id="tuningResponseSlider" />
</td>
<td>
<div class="helpicon cf_tip" i18n_title="pidTuningResponseSliderHelp"></div>
</td>
</tr>
</table>
</div>
<!-- BARO, MAG, GPS -->
<div id="pid_baro_mag_gps" class="pid_optional needed_by_ALT needed_by_VEL needed_by_MAG needed_by_Pos needed_by_PosR needed_by_NavR gui_box grey topspacer pid_tuning">
<table class="pid_titlebar needed_by_ALT needed_by_VEL needed_by_MAG">
@ -462,7 +570,7 @@
<tr class="dminGroup">
<td><input type="checkbox" id="dMinSwitch" class="toggle" /></td>
<td colspan="3">
<div class="helpicon cf_tip" i18n_title="pidTuningDMinHelp"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningDMinFeatureHelp"></div>
<span>
<label for="dminGroup">
<span i18n="pidTuningDMin" />
@ -742,6 +850,63 @@
<div class="note dynamicNotchWarning">
<p i18n="pidTuningDynamicNotchFilterDisabledWarning"></p>
</div>
<div class="note slidersFilterHighWarning">
<p i18n="pidTuningSliderHighWarning"></p>
</div>
<div class="gui_box slidersFilterDisabled">
<table class="note-button">
<td i18n="pidTuningSlidersDisabled"></td>
<td>
<a href="#" class="buttonFilterTuningSliders regular-button" i18n="pidTuningSliderEnableButton"></a>
</td>
</table>
</div>
<!-- Filter Slider -->
<div class="gui_box grey topspacer tuningFilterSliders">
<table class="pid_titlebar">
<tr>
<th></th>
<th></th>
<th i18n="pidTuningSliderHighFiltering"></th>
<th i18n="pidTuningSliderDefaultFiltering"></th>
<th i18n="pidTuningSliderLowFiltering"></th>
<th>
<div class="helpicon cf_tip" i18n_title="pidTuningFilterSlidersHelp"></div>
</th>
</tr>
</table>
<table class="sliderLabels">
<tr>
<td>
<span i18n="pidTuningGyroFilterSlider"/>
</td>
<td>
<output type="number" name="tuningGyroFilterSlider-number"></output>
</td>
<td colspan="3">
<input type="range" min="0.5" max="1.5" step="0.05" class="tuningSlider" id="tuningGyroFilterSlider" />
</td>
<td>
<div class="helpicon cf_tip" i18n_title="pidTuningGyroFilterSliderHelp"></div>
</td>
</tr>
<tr>
<td>
<span i18n="pidTuningDTermFilterSlider"/>
</td>
<td>
<output type="number" name="tuningDTermFilterSlider-number"></output>
</td>
<td colspan="3">
<input type="range" min="0.5" max="1.5" step="0.05" class="tuningSlider" id="tuningDTermFilterSlider" />
</td>
<td>
<div class="helpicon cf_tip" i18n_title="pidTuningDTermFilterSliderHelp"></div>
</td>
</tr>
</table>
</div>
<div class="cf_column two_columns">
<div class="gui_box grey topspacer pid_filter two_columns_first">