Add tuning sliders

10.7.0-preview
IvoFPV 2019-08-09 12:25:28 +02:00
parent a5a9070f98
commit 35dd326778
8 changed files with 951 additions and 33 deletions

View File

@ -1514,10 +1514,14 @@
"message": "Advance",
"description": "Advance of the D Min feature"
},
"pidTuningDMinHelp": {
"pidTuningDMinFeatureHelp": {
"message": "D Min provides a way to have a lower level of D in normal flight and a higher level for quick maneuvers that might cause overshoot, like flips and rolls. It also brings D up during prop wash. Gain adjusts how fast D gets up to its maximum value and is based on gyro to determine sharp moves and propwash events. Advance makes D go up earlier by using setpoint instead of gyro to determine sharp moves.",
"description": "D Min feature helpicon message"
},
"pidTuningDMinHelp": {
"message": "Controls the strength of dampening (D-term) in normal forward flight.<br>With D_min enabled, the Active D-gain changes during flight. In normal forward flight it is at the D_min gains below. During a sharp move or during prop wash, the Active D-gain raises to the Derivative gains specified to the left.<br><br>Full Derivative gains are reached on sharp stick inputs, but only partial are achieved during prop wash.<br>Adjust the D_Min Gain and Advance to control the gain boost sensitivity and timing.",
"description": "D Min helpicon message on PID table titlebar"
},
"pidTuningPidSettings": {
"message": "PID Controller Settings"
},
@ -1643,15 +1647,31 @@
"pidTuningProportional": {
"message": "Proportional"
},
"pidTuningProportionalHelp": {
"message": "Controls the strength of how tightly the machine tracks the sticks (the Setpoint).<br><br>Higher value (gains) provide tighter tracking, but can cause overshoot if too high in proportion to the Derivative (D-term). Think of the P-term as the spring on a car.",
"description": "Proportional Term helpicon message on PID table titlebar"
},
"pidTuningIntegral": {
"message": "Integral"
},
"pidTuningIntegralHelp": {
"message": "Controls the strength of how tightly the machine holds the overall position of the Setpoint.<br>Similar to Proportional, but for longer biases on the craft such as an offset center of gravity (CoG) or persistent outside influence (steady wind).<br><br>Higher gains provide tighter tracking (e.g.: in sweeping turns), but can make the craft feel stiff for commanded stick inputs.<br>If extremely high in proportion to the D-term, can cause slow oscillations.",
"description": "Integral Term helpicon message on PID table titlebar"
},
"pidTuningDerivative": {
"message": "Derivative"
},
"pidTuningDerivativeHelp": {
"message": "Controls the strength of dampening to ANY motion on the craft. For stick moves, the D-term dampens the command. For an outside influence (prop wash OR wind gust) the D-term dampens the influence.<br><br>Higher gains provide more dampening and reduce overshoot by P-term and FF.<br>However, the D-term is VERY sensitive to gyro high frequency vibrations (noise | magnifies by 10x to 100x).<br><br>High frequency noise can cause motor heat and burn out motors if D-gains are too high or the gyro noise is not filtered well (see Filters tab).<br><br>Think of the D-term as the shock absorber on your car, but with the negative inherent property of magnifying high frequency gyro noise.",
"description": "Derivative Term helpicon message on PID table titlebar"
},
"pidTuningFeedforward": {
"message": "Feedforward"
},
"pidTuningFeedforwardHelp": {
"message": "Is an additional pushing term (spring) based on stick input. FF helps the P-term push the craft for commanded stick moves.<br><br>The P-term pushes based on the difference between the commanded Setpoint (deg/sec) and the gyro reading of current rotational rate (deg/sec). FF pushes based on the commanded change of the sticks alone.<br><br>Higher values (gains) will result in a more sharp machine response to stick input.<br>Too high of values may result in some overshoot, increased motor heat, and motor saturation (where motors can not keep up with the desired rate of change).<br>Lower or zero (0) values will result in a slower and smoother response to stick inputs.",
"description": "Feedforward Term helpicon message on PID table titlebar"
},
"pidTuningRcRate": {
"message": "RC Rate"
},
@ -3150,6 +3170,98 @@
"pidTuningNonProfileFilterSettings": {
"message": "Profile independent Filter Settings"
},
"pidTuningFilterSlidersHelp": {
"message": "Sliders to adjust the quad gyro and D-term filtering.<br><br>More Filtering gives you smoother flight, but also increases gyro signal delay (Phase Delay) to the PID loop which will result in worse aggressive flight performance, prop wash handling, stick response and if excessive can cause oscillations.<br><br>Less Filtering reduces the gyro signal delay, but can increase motor temperatures due to the D-term reacting to the high frequency motor vibrations (noise).<br>Additionally, if filtering is excessively low, it will cause a decrease in flight performance (higher noise to signal ratio).",
"description": "Overall helpicon message for filter tuning sliders"
},
"pidTuningSliderLowFiltering": {
"message": "Less Filtering",
"description": "Filter tuning slider low header"
},
"pidTuningSliderDefaultFiltering": {
"message": "Default Filtering",
"description": "Filter tuning slider default header"
},
"pidTuningSliderHighFiltering": {
"message": "More Filtering",
"description": "Filter tuning slider high header"
},
"pidTuningGyroFilterSlider": {
"message": "Gyro Filter Multiplier:",
"description": "Gyro filter tuning slider label"
},
"pidTuningGyroFilterSliderHelp": {
"message": "Raises or Lowers the default Gyro Lowpass Filters in proportion to each-other. The gyro filtering is applied before the PID loop.<br>General motor noise ranges per quad class:<br><br>6\"+ quads - generally within 100hz to 330hz<br>5\" quads - generally within 220hz to 500hz<br>Whoop to 3\" quads - generally within 300hz to 850hz<br><br>Generally, you want to set the slider to have the Gyro Lowpass 1 Dynamic Min/Max Cutoff range cover the above.<br>However, for smoother flights use More Filtering on the slider. To get a more aggressive filter tune, use Less Filtering on the slider.<br><br>With Less Filtering BE CAREFUL to not get radical as to cause a fly-away or burn out motors.<br>Note frame resonance issues, bad bearings, and beat up props may cause you to need more filtering.",
"description": "Gyro filtering tuning slider helpicon message"
},
"pidTuningDTermFilterSlider": {
"message": "D Term Filter Multiplier:",
"description": "D Term filter tuning slider label"
},
"pidTuningDTermFilterSliderHelp": {
"message": "Raises or Lower the default D-term Lowpass Filters in proportion to each-other.<br>The D-term filtering is applied after the PID loop, ONLY on the D-term, since it is the term most sensitive to noise and can amplify any high frequency noise by 10x to 100x plus.<br><br>Generally you want to move the D-term Filter slider up with the Gyro Filter slider. You want to have the D-term filter cutoffs well below the motor noise range for harder D-term filtering then what is applied on the entire gyro signal with the Gyro Filter Multiplier.<br>That recommended differential is built into the default and slider scaling.",
"description": "D Term filtering tuning slider helpicon message"
},
"pidTuningPidSlidersHelp": {
"message": "Sliders to adjust the quad flight characteristics (PID gains)<br><br>Master Multiplier: Raises or Lowers all the PID gains (above) holding the proportional difference between the gains.<br><br>PD Balance: Adjusts the balance (ratio \\ proportional difference) between the P and D terms ('the spring' [p-term] and 'shock absorber' [d-term]).<br><br>PD Gain: Raises or Lowers the P&D gains together - holding the ratio (balance) between the two - for more (or less) PID control authority.<br><br>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": "<span class=\"message-negative\">CAUTION</span>: Pushing sliders this high may cause flyaways, motor damage or unsafe craft behaviour. Please proceed with caution.",
"description": "Warning shown when tuning slider are above safe limits"
},
"pidTuningSlidersDisabled": {
"message": "<strong>Note:</strong> Sliders are disabled because values were changed manually. Clicking the '$t(pidTuningSliderEnableButton.message)' button will activate them again. This will reset the values and any unsaved changes will be lost.",
"description": "Tuning sliders disabled note when manual changes are detected"
},
"pidTuningSliderEnableButton": {
"message": "Enable Sliders",
"description": "Button label for enabling sliders"
},
"pidTuningSliderLow": {
"message": "Low",
"description": "Tuning Slider Low header"
},
"pidTuningSliderDefault": {
"message": "Default",
"description": "Tuning Slider Default header"
},
"pidTuningSliderHigh": {
"message": "High",
"description": "Tuning Slider High header"
},
"pidTuningMasterSlider": {
"message": "Master Multiplier:",
"description": "Master tuning slider label"
},
"pidTuningPDRatioSlider": {
"message": "PD Balance:",
"description": "PD balance tuning slider label"
},
"pidTuningPDGainSlider": {
"message": "P and D Gain:",
"description": "P and D gain tuning slider label"
},
"pidTuningResponseSlider": {
"message": "Stick Response Gain:",
"description": "Response tuning slider label"
},
"pidTuningMasterSliderHelp": {
"message": "Generally larger quads need higher PID gains due to having a lower power to weight ratio.<br><br>Smaller quads (micros) generally need lower PID gains due to a higher power to weight ratio.<br><br>Higher values are for lower authority quads. Lower values are for higher authority quads.",
"description": "Master gain tuning slider helpicon message"
},
"pidTuningPDRatioSliderHelp":{
"message": "Lower PD balance will lower overall response but will also reduce a possibility of fast bounceback after a flip or roll.<br><br>Higher PD balance provides faster reponse and better propwash handling. However, if your PD balance is too high you will get oscillations after a flip or roll and extended oscillations during prop wash.",
"description": "PD balance tuning slider helpicon message"
},
"pidTuningPDGainSliderHelp":{
"message": "Lower P and D gain will result in cooler motors but will result in more propwash oscillation. Too low value may cause the quad to be unstable.<br><br>P and D terms work together to reduce propwash.<br><br>Higher values will increase motor heat and could increase oscillations during smooth forward flight due to higher D term gains.",
"description": "P and D gain tuning slider helpicon message"
},
"pidTuningResponseSliderHelp":{
"message": "Lower values will worsen the stick response and may result in slow bounceback at the end of a flip or roll (I-term windup).<br><br>Higher value will have a better stick response for sharp moves. However, too high of values can cause overshoots and fast bounceback at the end of a flip or roll.",
"description": "Stick response gain tuning slider helpicon message"
},
"pidTuningGyroLowpassFiltersGroup": {
"message": "Gyro Lowpass Filters"
},
@ -5148,15 +5260,6 @@
"pidTuningFilterTip": {
"message": "<b>Gyro Soft Filter:</b> Lowpass filter for gyro. Use lower value for more filtering.<br><b>D Term Filter:</b> Lowpass filter for Dterm. Can affect D tuning. Use lower value for more filtering. <br><b>Yaw Filter:</b> Filters yaw output. It can help on setups with noisy yaw axis."
},
"pidTuningPidTuningTip": {
"message": "<b>Proportional:</b> You will notice a very strong resistant force to any attempts to move the MultiRotor<br><b>Integral:</b> Increase the ability to hold overall initial position and reduce drift, but also increase the delay in returning to initial position.<br><b>Derivative:</b> Improves the speed at which deviations are recovered, but increases noise."
},
"pidTuningPidTuningTipFeedforward": {
"message": "<b>Proportional:</b> You will notice a very strong resistant force to any attempts to move the MultiRotor<br><b>Integral:</b> Increase the ability to hold overall initial position and reduce drift, but also increase the delay in returning to initial position.<br><b>Derivative:</b> Improves the speed at which deviations are recovered, but increases noise<br><b>Feedforward:</b> Usually the PID controller reacts to the error. The Feedforward anticipates the error based on the stick input, giving responsiveness to the quad."
},
"pidTuningPidTuningTipDMin": {
"message": "<b>Proportional:</b> You will notice a very strong resistant force to any attempts to move the MultiRotor<br><b>Integral:</b> Increase the ability to hold overall initial position and reduce drift, but also increase the delay in returning to initial position.<br><b>Derivative:</b> Improves the speed at which deviations are recovered, but increases noise<br><b>Feedforward:</b> Usually the PID controller reacts to the error. The Feedforward anticipates the error based on the stick input, giving responsiveness to the quad.<br><b>D Min:</b> D Min provides a way to have a lower level of D in normal flight and a higher level for quick maneuvers that might cause overshoot, like flips and rolls. It also brings D up during prop wash. A value of zero will disable the feature."
},
"pidTuningRatesTip": {
"message": "Play with the rates and see how those affect the stick curve"
},

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

@ -270,8 +270,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 () {
@ -299,7 +297,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();
}
@ -353,11 +350,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() {
@ -412,18 +407,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();
@ -1412,6 +1403,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">