diff --git a/locales/en/messages.json b/locales/en/messages.json
index 69581428..fdb89071 100644
--- a/locales/en/messages.json
+++ b/locales/en/messages.json
@@ -3222,8 +3222,8 @@
"message": "Sliders to adjust the quad flight characteristics (PID gains)
Master Multiplier: Raises or Lowers all the PID gains (above) holding the proportional difference between the gains.
PD Balance: Adjusts the balance (ratio \\ proportional difference) between the P and D terms ('the spring' [p-term] and 'shock absorber' [d-term]).
PD Gain: Raises or Lowers the P&D gains together - holding the ratio (balance) between the two - for more (or less) PID control authority.
Stick Response Gain: Raises or Lowers the FeedForward gains to control the stick response feel of the quad.",
"description": "Overall helpicon message for PID tuning sliders"
},
- "pidTuningSliderHighWarning": {
- "message": " : Pushing sliders this high may cause flyaways, motor damage or unsafe craft behaviour. Please proceed with caution.",
+ "pidTuningSliderWarning": {
+ "message": " : Current slider positions may cause flyaways, motor damage or unsafe craft behaviour. Please proceed with caution.",
"description": "Warning shown when tuning slider are above safe limits"
},
"pidTuningSlidersDisabled": {
@@ -3234,6 +3234,10 @@
"message": "Enable Sliders",
"description": "Button label for enabling sliders"
},
+ "pidTuningSlidersNonExpertMode": {
+ "message": "Note: Sliders range is restricted because you are not in expert mode. This range should be suitable for most builds and beginners.",
+ "description": "Sliders restricted message"
+ },
"pidTuningSliderLow": {
"message": "Low",
"description": "Tuning Slider Low header"
diff --git a/src/css/tabs-dark/pid_tuning-dark.css b/src/css/tabs-dark/pid_tuning-dark.css
index 43a3ee56..fc3633c1 100644
--- a/src/css/tabs-dark/pid_tuning-dark.css
+++ b/src/css/tabs-dark/pid_tuning-dark.css
@@ -154,7 +154,6 @@
border-bottom: 1px solid #6b6b6b;
}
-.tab-pid_tuning .slidersHighWarning,
-.tab-pid_tuning .slidersFilterHighWarning {
+.tab-pid_tuning .slidersWarning {
background: #542415;
}
diff --git a/src/css/tabs/pid_tuning.css b/src/css/tabs/pid_tuning.css
index 24d0bf06..df44b278 100644
--- a/src/css/tabs/pid_tuning.css
+++ b/src/css/tabs/pid_tuning.css
@@ -751,7 +751,7 @@
opacity: 0.8;
transition: opacity .2s;
margin: 7px;
- background: none;
+ background: var(--boxBackground);
}
.tab-pid_tuning .tuningSlider:hover {
@@ -766,6 +766,13 @@
height: 15px;
}
+.tab-pid_tuning .nonExpertModeSliders.tuningSlider::-webkit-slider-runnable-track {
+ background: linear-gradient(90deg, rgb(197, 197, 197) -50%, rgb(241, 241, 241) 50%, rgb(255, 84, 14) 150%);
+ background-size: 55%;
+ background-position: 44%;
+ background-repeat: no-repeat;
+}
+
.tab-pid_tuning .tuningSlider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 23px;
@@ -830,14 +837,19 @@
width: 30px;
}
-.tab-pid_tuning .slidersHighWarning,
-.tab-pid_tuning .slidersFilterHighWarning {
- background: #ffb3b3;
+.tab-pid_tuning .slidersWarning {
+ background: #ffa3a3;
border: 1px solid red;
font-weight: 600;
font-size: 12px;
}
+.tab-pid_tuning .nonExpertModeSlidersNote {
+ text-align: center;
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+
.tab-pid_tuning .note-button td:nth-child(n) {
padding-left: 7px;
padding-right: 7px;
diff --git a/src/js/TuningSliders.js b/src/js/TuningSliders.js
index 9dbc5474..231b1c09 100644
--- a/src/js/TuningSliders.js
+++ b/src/js/TuningSliders.js
@@ -20,6 +20,8 @@ var TuningSliders = {
cachedPidSliderValues: false,
cachedGyroSliderValues: false,
cachedDTermSliderValues: false,
+
+ expertMode: false,
};
TuningSliders.initialize = function() {
@@ -27,6 +29,7 @@ TuningSliders.initialize = function() {
this.FILTER_DEFAULT = FC.getFilterDefaults();
this.setDMinFeatureEnabled($('#dMinSwitch').is(':checked'));
+ this.setExpertMode($('input[name="expertModeCheckbox"]').is(':checked'));
this.initPidSlidersPosition();
this.initGyroFilterSliderPosition();
@@ -50,6 +53,17 @@ TuningSliders.setDMinFeatureEnabled = function(dMinFeatureEnabled) {
}
};
+TuningSliders.setExpertMode = function(expertMode) {
+ this.expertMode = expertMode;
+ const allTuningSliderElements = $('#tuningMasterSlider, #tuningPDRatioSlider, #tuningPDGainSlider,\
+ #tuningResponseSlider, #tuningGyroFilterSlider, #tuningDTermFilterSlider');
+ if (this.expertMode) {
+ allTuningSliderElements.removeClass('nonExpertModeSliders');
+ } else {
+ allTuningSliderElements.addClass('nonExpertModeSliders');
+ }
+};
+
TuningSliders.scaleSliderValue = function(value) {
if (value > 1) {
return Math.round(((value - 1) * 2 + 1) * 10) / 10;
@@ -90,8 +104,8 @@ TuningSliders.initPidSlidersPosition = function() {
};
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;
+ this.gyroFilterSliderValue = Math.round((FILTER_CONFIG.gyro_lowpass_dyn_min_hz + FILTER_CONFIG.gyro_lowpass_dyn_max_hz + 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;
$('output[name="tuningGyroFilterSlider-number"]').val(this.gyroFilterSliderValue);
$('#tuningGyroFilterSlider').val(this.downscaleSliderValue(this.gyroFilterSliderValue));
};
@@ -139,10 +153,9 @@ TuningSliders.resetDTermFilterSlider = function() {
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_P_GAIN = 70;
const WARNING_I_GAIN = 120;
- const WARNING_DMAX_GAIN = 70;
+ const WARNING_DMAX_GAIN = 60;
const WARNING_DMIN_GAIN = 40;
this.pidSlidersUnavailable = false;
@@ -172,26 +185,21 @@ TuningSliders.updatePidSlidersDisplay = function() {
this.pidSlidersUnavailable = true;
}
- if (this.pidSlidersUnavailable) {
- $('.tuningPIDSliders').hide();
- $('.slidersDisabled').show();
- } else {
- $('.tuningPIDSliders').show();
- $('.slidersDisabled').hide();
+ if (!this.pidSlidersUnavailable) {
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();
- }
+ $('.tuningPIDSliders').toggle(!this.pidSlidersUnavailable);
+ $('.subtab-pid .slidersDisabled').toggle(this.pidSlidersUnavailable);
+ $('.subtab-pid .nonExpertModeSlidersNote').toggle(!this.pidSlidersUnavailable && !this.expertMode);
+ $('.subtab-pid .slidersWarning').toggle((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);
};
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;
+ const WARNING_FILTER_HIGH_GAIN = 1.4;
+ const WARNING_FILTER_LOW_GAIN = 0.7;
this.filterGyroSliderUnavailable = false;
this.filterDTermSliderUnavailable = false;
@@ -222,27 +230,22 @@ TuningSliders.updateFilterSlidersDisplay = function() {
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();
- }
+ $('.tuningFilterSliders').toggle(!(this.filterGyroSliderUnavailable && this.filterDTermSliderUnavailable));
+ $('.subtab-filter .slidersDisabled').toggle(this.filterGyroSliderUnavailable || this.filterDTermSliderUnavailable);
+ $('.subtab-filter .nonExpertModeSlidersNote').toggle((!this.filterGyroSliderUnavailable || !this.filterDTermSliderUnavailable) && !this.expertMode);
+ $('.subtab-filter .slidersWarning').toggle(((this.gyroFilterSliderValue >= WARNING_FILTER_HIGH_GAIN ||
+ this.gyroFilterSliderValue <= WARNING_FILTER_LOW_GAIN) && !this.filterGyroSliderUnavailable) ||
+ ((this.dtermFilterSliderValue >= WARNING_FILTER_HIGH_GAIN ||
+ this.dtermFilterSliderValue <= WARNING_FILTER_LOW_GAIN) && !this.filterDTermSliderUnavailable));
};
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
+ const MAX_PID_GAIN = 200;
+ const MAX_DMIN_GAIN = 100;
+ const MAX_FF_GAIN = 2000;
+
if (this.dMinFeatureEnabled) {
//dmin
ADVANCED_TUNING.dMinRoll = Math.round(this.PID_DEFAULT[3] * this.PDGainSliderValue);
@@ -277,16 +280,16 @@ TuningSliders.calculateNewPids = function() {
//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);
+ PIDs[j][i] = Math.min(Math.round(PIDs[j][i] * this.MasterSliderValue), MAX_PID_GAIN);
}
}
- 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);
+ ADVANCED_TUNING.feedforwardRoll = Math.min(Math.round(ADVANCED_TUNING.feedforwardRoll * this.MasterSliderValue), MAX_FF_GAIN);
+ ADVANCED_TUNING.feedforwardPitch = Math.min(Math.round(ADVANCED_TUNING.feedforwardPitch * this.MasterSliderValue), MAX_FF_GAIN);
+ ADVANCED_TUNING.feedforwardYaw = Math.min(Math.round(ADVANCED_TUNING.feedforwardYaw * this.MasterSliderValue), MAX_FF_GAIN);
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);
+ ADVANCED_TUNING.dMinRoll = Math.min(Math.round(ADVANCED_TUNING.dMinRoll * this.MasterSliderValue), MAX_DMIN_GAIN);
+ ADVANCED_TUNING.dMinPitch = Math.min(Math.round(ADVANCED_TUNING.dMinPitch * this.MasterSliderValue), MAX_DMIN_GAIN);
+ ADVANCED_TUNING.dMinYaw = Math.min(Math.round(ADVANCED_TUNING.dMinYaw * this.MasterSliderValue), MAX_DMIN_GAIN);
}
$('output[name="tuningMasterSlider-number"]').val(this.MasterSliderValue);
@@ -341,4 +344,4 @@ TuningSliders.calculateNewDTermFilters = function() {
$('.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);
-};
\ No newline at end of file
+};
diff --git a/src/js/tabs/pid_tuning.js b/src/js/tabs/pid_tuning.js
index 05695eee..dfd3b7dc 100644
--- a/src/js/tabs/pid_tuning.js
+++ b/src/js/tabs/pid_tuning.js
@@ -11,6 +11,7 @@ TABS.pid_tuning = {
SETPOINT_WEIGHT_RANGE_HIGH: 20,
SETPOINT_WEIGHT_RANGE_LEGACY: 2.54,
activeSubtab: 'pid',
+ analyticsChanges: {},
};
TABS.pid_tuning.initialize = function (callback) {
@@ -1434,6 +1435,18 @@ TABS.pid_tuning.initialize = function (callback) {
// filter and tuning sliders
TuningSliders.initialize();
+ self.analyticsChanges = {};
+
+ // UNSCALED non expert slider constrain values
+ const NON_EXPERT_SLIDER_MAX = 1.25;
+ const NON_EXPERT_SLIDER_MIN = 0.7;
+
+ $('input[name="expertModeCheckbox"]').change(function() {
+ TuningSliders.setExpertMode($(this).is(':checked'));
+ TuningSliders.updatePidSlidersDisplay();
+ TuningSliders.updateFilterSlidersDisplay();
+ });
+
$('#dMinSwitch').change(function() {
TuningSliders.setDMinFeatureEnabled($(this).is(':checked'));
// switch dmin and dmax values on dmin on/off if sliders available
@@ -1462,6 +1475,13 @@ TABS.pid_tuning.initialize = function (callback) {
} else {
slider.attr('step', 0.1);
}
+ if (!TuningSliders.expertMode) {
+ if (slider.val() > NON_EXPERT_SLIDER_MAX) {
+ slider.val(NON_EXPERT_SLIDER_MAX);
+ } else if (slider.val() < NON_EXPERT_SLIDER_MIN) {
+ slider.val(NON_EXPERT_SLIDER_MIN);
+ }
+ }
const scaledValue = TuningSliders.scaleSliderValue(slider.val());
if (slider.is('#tuningMasterSlider')) {
TuningSliders.MasterSliderValue = scaledValue;
@@ -1473,6 +1493,7 @@ TABS.pid_tuning.initialize = function (callback) {
TuningSliders.ResponseSliderValue = scaledValue;
}
TuningSliders.calculateNewPids();
+ self.analyticsChanges['PidTuningSliders'] = "On";
});
$('#tuningMasterSlider, #tuningPDRatioSlider, #tuningPDGainSlider, #tuningResponseSlider').mousedown(function() {
// adjust step for more smoothness above 1x on mousedown
@@ -1514,18 +1535,28 @@ TABS.pid_tuning.initialize = function (callback) {
if ($('input[id="useIntegratedYaw"]').is(':checked')) {
$('input[id="useIntegratedYaw"]').prop('checked', true).click();
}
+ self.analyticsChanges['PidTuningSliders'] = "On";
});
// filter slider inputs
$('#tuningGyroFilterSlider, #tuningDTermFilterSlider').on('input', function() {
const slider = $(this);
+ if (!TuningSliders.expertMode) {
+ if (slider.val() > NON_EXPERT_SLIDER_MAX) {
+ slider.val(NON_EXPERT_SLIDER_MAX);
+ } else if (slider.val() < NON_EXPERT_SLIDER_MIN) {
+ slider.val(NON_EXPERT_SLIDER_MIN);
+ }
+ }
const scaledValue = TuningSliders.scaleSliderValue(slider.val());
if (slider.is('#tuningGyroFilterSlider')) {
TuningSliders.gyroFilterSliderValue = scaledValue;
TuningSliders.calculateNewGyroFilters();
+ self.analyticsChanges['GyroFilterTuningSlider'] = "On";
} else if (slider.is('#tuningDTermFilterSlider')) {
TuningSliders.dtermFilterSliderValue = scaledValue;
TuningSliders.calculateNewDTermFilters();
+ self.analyticsChanges['DTermFilterTuningSlider'] = "On";
}
});
$('#tuningGyroFilterSlider, #tuningDTermFilterSlider').mouseup(function() {
@@ -1552,30 +1583,42 @@ TABS.pid_tuning.initialize = function (callback) {
$('input[id="gyroLowpassEnabled"]').prop('checked', true).click();
$('input[id="gyroLowpass2Enabled"]').prop('checked', false).click();
TuningSliders.resetGyroFilterSlider();
+ self.analyticsChanges['GyroFilterTuningSlider'] = "On";
}
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();
+ self.analyticsChanges['DTermFilterTuningSlider'] = "On";
}
});
// update on pid table inputs
- $('#pid_main input').on('input', () => TuningSliders.updatePidSlidersDisplay());
+ $('#pid_main input').on('input', function() {
+ TuningSliders.updatePidSlidersDisplay();
+ self.analyticsChanges['PidTuningSliders'] = "Off";
+ });
// update on filter value or type changes
- $('.pid_filter input, .pid_filter select').on('input', () => TuningSliders.updateFilterSlidersDisplay());
+ $('.pid_filter input, .pid_filter select').on('input', function() {
+ TuningSliders.updateFilterSlidersDisplay();
+ if (TuningSliders.filterGyroSliderUnavailable) {
+ self.analyticsChanges['GyroFilterTuningSlider'] = "Off";
+ }
+ if (TuningSliders.filterDTermSliderUnavailable) {
+ self.analyticsChanges['DTermFilterTuningSlider'] = "Off";
+ }
+ });
// update on filter switch changes
- $('.inputSwitch input').change(() => TuningSliders.updateFilterSlidersDisplay());
+ $('.inputSwitch input').change(() => $('.pid_filter input').trigger('input'));
$('.tuningHelp').hide();
} else {
$('.tuningPIDSliders').hide();
- $('.slidersDisabled').hide();
- $('.slidersHighWarning').hide();
$('.tuningFilterSliders').hide();
- $('.slidersFilterDisabled').hide();
- $('.slidersFilterHighWarning').hide();
+ $('.slidersDisabled').hide();
+ $('.slidersWarning').hide();
+ $('.nonExpertModeSlidersNote').hide();
$('.tuningHelpSliders').hide();
}
@@ -1622,6 +1665,9 @@ TABS.pid_tuning.initialize = function (callback) {
GUI.log(i18n.getMessage('pidTuningEepromSaved'));
});
+
+ analytics.sendChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges);
+ self.analyticsChanges = {};
});
// Setup model for rates preview
diff --git a/src/tabs/pid_tuning.html b/src/tabs/pid_tuning.html
index 5be61a7f..48a5804d 100644
--- a/src/tabs/pid_tuning.html
+++ b/src/tabs/pid_tuning.html
@@ -71,8 +71,8 @@