1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-25 09:15:49 +03:00

Merge branch 'master' into fix_tab_switch

This commit is contained in:
haslinghuis 2021-11-26 02:49:56 +01:00 committed by GitHub
commit a45cc1d8c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 4438 additions and 561 deletions

View file

@ -5,30 +5,31 @@
const ConfigStorage = {
// key can be one string, or array of strings
get: function(key, callback) {
let result = {};
if (Array.isArray(key)) {
let obj = {};
key.forEach(function (element) {
try {
obj = {...obj, ...JSON.parse(window.localStorage.getItem(element))};
result = {...result, ...JSON.parse(window.localStorage.getItem(element))};
} catch (e) {
// is okay
}
});
callback(obj);
callback?.(result);
} else {
const keyValue = window.localStorage.getItem(key);
if (keyValue) {
let obj = {};
try {
obj = JSON.parse(keyValue);
result = JSON.parse(keyValue);
} catch (e) {
// It's fine if we fail that parse
}
callback(obj);
callback?.(result);
} else {
callback({});
callback?.(result);
}
}
return result;
},
// set takes an object like {'userLanguageSelect':'DEFAULT'}
set: function(input) {

View file

@ -37,6 +37,9 @@ const TuningSliders = {
cachedGyroSliderValues: false,
cachedDTermSliderValues: false,
sliderGyroFilterDisabled: false,
sliderDTermFilterDisabled: false,
expertMode: false,
};
@ -72,7 +75,25 @@ TuningSliders.initialize = function() {
this.cachedDTermSliderValues = false;
this.updatePidSlidersDisplay();
this.updateFilterSlidersDisplay();
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
// if sliders are enabled on initialization tuning has not yet updated values according to sliders.
if (!FC.TUNING_SLIDERS.slider_gyro_filter) {
this.updateFilterSlidersDisplay();
}
if (!FC.TUNING_SLIDERS.slider_dterm_filter) {
this.updateFilterSlidersDisplay();
}
this.updateFilterSlidersWarning();
$('.subtab-filter .slidersDisabled').hide();
} else {
this.updateFilterSlidersDisplay();
$('select[id="sliderGyroFilterModeSelect"]').hide();
$('select[id="sliderDTermFilterModeSelect"]').hide();
}
};
TuningSliders.updateExpertModeSlidersDisplay = function() {
@ -109,6 +130,8 @@ TuningSliders.updateExpertModeSlidersDisplay = function() {
$('#sliderPitchPIGain').prop('disabled', !this.expertMode);
$('#sliderMasterMultiplier').prop('disabled', !this.expertMode);
$('.sliderGyroFilter').prop('disabled', gyro && !this.expertMode);
$('.sliderDTermFilter').prop('disabled', dterm && !this.expertMode);
$('#sliderGyroFilterMultiplier').prop('disabled', gyro && !this.expertMode);
$('#sliderDTermFilterMultiplier').prop('disabled', dterm && !this.expertMode);
@ -118,9 +141,6 @@ TuningSliders.updateExpertModeSlidersDisplay = function() {
$('.advancedSlider').toggleClass('disabledSliders', !this.expertMode);
$('.sliderGyroFilter').toggleClass('disabledSliders', gyro && !this.expertMode);
$('.sliderDtermFilter').toggleClass('disabledSliders', dterm && !this.expertMode);
$('.advancedSliderDmaxGain').toggle(dMaxGain || this.expertMode);
$('.advancedSliderIGain').toggle(iGain || this.expertMode);
$('.advancedSliderRollPitchRatio').toggle(rpRatio || this.expertMode);
@ -227,8 +247,11 @@ TuningSliders.initGyroFilterSliderPosition = function() {
this.sliderGyroFilter = FC.TUNING_SLIDERS.slider_gyro_filter;
this.sliderGyroFilterMultiplier = FC.TUNING_SLIDERS.slider_gyro_filter_multiplier / 100;
} else {
this.sliderGyroFilterMultiplier = Math.floor((FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz + FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz + FC.FILTER_CONFIG.gyro_lowpass2_hz) /
(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz + this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz + this.FILTER_DEFAULT.gyro_lowpass2_hz) * 100) / 100;
this.sliderGyroFilterMultiplier =
Math.floor(
(FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz + FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz + FC.FILTER_CONFIG.gyro_lowpass_hz + FC.FILTER_CONFIG.gyro_lowpass2_hz) /
(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz + this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz + this.FILTER_DEFAULT.gyro_lowpass_hz +
this.FILTER_DEFAULT.gyro_lowpass2_hz) * 100) / 100;
}
$('#sliderGyroFilterMultiplier').val(this.sliderGyroFilterMultiplier);
@ -236,16 +259,19 @@ TuningSliders.initGyroFilterSliderPosition = function() {
};
TuningSliders.initDTermFilterSliderPosition = function() {
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
this.sliderDTermFilterMultiplier = Math.floor((FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz + FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz + FC.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;
} else {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
this.sliderDTermFilter = FC.TUNING_SLIDERS.slider_dterm_filter;
this.sliderDTermFilterMultiplier = FC.TUNING_SLIDERS.slider_dterm_filter_multiplier / 100;
} else {
this.sliderDTermFilterMultiplier =
Math.floor(
(FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz + FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz + FC.FILTER_CONFIG.dterm_lowpass_hz + FC.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_lowpass_hz +
this.FILTER_DEFAULT.dterm_lowpass2_hz) * 100) / 100;
}
$('output[name="sliderDTermFilterMultiplier-number"]').val(this.sliderDTermFilterMultiplier);
$('#sliderDTermFilterMultiplier').val(this.sliderDTermFilterMultiplier);
$('output[name="sliderDTermFilterMultiplier-number"]').val(this.sliderDTermFilterMultiplier);
};
TuningSliders.resetPidSliders = function() {
@ -282,43 +308,17 @@ TuningSliders.resetPidSliders = function() {
};
TuningSliders.resetGyroFilterSlider = function() {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
if (!this.cachedGyroSliderValues) {
this.sliderGyroFilterMultiplier = 1;
}
this.sliderGyroFilter = 1;
FC.TUNING_SLIDERS.slider_gyro_filter = 1;
this.initGyroFilterSliderPosition();
} else {
this.sliderGyroFilterMultiplier = 1;
$('#sliderGyroFilterMultiplier').val(this.sliderGyroFilterMultiplier);
}
this.FilterReset = true;
this.sliderGyroFilterMultiplier = 1;
$('#sliderGyroFilterMultiplier').val(this.sliderGyroFilterMultiplier);
this.calculateNewGyroFilters();
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
this.updateFilterSlidersDisplay();
}
this.updateFilterSlidersDisplay();
};
TuningSliders.resetDTermFilterSlider = function() {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
if (!this.cachedDTermSliderValues) {
this.sliderDTermFilterMultiplier = 1;
}
this.sliderDtermFilter = 1;
FC.TUNING_SLIDERS.slider_dterm_filter = 1;
this.initDTermFilterSliderPosition();
} else {
this.sliderDTermFilterMultiplier = 1;
$('#sliderDTermFilterMultiplier').val(this.sliderDTermFilterMultiplier);
}
this.FilterReset = true;
this.sliderDTermFilterMultiplier = 1;
$('#sliderDTermFilterMultiplier').val(this.sliderDTermFilterMultiplier);
this.calculateNewDTermFilters();
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
this.updateFilterSlidersDisplay();
}
this.updateFilterSlidersDisplay();
};
TuningSliders.legacyUpdateFilterSlidersDisplay = function() {
@ -327,6 +327,8 @@ TuningSliders.legacyUpdateFilterSlidersDisplay = function() {
parseInt($('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val()) !==
Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz * this.sliderGyroFilterMultiplier) ||
parseInt($('.pid_filter select[name="gyroLowpassDynType"]').val()) !== this.FILTER_DEFAULT.gyro_lowpass_type ||
parseInt($('.pid_filter input[name="gyroLowpassFrequency"]').val()) !==
Math.floor(this.FILTER_DEFAULT.gyro_lowpass_hz * this.sliderGyroFilterMultiplier) ||
parseInt($('.pid_filter input[name="gyroLowpass2Frequency"]').val()) !==
Math.floor(this.FILTER_DEFAULT.gyro_lowpass2_hz * this.sliderGyroFilterMultiplier) ||
parseInt($('.pid_filter select[name="gyroLowpass2Type"]').val()) !== this.FILTER_DEFAULT.gyro_lowpass2_type) {
@ -340,6 +342,8 @@ TuningSliders.legacyUpdateFilterSlidersDisplay = function() {
parseInt($('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').val()) !==
Math.round(this.FILTER_DEFAULT.dterm_lowpass_dyn_max_hz * this.sliderDTermFilterMultiplier) ||
parseInt($('.pid_filter select[name="dtermLowpassDynType"]').val()) !== this.FILTER_DEFAULT.dterm_lowpass_type ||
parseInt($('.pid_filter input[name="dtermLowpassFrequency"]').val()) !==
Math.round(this.FILTER_DEFAULT.dterm_lowpass_hz * this.sliderDTermFilterMultiplier) ||
parseInt($('.pid_filter input[name="dtermLowpass2Frequency"]').val()) !==
Math.round(this.FILTER_DEFAULT.dterm_lowpass2_hz * this.sliderDTermFilterMultiplier) ||
parseInt($('.pid_filter select[name="dtermLowpass2Type"]').val()) !== this.FILTER_DEFAULT.dterm_lowpass2_type) {
@ -347,6 +351,12 @@ TuningSliders.legacyUpdateFilterSlidersDisplay = function() {
} else {
this.cachedDTermSliderValues = true;
}
$('.tuningFilterSliders .sliderLabels tr:nth-child(2)').toggle(!this.GyroSliderUnavailable);
$('.tuningFilterSliders .sliderLabels tr:last-child').toggle(!this.DTermSliderUnavailable);
$('.tuningFilterSliders').toggle(!(this.GyroSliderUnavailable && this.DTermSliderUnavailable));
$('.subtab-filter .slidersDisabled').toggle(this.GyroSliderUnavailable || this.DTermSliderUnavailable);
};
TuningSliders.updateSlidersWarning = function(slidersUnavailable = false) {
@ -366,20 +376,20 @@ TuningSliders.updateSlidersWarning = function(slidersUnavailable = false) {
$('.subtab-pid .slidersWarning').toggle(enableWarning && !slidersUnavailable);
};
TuningSliders.updateFilterSlidersWarning = function(gyroSliderUnavailable = false, DTermSliderUnavailable = false) {
TuningSliders.updateFilterSlidersWarning = function() {
let WARNING_FILTER_GYRO_LOW_GAIN = 0.7;
let WARNING_FILTER_GYRO_HIGH_GAIN = 1.25;
let WARNING_FILTER_GYRO_HIGH_GAIN = 1.4;
let WARNING_FILTER_DTERM_LOW_GAIN = 0.7;
const WARNING_FILTER_DTERM_HIGH_GAIN = 1.25;
let WARNING_FILTER_DTERM_HIGH_GAIN = 1.4;
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
WARNING_FILTER_GYRO_LOW_GAIN = 0.45;
WARNING_FILTER_GYRO_HIGH_GAIN = 1.55;
WARNING_FILTER_DTERM_LOW_GAIN = 0.75;
WARNING_FILTER_DTERM_HIGH_GAIN = 1.25;
}
$('.subtab-filter .slidersWarning').toggle(((this.sliderGyroFilterMultiplier >= WARNING_FILTER_GYRO_HIGH_GAIN ||
this.sliderGyroFilterMultiplier <= WARNING_FILTER_GYRO_LOW_GAIN) && !gyroSliderUnavailable) ||
((this.sliderDTermFilterMultiplier >= WARNING_FILTER_DTERM_HIGH_GAIN ||
this.sliderDTermFilterMultiplier <= WARNING_FILTER_DTERM_LOW_GAIN) && !DTermSliderUnavailable));
$('.subtab-filter .slidersWarning').toggle((this.sliderGyroFilterMultiplier >= WARNING_FILTER_GYRO_HIGH_GAIN ||
this.sliderGyroFilterMultiplier <= WARNING_FILTER_GYRO_LOW_GAIN) ||
(this.sliderDTermFilterMultiplier >= WARNING_FILTER_DTERM_HIGH_GAIN || this.sliderDTermFilterMultiplier <= WARNING_FILTER_DTERM_LOW_GAIN));
};
TuningSliders.updatePidSlidersDisplay = function() {
@ -426,65 +436,116 @@ TuningSliders.updatePidSlidersDisplay = function() {
this.updateSlidersWarning(this.pidSlidersUnavailable);
};
TuningSliders.updateGyroFilterSliderDisplay = function() {
// check if enabled filters were changed manually by comparing current value and those based on slider position
const lp1DynMin = parseInt($('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val());
const lp1DynMax = parseInt($('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val());
const lp1Static = parseInt($('.pid_filter input[name="gyroLowpassFrequency"]').val());
const lp2Freq = parseInt($('.pid_filter input[name="gyroLowpass2Frequency"]').val());
const lp1DynamicMinChanged = (lp1DynMin > 0) && (lp1DynMin !== Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz * this.sliderGyroFilterMultiplier));
const lp1DynamicMaxChanged = (lp1DynMax > 0) && (lp1DynMax !== Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz * this.sliderGyroFilterMultiplier));
const lp1Changed = (lp1Static > 0) && (lp1Static !== Math.floor(this.FILTER_DEFAULT.gyro_lowpass_hz * this.sliderGyroFilterMultiplier));
const lp2Changed = (lp2Freq > 0) && (lp2Freq !== Math.floor(this.FILTER_DEFAULT.gyro_lowpass2_hz * this.sliderGyroFilterMultiplier));
const hideSlider = (lp1DynMin && (lp1DynamicMinChanged || lp1DynamicMaxChanged)) || (lp1Static && lp1Changed) || (lp2Freq && lp2Changed) || this.sliderGyroFilterDisabled;
if (hideSlider) {
this.GyroSliderUnavailable = true;
this.sliderGyroFilter = 0;
} else {
this.GyroSliderUnavailable = false;
this.sliderGyroFilter = 1;
this.cachedGyroSliderValues = true;
}
// update Gyro mode and slider
$('select[id="sliderGyroFilterModeSelect"]').val(this.sliderGyroFilter);
$('.sliderGyroFilter').toggleClass('disabledSliders', !this.sliderGyroFilter || !(lp1Static || lp1DynMin || lp2Freq));
$('#sliderGyroFilterMultiplier').prop('disabled', !this.sliderGyroFilter);
};
TuningSliders.updateDTermFilterSliderDisplay = function() {
// check if enabled filters were changed manually by comparing current value and those based on slider position
const lp1DynMin = parseInt($('.pid_filter input[name="dtermLowpassDynMinFrequency"]').val());
const lp1DynMax = parseInt($('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').val());
const lp1Static = parseInt($('.pid_filter input[name="dtermLowpassFrequency"]').val());
const lp2Freq = parseInt($('.pid_filter input[name="dtermLowpass2Frequency"]').val());
const lp1DynamicMinChanged = (lp1DynMin > 0) && (lp1DynMin !== Math.floor(this.FILTER_DEFAULT.dterm_lowpass_dyn_min_hz * this.sliderDTermFilterMultiplier));
const lp1DynamicMaxChanged = (lp1DynMax > 0) && (lp1DynMax !== Math.floor(this.FILTER_DEFAULT.dterm_lowpass_dyn_max_hz * this.sliderDTermFilterMultiplier));
const lp1Changed = (lp1Static > 0) && (lp1Static !== Math.floor(this.FILTER_DEFAULT.dterm_lowpass_hz * this.sliderDTermFilterMultiplier));
const lp2Changed = (lp2Freq > 0) && (lp2Freq !== Math.floor(this.FILTER_DEFAULT.dterm_lowpass2_hz * this.sliderDTermFilterMultiplier));
const hideSlider = (lp1DynMin && (lp1DynamicMinChanged || lp1DynamicMaxChanged)) || (lp1Static && lp1Changed) || (lp2Freq && lp2Changed) || this.sliderDTermFilterDisabled;
if (hideSlider) {
this.DTermSliderUnavailable = true;
this.sliderDTermFilter = 0;
} else {
this.DTermSliderUnavailable = false;
this.sliderDTermFilter = 1;
this.cachedDTermSliderValues = true;
}
// update DTerm mode and slider
$('select[id="sliderDTermFilterModeSelect"]').val(this.sliderDTermFilter);
$('.sliderDTermFilter').toggleClass('disabledSliders', !this.sliderDTermFilter || !(lp1Static || lp1DynMin || lp2Freq));
$('#sliderDTermFilterMultiplier').prop('disabled', !this.sliderDTermFilter);
};
TuningSliders.updateFilterSlidersDisplay = function() {
// check if filters changed manually by comparing current value and those based on slider position
this.GyroSliderUnavailable = false;
this.DTermSliderUnavailable = false;
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
this.GyroSliderUnavailable = !FC.TUNING_SLIDERS.slider_gyro_filter;
this.DTermSliderUnavailable = !FC.TUNING_SLIDERS.slider_dterm_filter;
if (parseInt($('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val()) !==
Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz * this.sliderGyroFilterMultiplier) ||
parseInt($('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val()) !==
Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz * this.sliderGyroFilterMultiplier) ||
parseInt($('.pid_filter select[name="gyroLowpassDynType"]').val()) !== this.FILTER_DEFAULT.gyro_lowpass_type ||
parseInt($('.pid_filter input[name="gyroLowpass2Frequency"]').val()) !==
Math.floor(this.FILTER_DEFAULT.gyro_lowpass2_hz * this.sliderGyroFilterMultiplier) ||
parseInt($('.pid_filter select[name="gyroLowpass2Type"]').val()) !== this.FILTER_DEFAULT.gyro_lowpass2_type) {
this.GyroSliderUnavailable = true;
this.sliderGyroFilter = 0;
} else {
this.cachedGyroSliderValues = true;
this.sliderGyroFilter = 1;
}
if (parseInt($('.pid_filter input[name="dtermLowpassDynMinFrequency"]').val()) !==
Math.floor(this.FILTER_DEFAULT.dterm_lowpass_dyn_min_hz * this.sliderDTermFilterMultiplier) ||
Math.abs(parseInt($('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').val()) - this.FILTER_DEFAULT.dterm_lowpass_dyn_max_hz * this.sliderDTermFilterMultiplier) > 1 ||
parseInt($('.pid_filter select[name="dtermLowpassDynType"]').val()) !== this.FILTER_DEFAULT.dterm_lowpass_type ||
parseInt($('.pid_filter input[name="dtermLowpass2Frequency"]').val()) !==
Math.floor(this.FILTER_DEFAULT.dterm_lowpass2_hz * this.sliderDTermFilterMultiplier) ||
parseInt($('.pid_filter select[name="dtermLowpass2Type"]').val()) !== this.FILTER_DEFAULT.dterm_lowpass2_type) {
this.DTermSliderUnavailable = true;
this.sliderDTermFilter = 0;
} else {
this.cachedDTermSliderValues = true;
this.sliderDTermFilter = 1;
}
this.updateGyroFilterSliderDisplay();
this.updateDTermFilterSliderDisplay();
} else {
this.legacyUpdateFilterSlidersDisplay();
}
if (this.GyroSliderUnavailable) {
$('.tuningFilterSliders .sliderLabels tr:nth-child(2)').hide();
} else {
$('.tuningFilterSliders .sliderLabels tr:nth-child(2)').show();
}
if (this.DTermSliderUnavailable) {
$('.tuningFilterSliders .sliderLabels tr:last-child').hide();
} else {
$('.tuningFilterSliders .sliderLabels tr:last-child').show();
}
$('.tuningFilterSliders').toggle(!(this.GyroSliderUnavailable && this.DTermSliderUnavailable));
$('.subtab-filter .slidersDisabled').toggle(this.GyroSliderUnavailable || this.DTermSliderUnavailable);
$('.subtab-filter .nonExpertModeSlidersNote').toggle((!this.GyroSliderUnavailable || !this.DTermSliderUnavailable) && !this.expertMode);
this.updateFilterSlidersWarning(this.GyroSliderUnavailable, this.DTermSliderUnavailable);
};
TuningSliders.gyroFilterSliderEnable = function() {
this.sliderGyroFilter = true;
this.sliderGyroFilterDisabled = false;
this.FilterReset = true;
FC.TUNING_SLIDERS.slider_gyro_filter = 1;
this.writeFilterSliders();
this.updateLowpassValues();
this.updateFilterSlidersDisplay();
};
TuningSliders.gyroFilterSliderDisable = function() {
this.sliderGyroFilter = false;
this.sliderGyroFilterDisabled = true;
this.FilterReset = true;
FC.TUNING_SLIDERS.slider_gyro_filter = 0;
this.writeFilterSliders();
};
TuningSliders.dtermFilterSliderEnable = function() {
this.sliderDTermFilter = true;
this.sliderDTermFilterDisabled = false;
this.FilterReset = true;
FC.TUNING_SLIDERS.slider_dterm_filter = 1;
this.writeFilterSliders();
this.updateLowpassValues();
this.updateFilterSlidersDisplay();
};
TuningSliders.dtermFilterSliderDisable = function() {
this.sliderDTermFilter = false;
this.sliderDTermFilterDisabled = true;
this.FilterReset = true;
FC.TUNING_SLIDERS.slider_dterm_filter = 0;
this.writeFilterSliders();
};
TuningSliders.updateFormPids = function(updateSlidersOnly = false) {
if (!updateSlidersOnly) {
FC.PID_NAMES.forEach(function (elementPid, indexPid) {
@ -611,6 +672,7 @@ TuningSliders.calculateLegacyGyroFilters = function() {
// calculate, set and display new values in forms based on slider position
FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz = Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz * this.sliderGyroFilterMultiplier);
FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz = Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz * this.sliderGyroFilterMultiplier);
FC.FILTER_CONFIG.gyro_lowpass_hz = Math.floor(this.FILTER_DEFAULT.gyro_lowpass_hz * this.sliderGyroFilterMultiplier);
FC.FILTER_CONFIG.gyro_lowpass2_hz = Math.floor(this.FILTER_DEFAULT.gyro_lowpass2_hz * this.sliderGyroFilterMultiplier);
FC.FILTER_CONFIG.gyro_lowpass_type = this.FILTER_DEFAULT.gyro_lowpass_type;
FC.FILTER_CONFIG.gyro_lowpass2_type = this.FILTER_DEFAULT.gyro_lowpass2_type;
@ -623,6 +685,7 @@ TuningSliders.calculateLegacyDTermFilters = function() {
// calculate, set and display new values in forms based on slider position
FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz = Math.round(this.FILTER_DEFAULT.dterm_lowpass_dyn_min_hz * this.sliderDTermFilterMultiplier);
FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz = Math.round(this.FILTER_DEFAULT.dterm_lowpass_dyn_max_hz * this.sliderDTermFilterMultiplier);
FC.FILTER_CONFIG.dterm_lowpass_hz = Math.round(this.FILTER_DEFAULT.dterm_lowpass_hz * this.sliderDTermFilterMultiplier);
FC.FILTER_CONFIG.dterm_lowpass2_hz = Math.round(this.FILTER_DEFAULT.dterm_lowpass2_hz * this.sliderDTermFilterMultiplier);
FC.FILTER_CONFIG.dterm_lowpass_type = this.FILTER_DEFAULT.dterm_lowpass_type;
FC.FILTER_CONFIG.dterm_lowpass2_type = this.FILTER_DEFAULT.dterm_lowpass2_type;
@ -635,7 +698,6 @@ TuningSliders.calculateNewGyroFilters = function() {
// this is the main calculation for Gyro Filter slider, inputs are in form of slider position values
// values get set both into forms and their respective variables
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
FC.TUNING_SLIDERS.slider_gyro_filter = this.sliderGyroFilter;
//rounds slider values to nearies multiple of 5 and passes to the FW. Avoid dividing calc by (* x 100)/5 = 20
FC.TUNING_SLIDERS.slider_gyro_filter_multiplier = Math.round(this.sliderGyroFilterMultiplier * 20) * 5;
this.writeFilterSliders();
@ -645,10 +707,9 @@ TuningSliders.calculateNewGyroFilters = function() {
};
TuningSliders.calculateNewDTermFilters = function() {
// this is the main calculation for Gyro Filter slider, inputs are in form of slider position values
// this is the main calculation for DTerm Filter slider, inputs are in form of slider position values
// values get set both into forms and their respective variables
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
FC.TUNING_SLIDERS.slider_dterm_filter = this.sliderDTermFilter;
//rounds slider values to nearies multiple of 5 and passes to the FW. Avoid divide by ROUND[(* x 100)/5 = 20]
FC.TUNING_SLIDERS.slider_dterm_filter_multiplier = Math.round(this.sliderDTermFilterMultiplier * 20) * 5;
this.writeFilterSliders();
@ -657,8 +718,20 @@ TuningSliders.calculateNewDTermFilters = function() {
}
};
// We need to write filter config to switch filters without having to save.
TuningSliders.updateFiltersInFirmware = function() {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
MSP.promise(MSPCodes.MSP_SET_FILTER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_FILTER_CONFIG))
.then(() => MSPCodes.MSP_SET_TUNING_SLIDERS, mspHelper.crunch(MSPCodes.MSP_SET_TUNING_SLIDERS))
.then(() => MSP.promise(MSPCodes.MSP_FILTER_CONFIG))
.then(() => this.updateLowpassValues());
}
};
TuningSliders.writeFilterSliders = function () {
// send sliders to firmware
MSP.promise(MSPCodes.MSP_SET_TUNING_SLIDERS, mspHelper.crunch(MSPCodes.MSP_SET_TUNING_SLIDERS))
// pulls values from firmware
.then(() => MSP.promise(MSPCodes.MSP_FILTER_CONFIG))
.then(() => {
TuningSliders.updateLowpassValues();
@ -673,15 +746,19 @@ TuningSliders.writeFilterSliders = function () {
TuningSliders.updateLowpassValues = function() {
$('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val(FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz);
$('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val(FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz);
$('.pid_filter select[name="gyroLowpassDynType"]').val(FC.FILTER_CONFIG.gyro_lowpass_type);
$('.pid_filter input[name="gyroLowpassFrequency"]').val(FC.FILTER_CONFIG.gyro_lowpass_hz);
$('.pid_filter select[name="gyroLowpassType"]').val(FC.FILTER_CONFIG.gyro_lowpass_type);
$('.pid_filter input[name="gyroLowpass2Frequency"]').val(FC.FILTER_CONFIG.gyro_lowpass2_hz);
$('.pid_filter select[name="gyroLowpassDynType]"').val(FC.FILTER_CONFIG.gyro_lowpass_type);
$('.pid_filter select[name="gyroLowpass2Type"]').val(FC.FILTER_CONFIG.gyro_lowpass2_type);
$('output[name="sliderGyroFilterMultiplier-number"]').val(this.sliderGyroFilterMultiplier);
$('.pid_filter input[name="dtermLowpassDynMinFrequency"]').val(FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz);
$('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').val(FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz);
$('.pid_filter input[name="dtermLowpass2Frequency"]').val(FC.FILTER_CONFIG.dterm_lowpass2_hz);
$('.pid_filter select[name="dtermLowpassDynType"]').val(FC.FILTER_CONFIG.dterm_lowpass_type);
$('.pid_filter input[name="dtermLowpassFrequency"]').val(FC.FILTER_CONFIG.dterm_lowpass_hz);
$('.pid_filter select[name="dtermLowpassType"]').val(FC.FILTER_CONFIG.dterm_lowpass_type);
$('.pid_filter input[name="dtermLowpass2Frequency"]').val(FC.FILTER_CONFIG.dterm_lowpass2_hz);
$('.pid_filter select[name="dtermLowpass2Type"]').val(FC.FILTER_CONFIG.dterm_lowpass2_type);
$('output[name="sliderDTermFilterMultiplier-number"]').val(this.sliderDTermFilterMultiplier);
};

View file

@ -30,6 +30,9 @@ const CONFIGURATOR = {
cliActive: false,
cliValid: false,
productName: 'Betaflight Configurator',
cliEngineActive: false,
cliEngineValid: false,
gitChangesetId: 'unknown',
version: '0.0.1',
gitRevision: 'norevision',
latestVersion: '0.0.1',

View file

@ -853,6 +853,7 @@ const FC = {
versionFilterDefaults.gyro_lowpass_hz = 250;
versionFilterDefaults.gyro_lowpass_dyn_min_hz = 250;
versionFilterDefaults.gyro_lowpass2_hz = 500;
versionFilterDefaults.dterm_lowpass_hz = 75;
versionFilterDefaults.dterm_lowpass_dyn_min_hz = 75;
versionFilterDefaults.dterm_lowpass_dyn_max_hz = 150;
}

View file

@ -19,6 +19,7 @@ const GuiControl = function () {
this.operating_system = null;
this.interval_array = [];
this.timeout_array = [];
this.buttonDisabledClass = "disabled";
this.defaultAllowedTabsWhenDisconnected = [
'landing',
@ -36,6 +37,7 @@ const GuiControl = function () {
'power',
'adjustments',
'auxiliary',
'presets',
'cli',
'configuration',
'gps',
@ -407,5 +409,166 @@ GuiControl.prototype.isOther = function () {
return this.Mode === GUI_MODES.Other;
};
GuiControl.prototype.showYesNoDialog = function(yesNoDialogSettings) {
// yesNoDialogSettings:
// title, text, buttonYesText, buttonNoText, buttonYesCallback, buttonNoCallback
const dialog = $(".dialogYesNo");
const title = dialog.find(".dialogYesNoTitle");
const content = dialog.find(".dialogYesNoContent");
const buttonYes = dialog.find(".dialogYesNo-yesButton");
const buttonNo = dialog.find(".dialogYesNo-noButton");
title.html(yesNoDialogSettings.title);
content.html(yesNoDialogSettings.text);
buttonYes.html(yesNoDialogSettings.buttonYesText);
buttonNo.html(yesNoDialogSettings.buttonNoText);
buttonYes.off("click");
buttonNo.off("click");
buttonYes.on("click", () => {
dialog[0].close();
yesNoDialogSettings.buttonYesCallback?.();
});
buttonNo.on("click", () => {
dialog[0].close();
yesNoDialogSettings.buttonNoCallback?.();
});
dialog[0].showModal();
};
GuiControl.prototype.showWaitDialog = function(waitDialogSettings) {
// waitDialogSettings:
// title, buttonCancelCallback
const dialog = $(".dialogWait")[0];
const title = $(".dialogWaitTitle");
const buttonCancel = $(".dialogWait-cancelButton");
title.html(waitDialogSettings.title);
buttonCancel.toggle(!!waitDialogSettings.buttonCancelCallback);
buttonCancel.off("click");
buttonCancel.on("click", () => {
dialog.close();
waitDialogSettings.buttonCancelCallback?.();
});
dialog.showModal();
return dialog;
};
GuiControl.prototype.showInformationDialog = function(informationDialogSettings) {
// informationDialogSettings:
// title, text, buttonConfirmText
return new Promise(resolve => {
const dialog = $(".dialogInformation");
const title = dialog.find(".dialogInformationTitle");
const content = dialog.find(".dialogInformationContent");
const buttonConfirm = dialog.find(".dialogInformation-confirmButton");
title.html(informationDialogSettings.title);
content.html(informationDialogSettings.text);
buttonConfirm.html(informationDialogSettings.buttonConfirmText);
buttonConfirm.off("click");
buttonConfirm.on("click", () => {
dialog[0].close();
resolve();
});
dialog[0].showModal();
});
};
GuiControl.prototype.saveToTextFileDialog = function(textToSave, suggestedFileName, extension) {
return new Promise((resolve, reject) => {
const accepts = [{ description: extension.toUpperCase() + ' files', extensions: [extension] }];
chrome.fileSystem.chooseEntry(
{
type: 'saveFile',
suggestedName: suggestedFileName,
accepts: accepts,
},
entry => this._saveToTextFileDialogFileSelected(entry, textToSave, resolve, reject),
);
});
};
GuiControl.prototype._saveToTextFileDialogFileSelected = function(entry, textToSave, resolve, reject) {
checkChromeRuntimeError();
if (!entry) {
console.log('No file selected for saving');
resolve(false);
return;
}
entry.createWriter(writer => {
writer.onerror = () => {
reject();
console.error('Failed to write file');
};
writer.onwriteend = () => {
if (textToSave.length > 0 && writer.length === 0) {
writer.write(new Blob([textToSave], {type: 'text/plain'}));
} else {
resolve(true);
console.log('File write complete');
}
};
writer.truncate(0);
},
() => {
reject();
console.error('Failed to get file writer');
});
};
GuiControl.prototype.readTextFileDialog = function(extension) {
const accepts = [{ description: extension.toUpperCase() + ' files', extensions: [extension] }];
return new Promise(resolve => {
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: accepts}, function(entry) {
checkChromeRuntimeError();
if (!entry) {
console.log('No file selected for loading');
resolve(false);
return;
}
entry.file((file) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => {
console.error(reader.error);
reject();
};
reader.readAsText(file);
});
});
});
};
GuiControl.prototype.escapeHtml = function(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
};
// initialize object into GUI variable
window.GUI = new GuiControl();

View file

@ -404,6 +404,10 @@ function startProcess() {
// Add a little timeout to let MSP comands finish
GUI.timeout_add('wait_for_msp_finished', () => TABS.cli.initialize(content_ready, GUI.nwGui), timeout);
break;
case 'presets':
TABS.presets.initialize(content_ready, GUI.nwGui);
break;
default:
console.log(`Tab not found: ${tab}`);
}

View file

@ -1178,6 +1178,8 @@ MspHelper.prototype.process_data = function(dataHandler) {
FC.ADVANCED_TUNING.feedforward_averaging = data.readU8();
FC.ADVANCED_TUNING.feedforward_smooth_factor = data.readU8();
FC.ADVANCED_TUNING.feedforward_boost = data.readU8();
FC.ADVANCED_TUNING.feedforward_max_rate_limit = data.readU8();
FC.ADVANCED_TUNING.feedforward_jitter_factor = data.readU8();
FC.ADVANCED_TUNING.vbat_sag_compensation = data.readU8();
FC.ADVANCED_TUNING.thrustLinearization = data.readU8();
}
@ -1501,7 +1503,6 @@ MspHelper.prototype.process_data = function(dataHandler) {
FC.TUNING_SLIDERS.slider_dterm_filter_multiplier = data.readU8();
FC.TUNING_SLIDERS.slider_gyro_filter = data.readU8();
FC.TUNING_SLIDERS.slider_gyro_filter_multiplier = data.readU8();
break;
case MSPCodes.MSP_SET_VTXTABLE_POWERLEVEL:
@ -1567,7 +1568,7 @@ MspHelper.prototype.process_data = function(dataHandler) {
console.log('Name set');
break;
case MSPCodes.MSP_SET_FILTER_CONFIG:
console.log('Filter config set');
// removed as this fires a lot with firmware sliders console.log('Filter config set');
break;
case MSPCodes.MSP_SET_ADVANCED_CONFIG:
console.log('Advanced config parameters set');
@ -2151,6 +2152,8 @@ MspHelper.prototype.crunch = function(code) {
buffer.push8(FC.ADVANCED_TUNING.feedforward_averaging)
.push8(FC.ADVANCED_TUNING.feedforward_smooth_factor)
.push8(FC.ADVANCED_TUNING.feedforward_boost)
.push8(FC.ADVANCED_TUNING.feedforward_max_rate_limit)
.push8(FC.ADVANCED_TUNING.feedforward_jitter_factor)
.push8(FC.ADVANCED_TUNING.vbat_sag_compensation)
.push8(FC.ADVANCED_TUNING.thrustLinearization);
}
@ -2311,19 +2314,20 @@ MspHelper.prototype.crunch = function(code) {
break;
case MSPCodes.MSP_SET_TUNING_SLIDERS:
buffer.push8(FC.TUNING_SLIDERS.slider_pids_mode)
.push8(FC.TUNING_SLIDERS.slider_master_multiplier)
.push8(FC.TUNING_SLIDERS.slider_roll_pitch_ratio)
.push8(FC.TUNING_SLIDERS.slider_i_gain)
.push8(FC.TUNING_SLIDERS.slider_d_gain)
.push8(FC.TUNING_SLIDERS.slider_pi_gain)
.push8(FC.TUNING_SLIDERS.slider_dmax_gain)
.push8(FC.TUNING_SLIDERS.slider_feedforward_gain)
.push8(FC.TUNING_SLIDERS.slider_pitch_pi_gain)
.push8(FC.TUNING_SLIDERS.slider_dterm_filter)
.push8(FC.TUNING_SLIDERS.slider_dterm_filter_multiplier)
.push8(FC.TUNING_SLIDERS.slider_gyro_filter)
.push8(FC.TUNING_SLIDERS.slider_gyro_filter_multiplier);
buffer
.push8(FC.TUNING_SLIDERS.slider_pids_mode)
.push8(FC.TUNING_SLIDERS.slider_master_multiplier)
.push8(FC.TUNING_SLIDERS.slider_roll_pitch_ratio)
.push8(FC.TUNING_SLIDERS.slider_i_gain)
.push8(FC.TUNING_SLIDERS.slider_d_gain)
.push8(FC.TUNING_SLIDERS.slider_pi_gain)
.push8(FC.TUNING_SLIDERS.slider_dmax_gain)
.push8(FC.TUNING_SLIDERS.slider_feedforward_gain)
.push8(FC.TUNING_SLIDERS.slider_pitch_pi_gain)
.push8(FC.TUNING_SLIDERS.slider_dterm_filter)
.push8(FC.TUNING_SLIDERS.slider_dterm_filter_multiplier)
.push8(FC.TUNING_SLIDERS.slider_gyro_filter)
.push8(FC.TUNING_SLIDERS.slider_gyro_filter_multiplier);
break;
default:

View file

@ -583,13 +583,17 @@ function onClosed(result) {
CONFIGURATOR.connectionValid = false;
CONFIGURATOR.cliValid = false;
CONFIGURATOR.cliActive = false;
CONFIGURATOR.cliEngineValid = false;
CONFIGURATOR.cliEngineActive = false;
}
function read_serial(info) {
if (!CONFIGURATOR.cliActive) {
MSP.read(info);
} else if (CONFIGURATOR.cliActive) {
if (CONFIGURATOR.cliActive) {
TABS.cli.read(info);
} else if (CONFIGURATOR.cliEngineActive) {
TABS.presets.read(info);
} else {
MSP.read(info);
}
}
@ -694,7 +698,8 @@ function update_live_status() {
display: 'inline-block'
});
if (GUI.active_tab != 'cli') {
if (GUI.active_tab !== 'cli' && GUI.active_tab !== 'presets') {
MSP.send_message(MSPCodes.MSP_BOXNAMES, false, false);
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_32)) {
MSP.send_message(MSPCodes.MSP_STATUS_EX, false, false);
} else {

View file

@ -18,6 +18,8 @@ options.initialize = function (callback) {
TABS.options.initCordovaForceComputerUI();
TABS.options.initDarkTheme();
TABS.options.initShowWarnings();
GUI.content_ready(callback);
});
};
@ -28,6 +30,19 @@ options.cleanup = function (callback) {
}
};
options.initShowWarnings = function () {
ConfigStorage.get('showPresetsWarningBackup', function (result) {
if (result.showPresetsWarningBackup) {
$('div.presetsWarningBackup input').prop('checked', true);
}
$('div.presetsWarningBackup input').change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'showPresetsWarningBackup': checked});
}).change();
});
};
options.initPermanentExpertMode = function () {
ConfigStorage.get('permanentExpertMode', function (result) {
if (result.permanentExpertMode) {

View file

@ -235,6 +235,7 @@ TABS.pid_tuning.initialize = function (callback) {
$('.pid_filter select[name="gyroLowpassType"]').val(FC.FILTER_CONFIG.gyro_lowpass_type);
$('.pid_filter select[name="gyroLowpass2Type"]').val(FC.FILTER_CONFIG.gyro_lowpass2_type);
$('.pid_filter input[name="dtermLowpass2Frequency"]').val(FC.FILTER_CONFIG.dterm_lowpass2_hz);
$('.pid_filter select[name="dtermLowpass2Type"]').val(FC.FILTER_CONFIG.dterm_lowpass2_type);
// We load it again because the limits are now bigger than in 1.16.0
$('.pid_filter input[name="gyroLowpassFrequency"]').attr("max","16000");
@ -343,16 +344,13 @@ TABS.pid_tuning.initialize = function (callback) {
$('select[id="throttleLimitType"]').val(FC.RC_TUNING.throttleLimitType);
$('.throttle_limit input[name="throttleLimitPercent"]').val(FC.RC_TUNING.throttleLimitPercent);
$('.pid_filter select[name="dtermLowpass2Type"]').val(FC.FILTER_CONFIG.dterm_lowpass2_type);
$('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val(FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz);
$('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val(FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz);
$('.pid_filter select[name="gyroLowpassDynType"]').val(FC.FILTER_CONFIG.gyro_lowpass_type);
$('.pid_filter input[name="dtermLowpassDynMinFrequency"]').val(FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz);
$('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').val(FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz);
$('.pid_filter select[name="dtermLowpassDynType"]').val(FC.FILTER_CONFIG.dterm_lowpass_type);
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
$('.pid_filter input[name="dtermLowpassDynExpo"]').val(FC.FILTER_CONFIG.dyn_lpf_curve_expo);
}
$('.pid_tuning input[name="dMinRoll"]').val(FC.ADVANCED_TUNING.dMinRoll);
$('.pid_tuning input[name="dMinPitch"]').val(FC.ADVANCED_TUNING.dMinPitch);
@ -366,8 +364,8 @@ TABS.pid_tuning.initialize = function (callback) {
} else {
$('.throttle_limit').hide();
$('.gyroLowpassDyn').hide();
$('.dtermLowpassDyn').hide();
$('.gyroLowpassDynLegacy').hide();
$('.dtermLowpassDynLegacy').hide();
$('.dtermLowpass2TypeGroup').hide();
$('.dminGroup').hide();
@ -444,7 +442,7 @@ TABS.pid_tuning.initialize = function (callback) {
dynamicNotchQ_e.val(FC.FILTER_CONFIG.dyn_notch_q);
dynamicNotchWidthPercent_e.val(FC.FILTER_CONFIG.dyn_notch_width_percent);
}
$('.rpmFilter span.suboption').toggle(checked);
}).prop('checked', FC.FILTER_CONFIG.gyro_rpm_notch_harmonics != 0).change();
} else {
@ -488,7 +486,19 @@ TABS.pid_tuning.initialize = function (callback) {
$('.rates_type').hide();
}
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
// hide legacy filter switches
$('.gyroLowpassLegacy').hide();
$('.gyroLowpassDynLegacy').hide();
$('.dtermLowpassLegacy').hide();
$('.dtermLowpassDynLegacy').hide();
$('.pid_filter input[name="dtermLowpassExpo"]').val(FC.FILTER_CONFIG.dyn_lpf_curve_expo);
} else {
// hide firmware filter switches
$('.gyroLowpass').hide();
$('.dtermLowpass').hide();
// Previous html attributes for legacy sliders
$('.pid_tuning .ROLL input[name="p"]').attr("max", "200");
$('.pid_tuning .ROLL input[name="i"]').attr("max", "200");
@ -509,6 +519,8 @@ TABS.pid_tuning.initialize = function (callback) {
$('select[id="feedforwardAveraging"]').val(FC.ADVANCED_TUNING.feedforward_averaging);
$('input[name="feedforwardSmoothFactor"]').val(FC.ADVANCED_TUNING.feedforward_smooth_factor);
$('input[name="feedforwardBoost"]').val(FC.ADVANCED_TUNING.feedforward_boost);
$('input[name="feedforwardMaxRateLimit"]').val(FC.ADVANCED_TUNING.feedforward_max_rate_limit);
$('input[name="feedforwardJitterFactor"]').val(FC.ADVANCED_TUNING.feedforward_jitter_factor);
// Vbat Sag Compensation
const vbatSagCompensationCheck = $('input[id="vbatSagCompensation"]');
@ -534,6 +546,8 @@ TABS.pid_tuning.initialize = function (callback) {
} else {
$('.vbatSagCompensation').hide();
$('.thrustLinearization').hide();
$('.feedforwardMaxRateLimit').hide();
$('.feedforwardJitterFactor').hide();
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_40)) {
$('.pid_tuning .ROLL input[name="f"]').val(FC.ADVANCED_TUNING.feedforwardRoll > 0 ? FC.ADVANCED_TUNING.feedforwardRoll : PID_DEFAULT[4]);
@ -680,6 +694,8 @@ TABS.pid_tuning.initialize = function (callback) {
$('.pid_filter input[name="gyroNotch1Frequency"]').val(checked ? hz : 0).attr('disabled', !checked)
.attr("min", checked ? 1 : 0).change();
$('.pid_filter input[name="gyroNotch1Cutoff"]').attr('disabled', !checked).change();
$('.gyroNotch1 span.suboption').toggle(checked);
});
$('input[id="gyroNotch2Enabled"]').change(function() {
@ -689,6 +705,8 @@ TABS.pid_tuning.initialize = function (callback) {
$('.pid_filter input[name="gyroNotch2Frequency"]').val(checked ? hz : 0).attr('disabled', !checked)
.attr("min", checked ? 1 : 0).change();
$('.pid_filter input[name="gyroNotch2Cutoff"]').attr('disabled', !checked).change();
$('.gyroNotch2 span.suboption').toggle(checked);
});
$('input[id="dtermNotchEnabled"]').change(function() {
@ -698,114 +716,354 @@ TABS.pid_tuning.initialize = function (callback) {
$('.pid_filter input[name="dTermNotchFrequency"]').val(checked ? hz : 0).attr('disabled', !checked)
.attr("min", checked ? 1 : 0).change();
$('.pid_filter input[name="dTermNotchCutoff"]').attr('disabled', !checked).change();
$('.dtermNotch span.suboption').toggle(checked);
});
$('input[id="gyroLowpassEnabled"]').change(function() {
const checked = $(this).is(':checked');
const disabledByDynamicLowpass = $('input[id="gyroLowpassDynEnabled"]').is(':checked');
// gyro filter selectors
const gyroLowpassDynMinFrequency = $('.pid_filter input[name="gyroLowpassDynMinFrequency"]');
const gyroLowpassDynMaxFrequency = $('.pid_filter input[name="gyroLowpassDynMaxFrequency"]');
const gyroLowpassFrequency = $('.pid_filter input[name="gyroLowpassFrequency"]');
const gyroLowpass2Frequency = $('.pid_filter input[name="gyroLowpass2Frequency"]');
const gyroLowpassType = $('.pid_filter select[name="gyroLowpassType"]');
const gyroLowpass2Type = $('.pid_filter select[name="gyroLowpass2Type"]');
const gyroLowpassDynType = $('.pid_filter select[name="gyroLowpassDynType"]');
const cutoff = FC.FILTER_CONFIG.gyro_lowpass_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass_hz : FILTER_DEFAULT.gyro_lowpass_hz;
const type = FC.FILTER_CONFIG.gyro_lowpass_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass_type : FILTER_DEFAULT.gyro_lowpass_type;
const gyroLowpassDynEnabled = $('.pid_filter input[id="gyroLowpassDynEnabled"]');
const gyroLowpassEnabled = $('.pid_filter input[id="gyroLowpassEnabled"]');
const gyroLowpass2Enabled = $('.pid_filter input[id="gyroLowpass2Enabled"]');
$('.pid_filter input[name="gyroLowpassFrequency"]').val((checked || disabledByDynamicLowpass) ? cutoff : 0).attr('disabled', !checked);
$('.pid_filter select[name="gyroLowpassType"]').val(type).attr('disabled', !checked);
const gyroLowpassOption = $('.gyroLowpass span.suboption');
const gyroLowpassOptionStatic = $('.gyroLowpass span.suboption.static');
const gyroLowpassOptionDynamic = $('.gyroLowpass span.suboption.dynamic');
const gyroLowpass2Option = $('.gyroLowpass2 span.suboption');
if (checked) {
$('input[id="gyroLowpassDynEnabled"]').prop('checked', false).change();
}
self.updateFilterWarning();
});
const gyroLowpassFilterMode = $('.pid_filter select[name="gyroLowpassFilterMode"]');
$('input[id="gyroLowpassDynEnabled"]').change(function() {
const checked = $(this).is(':checked');
let cutoff_min = FILTER_DEFAULT.gyro_lowpass_dyn_min_hz;
let type = FILTER_DEFAULT.gyro_lowpass_type;
if (FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz > 0 && FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz < FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz) {
cutoff_min = FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz;
type = FC.FILTER_CONFIG.gyro_lowpass_type;
}
// dterm filter selectors
const dtermLowpassDynMinFrequency = $('.pid_filter input[name="dtermLowpassDynMinFrequency"]');
const dtermLowpassDynMaxFrequency = $('.pid_filter input[name="dtermLowpassDynMaxFrequency"]');
const dtermLowpassFrequency = $('.pid_filter input[name="dtermLowpassFrequency"]');
const dtermLowpass2Frequency = $('.pid_filter input[name="dtermLowpass2Frequency"]');
const dtermLowpassType = $('.pid_filter select[name="dtermLowpassType"]');
const dtermLowpass2Type = $('.pid_filter select[name="dtermLowpass2Type"]');
const dtermLowpassDynType = $('.pid_filter select[name="dtermLowpassDynType"]');
$('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val(checked ? cutoff_min : 0).attr('disabled', !checked);
$('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').attr('disabled', !checked);
$('.pid_filter select[name="gyroLowpassDynType"]').val(type).attr('disabled', !checked);
const dtermLowpassDynEnabled = $('.pid_filter input[id="dtermLowpassDynEnabled"]');
const dtermLowpassEnabled = $('input[id="dtermLowpassEnabled"]');
const dtermLowpass2Enabled = $('input[id="dtermLowpass2Enabled"]');
if (checked) {
$('input[id="gyroLowpassEnabled"]').prop('checked', false).change();
} else if (FC.FILTER_CONFIG.gyro_lowpass_hz > 0 && !$('input[id="gyroLowpassEnabled"]').is(':checked')) {
$('input[id="gyroLowpassEnabled"]').prop('checked', true).change();
}
self.updateFilterWarning();
});
const dtermLowpassOption = $('.dtermLowpass span.suboption');
const dtermLowpassOptionStatic = $('.dtermLowpass span.suboption.static');
const dtermLowpassOptionDynamic = $('.dtermLowpass span.suboption.dynamic');
const dtermLowpass2Option = $('.dtermLowpass2 span.suboption');
$('input[id="gyroLowpass2Enabled"]').change(function() {
const checked = $(this).is(':checked');
const cutoff = FC.FILTER_CONFIG.gyro_lowpass2_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass2_hz : FILTER_DEFAULT.gyro_lowpass2_hz;
const type = FC.FILTER_CONFIG.gyro_lowpass2_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass2_type : FILTER_DEFAULT.gyro_lowpass2_type;
const dtermLowpassFilterMode = $('.pid_filter select[name="dtermLowpassFilterMode"]');
$('.pid_filter input[name="gyroLowpass2Frequency"]').val(checked ? cutoff : 0).attr('disabled', !checked);
$('.pid_filter select[name="gyroLowpass2Type"]').val(type).attr('disabled', !checked);
});
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
$('input[id="dtermLowpassEnabled"]').change(function() {
const checked = $(this).is(':checked');
const disabledByDynamicLowpass = $('input[id="dtermLowpassDynEnabled"]').is(':checked');
// Legacy filter selectors for lowpass 1 and 2
gyroLowpassEnabled.change(function() {
const checked = $(this).is(':checked');
const disabledByDynamicLowpass = gyroLowpassDynEnabled.is(':checked');
const cutoff = FC.FILTER_CONFIG.dterm_lowpass_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass_hz : FILTER_DEFAULT.dterm_lowpass_hz;
const type = FC.FILTER_CONFIG.dterm_lowpass_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass_type : FILTER_DEFAULT.dterm_lowpass_type;
const cutoff = FC.FILTER_CONFIG.gyro_lowpass_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass_hz : FILTER_DEFAULT.gyro_lowpass_hz;
const type = FC.FILTER_CONFIG.gyro_lowpass_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass_type : FILTER_DEFAULT.gyro_lowpass_type;
$('.pid_filter input[name="dtermLowpassFrequency"]').val((checked || disabledByDynamicLowpass) ? cutoff : 0).attr('disabled', !checked);
$('.pid_filter select[name="dtermLowpassType"]').val(type).attr('disabled', !checked);
gyroLowpassFrequency.val((checked || disabledByDynamicLowpass) ? cutoff : 0).attr('disabled', !checked);
gyroLowpassType.each((i, el) => $(el).val(type).attr('disabled', !checked));
if (checked) {
$('input[id="dtermLowpassDynEnabled"]').prop('checked', false).change();
}
self.updateFilterWarning();
});
if (checked) {
gyroLowpassDynEnabled.prop('checked', false).change();
}
self.updateFilterWarning();
});
$('.dynLpfCurveExpo').toggle(semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44));
$('input[id="dtermLowpassDynEnabled"]').change(function() {
const checked = $(this).is(':checked');
let cutoff_min = FILTER_DEFAULT.dterm_lowpass_dyn_min_hz;
let type = FILTER_DEFAULT.dterm_lowpass_type;
if (FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz > 0 && FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz < FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz) {
cutoff_min = FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz;
type = FC.FILTER_CONFIG.dterm_lowpass_type;
}
gyroLowpassDynEnabled.change(function() {
const checked = $(this).is(':checked');
let cutoff_min = FILTER_DEFAULT.gyro_lowpass_dyn_min_hz;
let type = FILTER_DEFAULT.gyro_lowpass_type;
if (FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz > 0 && FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz < FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz) {
cutoff_min = FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz;
type = FC.FILTER_CONFIG.gyro_lowpass_type;
}
$('.pid_filter input[name="dtermLowpassDynMinFrequency"]').val(checked ? cutoff_min : 0).attr('disabled', !checked);
$('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').attr('disabled', !checked);
$('.pid_filter select[name="dtermLowpassDynType"]').val(type).attr('disabled', !checked);
gyroLowpassDynMinFrequency.val(checked ? cutoff_min : 0).attr('disabled', !checked);
gyroLowpassDynMaxFrequency.attr('disabled', !checked);
gyroLowpassDynType.each((i, el) => $(el).val(type).attr('disabled', !checked));
if (checked) {
$('input[id="dtermLowpassEnabled"]').prop('checked', false).change();
} else if (FC.FILTER_CONFIG.dterm_lowpass_hz > 0 && !$('input[id="dtermLowpassEnabled"]').is(':checked')) {
$('input[id="dtermLowpassEnabled"]').prop('checked', true).change();
$('.pid_filter input[id="dtermLowpassDynExpoEnabled"]').prop('checked', false).change();
}
self.updateFilterWarning();
});
if (checked) {
gyroLowpassEnabled.prop('checked', false).change();
} else if (FC.FILTER_CONFIG.gyro_lowpass_hz > 0 && !gyroLowpassEnabled.is(':checked')) {
gyroLowpassEnabled.prop('checked', true).change();
}
self.updateFilterWarning();
});
$('input[id="dtermLowpassDynExpoEnabled"]').change(function() {
const checked = $(this).is(':checked');
const curveExpo = FC.FILTER_CONFIG.dyn_lpf_curve_expo > 0 ? FC.FILTER_CONFIG.dyn_lpf_curve_expo : FILTER_DEFAULT.dyn_lpf_curve_expo;
gyroLowpass2Enabled.change(function() {
const checked = $(this).is(':checked');
const cutoff = FC.FILTER_CONFIG.gyro_lowpass2_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass2_hz : FILTER_DEFAULT.gyro_lowpass2_hz;
const type = FC.FILTER_CONFIG.gyro_lowpass2_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass2_type : FILTER_DEFAULT.gyro_lowpass2_type;
$('.pid_filter input[name="dtermLowpassDynExpo"]').val(checked ? curveExpo : 0).attr('disabled', !checked);
});
gyroLowpass2Frequency.val(checked ? cutoff : 0).attr('disabled', !checked);
gyroLowpass2Type.each((i, el) => $(el).val(type).attr('disabled', !checked));
});
$('input[id="dtermLowpass2Enabled"]').change(function() {
const checked = $(this).is(':checked');
const cutoff = FC.FILTER_CONFIG.dterm_lowpass2_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass2_hz : FILTER_DEFAULT.dterm_lowpass2_hz;
const type = FC.FILTER_CONFIG.dterm_lowpass2_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass2_type : FILTER_DEFAULT.dterm_lowpass2_type;
dtermLowpassEnabled.change(function() {
const checked = $(this).is(':checked');
const disabledByDynamicLowpass = dtermLowpassDynEnabled.is(':checked');
$('.pid_filter input[name="dtermLowpass2Frequency"]').val(checked ? cutoff : 0).attr('disabled', !checked);
$('.pid_filter select[name="dtermLowpass2Type"]').val(type).attr('disabled', !checked);
});
const cutoff = FC.FILTER_CONFIG.dterm_lowpass_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass_hz : FILTER_DEFAULT.dterm_lowpass_hz;
const type = FC.FILTER_CONFIG.dterm_lowpass_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass_type : FILTER_DEFAULT.dterm_lowpass_type;
dtermLowpassFrequency.val((checked || disabledByDynamicLowpass) ? cutoff : 0).attr('disabled', !checked);
dtermLowpassType.each((i, el) => $(el).val(type).attr('disabled', !checked));
if (checked) {
dtermLowpassDynEnabled.prop('checked', false).change();
}
self.updateFilterWarning();
});
dtermLowpassDynEnabled.change(function() {
const checked = $(this).is(':checked');
let cutoff_min = FILTER_DEFAULT.dterm_lowpass_dyn_min_hz;
let type = FILTER_DEFAULT.dterm_lowpass_type;
if (FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz > 0 && FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz < FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz) {
cutoff_min = FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz;
type = FC.FILTER_CONFIG.dterm_lowpass_type;
}
dtermLowpassDynMinFrequency.val(checked ? cutoff_min : 0).attr('disabled', !checked);
dtermLowpassDynMaxFrequency.attr('disabled', !checked);
dtermLowpassDynType.each((i, el) => $(el).val(type).attr('disabled', !checked));
if (checked) {
dtermLowpassEnabled.prop('checked', false).change();
} else if (FC.FILTER_CONFIG.dterm_lowpass_hz > 0 && !dtermLowpassEnabled.is(':checked')) {
dtermLowpassEnabled.prop('checked', true).change();
}
self.updateFilterWarning();
});
dtermLowpass2Enabled.change(function() {
const checked = $(this).is(':checked');
const cutoff = FC.FILTER_CONFIG.dterm_lowpass2_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass2_hz : FILTER_DEFAULT.dterm_lowpass2_hz;
const type = FC.FILTER_CONFIG.dterm_lowpass2_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass2_type : FILTER_DEFAULT.dterm_lowpass2_type;
dtermLowpass2Frequency.val(checked ? cutoff : 0).attr('disabled', !checked);
dtermLowpass2Type.each((i, el) => $(el).val(type).attr('disabled', !checked));
});
} else {
// firmware 4.3 filter selectors for lowpass 1 and 2
gyroLowpassEnabled.change(function() {
const checked = $(this).is(':checked');
let cutoffMin = FILTER_DEFAULT.gyro_lowpass_dyn_min_hz;
let cutoffMax = FILTER_DEFAULT.gyro_lowpass_dyn_max_hz;
if (FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz > 0 || FC.FILTER_CONFIG.gyro_lowpass_hz > 0) {
// lowpass1 is enabled, set the master switch on, show the label, mode selector and type fields
if (checked) {
gyroLowpassFilterMode.val(FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz > 0 ? 1 : 0).change();
} else {
// the user is disabling Lowpass 1 so set everything to zero
gyroLowpassDynMinFrequency.val(0);
gyroLowpassDynMaxFrequency.val(0);
gyroLowpassFrequency.val(0);
FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz = 0;
FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz = 0;
FC.FILTER_CONFIG.gyro_lowpass_hz = 0;
TuningSliders.updateFiltersInFirmware();
}
} else {
// lowpass 1 is disabled, set the master switch off, only show label
if (checked) {
// user is trying to enable the lowpass filter, but it was off (both cutoffs are zero)
// initialise in dynamic mode with values at sliders, or use defaults
gyroLowpassFilterMode.val(1).change();
cutoffMin = Math.floor(cutoffMin * TuningSliders.sliderGyroFilterMultiplier);
cutoffMax = Math.floor(cutoffMax * TuningSliders.sliderGyroFilterMultiplier);
gyroLowpassDynMinFrequency.val(cutoffMin);
gyroLowpassDynMaxFrequency.val(cutoffMax);
FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz = cutoffMin;
FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz = cutoffMax;
TuningSliders.updateFiltersInFirmware();
}
}
gyroLowpassOption.toggle(checked);
gyroLowpassOptionStatic.toggle(FC.FILTER_CONFIG.gyro_lowpass_hz !== 0);
gyroLowpassOptionDynamic.toggle(FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz !== 0);
});
gyroLowpassFilterMode.change(function() {
const dynMode = parseInt($(this).val());
let cutoff = FILTER_DEFAULT.gyro_lowpass_hz;
let cutoffMin = FILTER_DEFAULT.gyro_lowpass_dyn_min_hz;
let cutoffMax = FILTER_DEFAULT.gyro_lowpass_dyn_max_hz;
if (dynMode) {
// dynamic mode, set the static field min to zero
gyroLowpassFrequency.val(0);
FC.FILTER_CONFIG.gyro_lowpass_hz = 0;
// if dyn min is zero, set dyn min to sliders or default
if (!FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz) {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44) && TuningSliders.sliderGyroFilter) {
cutoffMin = Math.floor(cutoffMin * TuningSliders.sliderGyroFilterMultiplier);
cutoffMax = Math.floor(cutoffMax * TuningSliders.sliderGyroFilterMultiplier);
}
gyroLowpassDynMinFrequency.val(cutoffMin);
gyroLowpassDynMaxFrequency.val(cutoffMax);
FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz = cutoffMin;
FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz = cutoffMax;
}
gyroLowpassOptionStatic.hide();
gyroLowpassOptionDynamic.show();
TuningSliders.updateFiltersInFirmware();
} else {
// static, set the dynamic field min to zero
gyroLowpassDynMinFrequency.val(0);
gyroLowpassDynMaxFrequency.val(0);
FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz = 0;
FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz = 0;
// If static is zero, set the dynamic cutoff field according to sliders or default
if (!FC.FILTER_CONFIG.gyro_lowpass_hz) {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44) && TuningSliders.sliderGyroFilter) {
cutoff = Math.floor(FILTER_DEFAULT.gyro_lowpass_hz * TuningSliders.sliderGyroFilterMultiplier);
}
gyroLowpassFrequency.val(cutoff);
FC.FILTER_CONFIG.gyro_lowpass_hz = cutoff;
}
gyroLowpassOptionStatic.show();
gyroLowpassOptionDynamic.hide();
TuningSliders.updateFiltersInFirmware();
}
});
// switch gyro lpf2
gyroLowpass2Enabled.change(function() {
const checked = $(this).is(':checked');
let cutoff = FC.FILTER_CONFIG.gyro_lowpass2_hz > 0 ? FC.FILTER_CONFIG.gyro_lowpass2_hz : FILTER_DEFAULT.gyro_lowpass2_hz;
if (TuningSliders.sliderGyroFilter) {
cutoff = checked ? Math.floor(FILTER_DEFAULT.gyro_lowpass2_hz * TuningSliders.sliderGyroFilterMultiplier) : 0;
FC.FILTER_CONFIG.gyro_lowpass2_hz = cutoff;
TuningSliders.updateFiltersInFirmware();
}
gyroLowpass2Frequency.val(checked ? cutoff : 0).attr('disabled', !checked);
gyroLowpass2Option.toggle(checked);
self.updateFilterWarning();
});
dtermLowpassEnabled.change(function() {
const checked = $(this).is(':checked');
let cutoffMin = FILTER_DEFAULT.dterm_lowpass_dyn_min_hz;
let cutoffMax = FILTER_DEFAULT.dterm_lowpass_dyn_max_hz;
if (FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz > 0 || FC.FILTER_CONFIG.dterm_lowpass_hz > 0) {
// lowpass1 is enabled, set the master switch on, show the label, mode selector and type fields
if (checked) {
dtermLowpassFilterMode.val(FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz > 0 ? 1 : 0).change();
} else {
// the user is disabling Lowpass 1 so set everything to zero
dtermLowpassDynMinFrequency.val(0);
dtermLowpassDynMaxFrequency.val(0);
dtermLowpassFrequency.val(0);
FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz = 0;
FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz = 0;
FC.FILTER_CONFIG.dterm_lowpass_hz = 0;
TuningSliders.updateFiltersInFirmware();
}
} else {
// lowpass 1 is disabled, set the master switch off, only show label
if (checked) {
// user is trying to enable the lowpass filter, but it was off (both cutoffs are zero)
// initialise in dynamic mode with values at sliders, or use defaults
dtermLowpassFilterMode.val(1).change();
if (TuningSliders.sliderDTermFilter) {
cutoffMin = Math.floor(cutoffMin * TuningSliders.sliderDTermFilterMultiplier);
cutoffMax = Math.floor(cutoffMax * TuningSliders.sliderDTermFilterMultiplier);
}
dtermLowpassDynMinFrequency.val(cutoffMin);
dtermLowpassDynMaxFrequency.val(cutoffMax);
FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz = cutoffMin;
FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz = cutoffMax;
TuningSliders.updateFiltersInFirmware();
}
}
dtermLowpassOption.toggle(checked);
dtermLowpassOptionStatic.toggle(FC.FILTER_CONFIG.dterm_lowpass_hz !== 0);
dtermLowpassOptionDynamic.toggle(FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz !== 0);
});
dtermLowpassFilterMode.change(function() {
const dynMode = parseInt($(this).val());
let cutoff = FILTER_DEFAULT.dterm_lowpass_hz;
let cutoffMin = FILTER_DEFAULT.dterm_lowpass_dyn_min_hz;
let cutoffMax = FILTER_DEFAULT.dterm_lowpass_dyn_max_hz;
if (dynMode) {
// dynamic mode, set the static field min to zero
dtermLowpassFrequency.val(0);
FC.FILTER_CONFIG.dterm_lowpass_hz = 0;
// if dyn min is zero, set dyn min to sliders or default
if (!FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz) {
if (TuningSliders.sliderDTermFilter) {
cutoffMin = Math.floor(cutoffMin * TuningSliders.sliderDTermFilterMultiplier);
cutoffMax = Math.floor(cutoffMax * TuningSliders.sliderDTermFilterMultiplier);
}
dtermLowpassDynMinFrequency.val(cutoffMin);
dtermLowpassDynMaxFrequency.val(cutoffMax);
FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz = cutoffMin;
FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz = cutoffMax;
}
dtermLowpassOptionStatic.hide();
dtermLowpassOptionDynamic.show();
TuningSliders.updateFiltersInFirmware();
} else {
// static, set the dynamic field min to zero
dtermLowpassDynMinFrequency.val(0);
dtermLowpassDynMaxFrequency.val(0);
FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz = 0;
FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz = 0;
// If static is zero, set the dynamic cutoff field according to sliders or default
if (!FC.FILTER_CONFIG.dterm_lowpass_hz) {
if (TuningSliders.sliderDTermFilter) {
cutoff = Math.floor(FILTER_DEFAULT.dterm_lowpass_hz * TuningSliders.sliderDTermFilterMultiplier);
}
dtermLowpassFrequency.val(cutoff);
FC.FILTER_CONFIG.dterm_lowpass_hz = cutoff;
}
dtermLowpassOptionStatic.show();
dtermLowpassOptionDynamic.hide();
TuningSliders.updateFiltersInFirmware();
}
});
dtermLowpass2Enabled.change(function() {
const checked = $(this).is(':checked');
let cutoff = FC.FILTER_CONFIG.dterm_lowpass2_hz > 0 ? FC.FILTER_CONFIG.dterm_lowpass2_hz : FILTER_DEFAULT.dterm_lowpass2_hz;
if (TuningSliders.sliderDTermFilter) {
cutoff = checked ? Math.floor(FILTER_DEFAULT.dterm_lowpass2_hz * TuningSliders.sliderDTermFilterMultiplier) : 0;
FC.FILTER_CONFIG.dterm_lowpass2_hz = cutoff;
TuningSliders.updateFiltersInFirmware();
}
dtermLowpass2Frequency.val(checked ? cutoff : 0).attr('disabled', !checked);
dtermLowpass2Option.toggle(checked);
self.updateFilterWarning();
});
}
$('input[id="yawLowpassEnabled"]').change(function() {
const checked = $(this).is(':checked');
const cutoff = FC.FILTER_CONFIG.yaw_lowpass_hz > 0 ? FC.FILTER_CONFIG.yaw_lowpass_hz : FILTER_DEFAULT.yaw_lowpass_hz;
$('.pid_filter input[name="yawLowpassFrequency"]').val(checked ? cutoff : 0).attr('disabled', !checked);
$('.yawLowpass span.suboption').toggle(checked);
});
// The notch cutoff must be smaller than the notch frecuency
@ -834,17 +1092,37 @@ TABS.pid_tuning.initialize = function (callback) {
}).change();
// Initial state of the filters: enabled or disabled
$('input[id="gyroNotch1Enabled"]').prop('checked', FC.FILTER_CONFIG.gyro_notch_hz != 0).change();
$('input[id="gyroNotch2Enabled"]').prop('checked', FC.FILTER_CONFIG.gyro_notch2_hz != 0).change();
$('input[id="dtermNotchEnabled"]').prop('checked', FC.FILTER_CONFIG.dterm_notch_hz != 0).change();
$('input[id="gyroLowpassEnabled"]').prop('checked', FC.FILTER_CONFIG.gyro_lowpass_hz != 0).change();
$('input[id="gyroLowpassDynEnabled"]').prop('checked', FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz != 0 && FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz < FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz).change();
$('input[id="dtermLowpassDynExpoEnabled"]').prop('checked', FC.FILTER_CONFIG.dyn_lpf_curve_expo != 0).change();
$('input[id="gyroLowpass2Enabled"]').prop('checked', FC.FILTER_CONFIG.gyro_lowpass2_hz != 0).change();
$('input[id="dtermLowpassEnabled"]').prop('checked', FC.FILTER_CONFIG.dterm_lowpass_hz != 0).change();
$('input[id="dtermLowpassDynEnabled"]').prop('checked', FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz != 0 && FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz < FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz).change();
$('input[id="dtermLowpass2Enabled"]').prop('checked', FC.FILTER_CONFIG.dterm_lowpass2_hz != 0).change();
$('input[id="yawLowpassEnabled"]').prop('checked', FC.FILTER_CONFIG.yaw_lowpass_hz != 0).change();
$('input[id="gyroNotch1Enabled"]').prop('checked', FC.FILTER_CONFIG.gyro_notch_hz !== 0).change();
$('input[id="gyroNotch2Enabled"]').prop('checked', FC.FILTER_CONFIG.gyro_notch2_hz !== 0).change();
$('input[id="dtermNotchEnabled"]').prop('checked', FC.FILTER_CONFIG.dterm_notch_hz !== 0).change();
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
gyroLowpassEnabled.prop('checked', FC.FILTER_CONFIG.gyro_lowpass_hz !== 0 || FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz !== 0).change();
dtermLowpassEnabled.prop('checked', FC.FILTER_CONFIG.dterm_lowpass_hz !== 0 || FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz !== 0).change();
if (FC.FILTER_CONFIG.gyro_lowpass_hz > 0) {
gyroLowpassFilterMode.val(0).change();
} else if (FC.FILTER_CONFIG.gyroLowpassDynMinFrequency > 0) {
gyroLowpassFilterMode.val(1).change();
}
if (FC.FILTER_CONFIG.dterm_lowpass_hz > 0) {
dtermLowpassFilterMode.val(0).change();
} else if (FC.FILTER_CONFIG.dtermLowpassDynMinFrequency > 0) {
dtermLowpassFilterMode.val(1).change();
}
} else {
gyroLowpassEnabled.prop('checked', FC.FILTER_CONFIG.gyro_lowpass_hz !== 0).change();
gyroLowpassDynEnabled.prop('checked', FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz !== 0 &&
FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz < FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz).change();
dtermLowpassEnabled.prop('checked', FC.FILTER_CONFIG.dterm_lowpass_hz !== 0).change();
dtermLowpassDynEnabled.prop('checked', FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz !== 0 &&
FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz < FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz).change();
}
gyroLowpass2Enabled.prop('checked', FC.FILTER_CONFIG.gyro_lowpass2_hz !== 0).change();
dtermLowpass2Enabled.prop('checked', FC.FILTER_CONFIG.dterm_lowpass2_hz !== 0).change();
$('input[id="yawLowpassEnabled"]').prop('checked', FC.FILTER_CONFIG.yaw_lowpass_hz !== 0).change();
self.updatePIDColors();
}
@ -973,7 +1251,7 @@ TABS.pid_tuning.initialize = function (callback) {
}
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
FC.FILTER_CONFIG.dterm_lowpass_type = $('.pid_filter select[name="dtermLowpassType"]').val();
FC.FILTER_CONFIG.dterm_lowpass_type = parseInt($('.pid_filter select[name="dtermLowpassType"]').val());
FC.ADVANCED_TUNING.itermThrottleThreshold = parseInt($('.antigravity input[name="itermThrottleThreshold"]').val());
FC.ADVANCED_TUNING.itermAcceleratorGain = parseInt($('.antigravity input[name="itermAcceleratorGain"]').val() * 1000);
}
@ -983,6 +1261,7 @@ TABS.pid_tuning.initialize = function (callback) {
FC.FILTER_CONFIG.gyro_lowpass_type = parseInt($('.pid_filter select[name="gyroLowpassType"]').val());
FC.FILTER_CONFIG.gyro_lowpass2_type = parseInt($('.pid_filter select[name="gyroLowpass2Type"]').val());
FC.FILTER_CONFIG.dterm_lowpass2_hz = parseInt($('.pid_filter input[name="dtermLowpass2Frequency"]').val());
FC.FILTER_CONFIG.dterm_lowpass2_type = parseInt($('.pid_filter select[name="dtermLowpass2Type"]').val());
}
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_40)) {
@ -1013,17 +1292,18 @@ TABS.pid_tuning.initialize = function (callback) {
FC.RC_TUNING.throttleLimitType = $('select[id="throttleLimitType"]').val();
FC.RC_TUNING.throttleLimitPercent = parseInt($('.throttle_limit input[name="throttleLimitPercent"]').val());
FC.FILTER_CONFIG.dterm_lowpass2_type = $('.pid_filter select[name="dtermLowpass2Type"]').val();
FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz = parseInt($('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val());
FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz = parseInt($('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val());
FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz = parseInt($('.pid_filter input[name="dtermLowpassDynMinFrequency"]').val());
FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz = parseInt($('.pid_filter input[name="dtermLowpassDynMaxFrequency"]').val());
if (FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz > 0 && FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz < FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz ) {
FC.FILTER_CONFIG.gyro_lowpass_type = $('.pid_filter select[name="gyroLowpassDynType"]').val();
}
if (FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz > 0 && FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz < FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz ) {
FC.FILTER_CONFIG.dterm_lowpass_type = $('.pid_filter select[name="dtermLowpassDynType"]').val();
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
if (FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz > 0 && FC.FILTER_CONFIG.gyro_lowpass_dyn_min_hz < FC.FILTER_CONFIG.gyro_lowpass_dyn_max_hz ) {
FC.FILTER_CONFIG.gyro_lowpass_type = $('.pid_filter select[name="gyroLowpassDynType"]').val();
}
if (FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz > 0 && FC.FILTER_CONFIG.dterm_lowpass_dyn_min_hz < FC.FILTER_CONFIG.dterm_lowpass_dyn_max_hz ) {
FC.FILTER_CONFIG.dterm_lowpass_type = $('.pid_filter select[name="dtermLowpassDynType"]').val();
}
}
FC.ADVANCED_TUNING.dMinRoll = parseInt($('.pid_tuning input[name="dMinRoll"]').val());
@ -1069,10 +1349,11 @@ TABS.pid_tuning.initialize = function (callback) {
FC.FILTER_CONFIG.dyn_lpf_curve_expo = parseInt($('.pid_filter input[name="dtermLowpassDynExpo"]').val());
FC.ADVANCED_TUNING.vbat_sag_compensation = $('input[id="vbatSagCompensation"]').is(':checked') ? parseInt($('input[name="vbatSagValue"]').val()) : 0;
FC.ADVANCED_TUNING.thrustLinearization = $('input[id="thrustLinearization"]').is(':checked') ? parseInt($('input[name="thrustLinearValue"]').val()) : 0;
FC.FILTER_CONFIG.dyn_lpf_curve_expo = parseInt($('.pid_filter input[name="dtermLowpassExpo"]').val());
FC.FILTER_CONFIG.dyn_notch_count = parseInt($('.pid_filter input[name="dynamicNotchCount"]').val());
FC.TUNING_SLIDERS.slider_pids_mode = TuningSliders.sliderPidsMode;
//rounds slider values to nearies multiple of 5 and passes to the FW. Avoid dividing calc by (* x 100)/5 = 20
//round slider values to nearest multiple of 5 and passes to the FW. Avoid dividing calc by (* x 100)/5 = 20
FC.TUNING_SLIDERS.slider_master_multiplier = Math.round(TuningSliders.sliderMasterMultiplier * 20) * 5;
FC.TUNING_SLIDERS.slider_d_gain = Math.round(TuningSliders.sliderDGain * 20) * 5;
FC.TUNING_SLIDERS.slider_pi_gain = Math.round(TuningSliders.sliderPIGain * 20) * 5;
@ -1488,11 +1769,14 @@ TABS.pid_tuning.initialize = function (callback) {
}
populateFilterTypeSelector('gyroLowpassType', loadFilterTypeValues());
populateFilterTypeSelector('gyroLowpassDynType', loadFilterTypeValues());
populateFilterTypeSelector('gyroLowpass2Type', loadFilterTypeValues());
populateFilterTypeSelector('dtermLowpassType', loadFilterTypeValues());
populateFilterTypeSelector('dtermLowpass2Type', loadFilterTypeValues());
populateFilterTypeSelector('dtermLowpassDynType', loadFilterTypeValues());
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
populateFilterTypeSelector('gyroLowpassDynType', loadFilterTypeValues());
populateFilterTypeSelector('dtermLowpassDynType', loadFilterTypeValues());
}
pid_and_rc_to_form();
@ -1900,6 +2184,8 @@ TABS.pid_tuning.initialize = function (callback) {
const SLIDER_STEP_UPPER = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44) ? 0.05 : 0.1;
const sliderPidsModeSelect = $('#sliderPidsModeSelect');
const sliderGyroFilterModeSelect = $('#sliderGyroFilterModeSelect');
const sliderDTermFilterModeSelect = $('#sliderDTermFilterModeSelect');
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
if (self.retainConfiguration) {
@ -1908,6 +2194,8 @@ TABS.pid_tuning.initialize = function (callback) {
self.saveInitialSettings();
}
sliderPidsModeSelect.val(FC.TUNING_SLIDERS.slider_pids_mode);
sliderGyroFilterModeSelect.val(FC.TUNING_SLIDERS.slider_gyro_filter);
sliderDTermFilterModeSelect.val(FC.TUNING_SLIDERS.slider_dterm_filter);
} else {
$('#dMinSwitch').change(function() {
TuningSliders.setDMinFeatureEnabled($(this).is(':checked'));
@ -1930,9 +2218,9 @@ TABS.pid_tuning.initialize = function (callback) {
// disable slides if Integrated Yaw is enabled or Slider PID mode is set to OFF
$('input[id="useIntegratedYaw"]').change(() => TuningSliders.updatePidSlidersDisplay());
// trigger Slider Display update when PID mode is changed
// trigger Slider Display update when PID / Filter mode is changed
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
$('select[id="sliderPidsModeSelect"]').on('change', function () {
sliderPidsModeSelect.on('change', function () {
const setMode = parseInt($(this).val());
TuningSliders.sliderPidsMode = setMode;
@ -1956,6 +2244,30 @@ TABS.pid_tuning.initialize = function (callback) {
}
}).trigger('change');
sliderGyroFilterModeSelect.change(function() {
const mode = parseInt($(this).find(':selected').val());
if (mode === 0) {
TuningSliders.gyroFilterSliderEnable();
} else {
TuningSliders.gyroFilterSliderDisable();
}
});
sliderDTermFilterModeSelect.change(function() {
const mode = parseInt($(this).find(':selected').val());
if (mode === 0) {
TuningSliders.dtermFilterSliderEnable();
} else {
TuningSliders.dtermFilterSliderDisable();
}
});
// initial gyro mode
sliderGyroFilterModeSelect.val(TuningSliders.sliderGyroFilter);
// initial dterm mode
sliderDTermFilterModeSelect.val(TuningSliders.sliderDTermFilter);
}
let allPidTuningSliders;
@ -2164,13 +2476,10 @@ TABS.pid_tuning.initialize = function (callback) {
TuningSliders.calculateNewDTermFilters();
}
});
// enable Filter sliders button
// enable Filter sliders button (legacy sliders)
$('a.buttonFilterTuningSliders').click(function() {
if (TuningSliders.GyroSliderUnavailable) {
//set Slider mode to ON when re-enabling Sliders
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
FC.TUNING_SLIDERS.slider_gyro_filter = 1;
}
// update switchery dynamically based on defaults
$('input[id="gyroLowpassDynEnabled"]').prop('checked', false).click();
$('input[id="gyroLowpassEnabled"]').prop('checked', true).click();
@ -2179,11 +2488,6 @@ TABS.pid_tuning.initialize = function (callback) {
self.analyticsChanges['GyroFilterTuningSlider'] = "On";
}
if (TuningSliders.DTermSliderUnavailable) {
//set Slider mode to ON when re-enabling Sliders
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
FC.TUNING_SLIDERS.slider_dterm_filter = 1;
}
// update switchery dynamically based on defaults
$('input[id="dtermLowpassDynEnabled"]').prop('checked', false).click();
$('input[id="dtermLowpassEnabled"]').prop('checked', true).click();
$('input[id="dtermLowpass2Enabled"]').prop('checked', false).click();
@ -2200,7 +2504,15 @@ TABS.pid_tuning.initialize = function (callback) {
}
});
// update on filter value or type changes
$('.pid_filter tr:not(.newFilter) input, .pid_filter tr:not(.newFilter) select').on('input', function() {
$('.pid_filter tr:not(.newFilter) input, .pid_filter tr:not(.newFilter) select').on('input', function(e) {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) {
// because legacy / firmware slider inputs for lowpass1 are duplicate the value isn't updated so set it here.
if (e.target.type === 'number') {
$(`.pid_filter input[name="${e.target.name}"]`).val(e.target.value);
} else if (e.target.type === 'select-one') {
$(`.pid_filter select[name="${e.target.name}"]`).val(e.target.value);
}
}
TuningSliders.updateFilterSlidersDisplay();
if (TuningSliders.GyroSliderUnavailable) {
self.analyticsChanges['GyroFilterTuningSlider'] = "Off";
@ -2741,10 +3053,12 @@ TABS.pid_tuning.updateRatesLabels = function() {
};
TABS.pid_tuning.updateFilterWarning = function() {
const gyroDynamicLowpassEnabled = $('input[id="gyroLowpassDynEnabled"]').is(':checked');
const gyroLowpass1Enabled = $('input[id="gyroLowpassEnabled"]').is(':checked');
const dtermDynamicLowpassEnabled = $('input[id="dtermLowpassDynEnabled"]').is(':checked');
const dtermLowpass1Enabled = $('input[id="dtermLowpassEnabled"]').is(':checked');
const gyroLowpassFilterMode = parseInt($('.pid_filter select[name="gyroLowpassFilterMode"]').val());
const gyroDynamicLowpassEnabled = gyroLowpassFilterMode === 1;
const gyroLowpass1Enabled = !gyroLowpassFilterMode;
const dtermLowpassFilterMode = parseInt($('.pid_filter select[name="dtermLowpassFilterMode"]').val());
const dtermDynamicLowpassEnabled = dtermLowpassFilterMode === 1;
const dtermLowpass1Enabled = !dtermLowpassFilterMode;
const warningE = $('#pid-tuning .filterWarning');
const warningDynamicNotchE = $('#pid-tuning .dynamicNotchWarning');
if (!(gyroDynamicLowpassEnabled || gyroLowpass1Enabled) || !(dtermDynamicLowpassEnabled || dtermLowpass1Enabled)) {