diff --git a/locales/en/messages.json b/locales/en/messages.json index c29bba7b..64349869 100644 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -2741,6 +2741,67 @@ "pidTuningVbatPidCompensationHelp": { "message": "Increases the PID values to compensate when Vbat gets lower. This will give more constant flight characteristics throughout the flight. The amount of compensation that is applied is calculated from the $t(powerBatteryMaximum.message) set in the $t(tabPower.message) page, so make sure that is set to something appropriate." }, + "pidTuningItermRotation": { + "message": "I Term Rotation" + }, + "pidTuningItermRotationHelp": { + "message": "Rotates the current I Term vector properly to other axes as the quad rotates when yawing continuously during rolls and when performing funnels and other tricks. Very appreciated by LOS acro pilots." + }, + "pidTuningSmartFeedforward": { + "message": "Smart Feedforward" + }, + "pidTuningSmartFeedforwardHelp": { + "message": "Reduces the effect of the F Term in the PIDF. When both the P Term and the F Term are active at the same moment, it only uses the larger of the two, avoiding overshoots without the needing to raise D, but also reduces the responsiveness effect produced by the F term when added to P." + }, + "pidTuningItermRelax": { + "message": "I Term Relax" + }, + "pidTuningItermRelaxHelp": { + "message": "Limits the accumulation of I Term when fast movements happen. This helps specially to reduce the bounceback at the end of rolls and other fast movements. You can choose the axes in which this is active, and if the fast movement is detectd using the Gyro or the Setpoint (stick)." + }, + "pidTuningItermRelaxAxes": { + "message": "Axes:" + }, + "pidTuningItermRelaxAxesOptionRP": { + "message": "RP" + }, + "pidTuningItermRelaxAxesOptionRPY": { + "message": "RPY" + }, + "pidTuningItermRelaxAxesOptionRPInc": { + "message": "RP (increment only)" + }, + "pidTuningItermRelaxAxesOptionRPYInc": { + "message": "RPY (increment only)" + }, + "pidTuningItermRelaxType": { + "message": "Type:" + }, + "pidTuningItermRelaxTypeOptionGyro": { + "message": "Gyro" + }, + "pidTuningItermRelaxTypeOptionSetpoint": { + "message": "Setpoint" + }, + "pidTuningAbsoluteControlGain": { + "message": "Absolute Control" + }, + "pidTuningAbsoluteControlGainHelp": { + "message": "This feature solves some underlying problems of I Term Rotation and should hopefully replace it at some point. The feature accumulates the absolute gyro error in quad coordinates and mixes a proportional correction into the setpoint. It needs to have the iterm_relax enable for RPY." + }, + "pidTuningThrottleBoost": { + "message": "Throttle Boost" + }, + "pidTuningThrottleBoostHelp": { + "message": "This feature allows throttle to be temporarily boosted to the up to down-side to increase acceleration torque to the motors, providing a much faster throttle response." + }, + "pidTuningAcroTrainerAngleLimit": { + "message": "Acro Trainer Angle Limit" + }, + "pidTuningAcroTrainerAngleLimitHelp": { + "message": "Adds a new angle limiting mode for pilots who are learning to fly in acro mode. The range valid is 10-80 (a value of 0 deactivates it)" + }, + "configHelp2": { "message": "Arbitrary board rotation in degrees, to allow mounting it sideways / upside down / rotated etc. When running external sensors, use the sensor alignments (Gyro, Acc, Mag) to define sensor position independent from board orientation. " }, diff --git a/src/css/tabs/pid_tuning.css b/src/css/tabs/pid_tuning.css index 34392add..8879ab88 100644 --- a/src/css/tabs/pid_tuning.css +++ b/src/css/tabs/pid_tuning.css @@ -281,6 +281,10 @@ width: 33%; } +.tab-pid_tuning table.compensation tr { + height: 25px; +} + .tab-pid_tuning table.compensation td { width: 60%; padding-left: 5px; @@ -289,12 +293,24 @@ .tab-pid_tuning table.compensation td:first-child { width: 10%; + text-align: right; } .tab-pid_tuning table.compensation td:last-child { width: 30%; } +.tab-pid_tuning table.compensation .suboption { + margin-left: 40px; +} + +.tab-pid_tuning table.compensation .suboption select{ + text-align-last: left; + font-size: 1.1em; + color: darkslategrey; + padding-left: 5px; +} + .tab-pid_tuning .pidTuningFeatures td { padding: 5px; } diff --git a/src/js/fc.js b/src/js/fc.js index f5216050..7dfe0a9d 100644 --- a/src/js/fc.js +++ b/src/js/fc.js @@ -369,6 +369,13 @@ var FC = { levelSensitivity: 0, itermThrottleThreshold: 0, itermAcceleratorGain: 0, + itermRotation: 0, + smartFeedforward: 0, + itermRelax: 0, + itermRelaxType: 0, + absoluteControlGain: 0, + throttleBoost: 0, + acroTrainerAngleLimit: 0, }; SENSOR_CONFIG = { diff --git a/src/js/msp/MSPHelper.js b/src/js/msp/MSPHelper.js index 235a3973..3f5964b3 100644 --- a/src/js/msp/MSPHelper.js +++ b/src/js/msp/MSPHelper.js @@ -888,13 +888,25 @@ MspHelper.prototype.process_data = function(dataHandler) { if (semver.gte(CONFIG.apiVersion, "1.24.0")) { ADVANCED_TUNING.levelAngleLimit = data.readU8(); ADVANCED_TUNING.levelSensitivity = data.readU8(); - } - if (semver.gte(CONFIG.apiVersion, "1.36.0")) { - ADVANCED_TUNING.itermThrottleThreshold = data.readU16(); - ADVANCED_TUNING.itermAcceleratorGain = data.readU16(); - } - if (semver.gte(CONFIG.apiVersion, "1.39.0")) { - ADVANCED_TUNING.dtermSetpointWeight = data.readU16(); + + if (semver.gte(CONFIG.apiVersion, "1.36.0")) { + ADVANCED_TUNING.itermThrottleThreshold = data.readU16(); + ADVANCED_TUNING.itermAcceleratorGain = data.readU16(); + + if (semver.gte(CONFIG.apiVersion, "1.39.0")) { + ADVANCED_TUNING.dtermSetpointWeight = data.readU16(); + + if (semver.gte(CONFIG.apiVersion, "1.40.0")) { + ADVANCED_TUNING.itermRotation = data.readU8(); + ADVANCED_TUNING.smartFeedforward = data.readU8(); + ADVANCED_TUNING.itermRelax = data.readU8(); + ADVANCED_TUNING.itermRelaxType = data.readU8(); + ADVANCED_TUNING.absoluteControlGain = data.readU8(); + ADVANCED_TUNING.throttleBoost = data.readU8(); + ADVANCED_TUNING.acroTrainerAngleLimit = data.readU8(); + } + } + } } } break; @@ -1538,16 +1550,30 @@ MspHelper.prototype.crunch = function(code) { .push8(ADVANCED_TUNING.itermThrottleGain) .push16(ADVANCED_TUNING.pidMaxVelocity) .push16(ADVANCED_TUNING.pidMaxVelocityYaw); + if (semver.gte(CONFIG.apiVersion, "1.24.0")) { buffer.push8(ADVANCED_TUNING.levelAngleLimit) .push8(ADVANCED_TUNING.levelSensitivity); - } - if (semver.gte(CONFIG.apiVersion, "1.36.0")) { - buffer.push16(ADVANCED_TUNING.itermThrottleThreshold) - .push16(ADVANCED_TUNING.itermAcceleratorGain); - } - if (semver.gte(CONFIG.apiVersion, "1.39.0")) { - buffer.push16(ADVANCED_TUNING.dtermSetpointWeight); + + if (semver.gte(CONFIG.apiVersion, "1.36.0")) { + buffer.push16(ADVANCED_TUNING.itermThrottleThreshold) + .push16(ADVANCED_TUNING.itermAcceleratorGain); + + if (semver.gte(CONFIG.apiVersion, "1.39.0")) { + buffer.push16(ADVANCED_TUNING.dtermSetpointWeight); + + if (semver.gte(CONFIG.apiVersion, "1.40.0")) { + buffer.push8(ADVANCED_TUNING.itermRotation) + .push8(ADVANCED_TUNING.smartFeedforward) + .push8(ADVANCED_TUNING.itermRelax) + .push8(ADVANCED_TUNING.itermRelaxType) + .push8(ADVANCED_TUNING.absoluteControlGain) + .push8(ADVANCED_TUNING.throttleBoost) + .push8(ADVANCED_TUNING.acroTrainerAngleLimit); + } + + } + } } } // only supports 1 version pre bf 3.0 diff --git a/src/js/tabs/pid_tuning.js b/src/js/tabs/pid_tuning.js index 85d3d1ae..c29c574b 100755 --- a/src/js/tabs/pid_tuning.js +++ b/src/js/tabs/pid_tuning.js @@ -299,6 +299,86 @@ TABS.pid_tuning.initialize = function (callback) { $('.dtermLowpass2').hide(); } + if (semver.gte(CONFIG.apiVersion, "1.40.0")) { + + // I Term Rotation + $('input[id="itermrotation"]').prop('checked', ADVANCED_TUNING.itermRotation !== 0); + + // Smart Feed Forward + $('input[id="smartfeedforward"]').prop('checked', ADVANCED_TUNING.smartFeedforward !== 0); + + // I Term Relax + var itermRelaxCheck = $('input[id="itermrelax"]'); + + itermRelaxCheck.prop('checked', ADVANCED_TUNING.itermRelax !== 0); + $('select[id="itermrelaxAxes"]').val(ADVANCED_TUNING.itermRelax > 0 ? ADVANCED_TUNING.itermRelax : 1); + $('select[id="itermrelaxType"]').val(ADVANCED_TUNING.itermRelaxType); + + itermRelaxCheck.change(function() { + var checked = $(this).is(':checked'); + + if (checked) { + $('.itermrelax .suboption').show(); + } else { + $('.itermrelax .suboption').hide(); + } + }); + itermRelaxCheck.change(); + + // Absolute Control + var absoluteControlGainNumberElement = $('input[name="absoluteControlGain-number"]'); + var absoluteControlGainRangeElement = $('input[name="absoluteControlGain-range"]'); + + absoluteControlGainNumberElement.change(function () { + absoluteControlGainRangeElement.val($(this).val()); + }); + absoluteControlGainRangeElement.change(function () { + absoluteControlGainNumberElement.val($(this).val()); + }); + absoluteControlGainNumberElement.val(ADVANCED_TUNING.absoluteControlGain).change(); + + // Throttle Boost + var throttleBoostNumberElement = $('input[name="throttleBoost-number"]'); + var throttleBoostRangeElement = $('input[name="throttleBoost-range"]'); + + throttleBoostNumberElement.change(function () { + throttleBoostRangeElement.val($(this).val()); + }); + throttleBoostRangeElement.change(function () { + throttleBoostNumberElement.val($(this).val()); + }); + throttleBoostNumberElement.val(ADVANCED_TUNING.throttleBoost).change(); + + // Acro Trainer + var acroTrainerAngleLimitNumberElement = $('input[name="acroTrainerAngleLimit-number"]'); + var acroTrainerAngleLimitRangeElement = $('input[name="acroTrainerAngleLimit-range"]'); + + var validateAcroTrainerAngle = function(value) { + // The minimum acro trainer angle is 10, but we must let zero too to deactivate it + if (value > 0 && value < 10) { + value = 10; + } + acroTrainerAngleLimitRangeElement.val(value); + acroTrainerAngleLimitNumberElement.val(value); + } + + acroTrainerAngleLimitNumberElement.change(function () { + validateAcroTrainerAngle($(this).val()); + }); + acroTrainerAngleLimitRangeElement.change(function () { + validateAcroTrainerAngle($(this).val()); + }); + acroTrainerAngleLimitNumberElement.val(ADVANCED_TUNING.acroTrainerAngleLimit).change(); + + } else { + $('.itermrotation').hide(); + $('.smartfeedforward').hide(); + $('.itermrelax').hide(); + $('.absoluteControlGain').hide(); + $('.throttleBoost').hide(); + $('.acroTrainerAngleLimit').hide(); + } + $('input[id="gyroNotch1Enabled"]').change(function() { var checked = $(this).is(':checked'); var hz = FILTER_CONFIG.gyro_notch_hz > 0 ? FILTER_CONFIG.gyro_notch_hz : DEFAULT.gyro_notch_hz; @@ -527,6 +607,21 @@ TABS.pid_tuning.initialize = function (callback) { FILTER_CONFIG.gyro_lowpass2_type = parseInt($('.pid_filter select[name="gyroLowpass2Type"]').val()); FILTER_CONFIG.dterm_lowpass2_hz = parseInt($('.pid_filter input[name="dtermLowpass2Frequency"]').val()); } + + if (semver.gte(CONFIG.apiVersion, "1.40.0")) { + ADVANCED_TUNING.itermRotation = $('input[id="itermrotation"]').is(':checked') ? 1 : 0; + ADVANCED_TUNING.smartFeedforward = $('input[id="smartfeedforward"]').is(':checked') ? 1 : 0; + + ADVANCED_TUNING.itermRelax = $('input[id="itermrelax"]').is(':checked') ? $('select[id="itermrelaxAxes"]').val() : 0; + ADVANCED_TUNING.itermRelaxType = $('input[id="itermrelax"]').is(':checked') ? $('select[id="itermrelaxType"]').val() : 0; + + ADVANCED_TUNING.absoluteControlGain = $('input[name="absoluteControlGain-number"]').val(); + + ADVANCED_TUNING.throttleBoost = $('input[name="throttleBoost-number"]').val(); + + ADVANCED_TUNING.acroTrainerAngleLimit = $('input[name="acroTrainerAngleLimit-number"]').val(); + } + } function showAllPids() { diff --git a/src/tabs/pid_tuning.html b/src/tabs/pid_tuning.html index 37c370cf..f22496a3 100755 --- a/src/tabs/pid_tuning.html +++ b/src/tabs/pid_tuning.html @@ -293,7 +293,7 @@ - + @@ -322,8 +322,60 @@ + + + + + +
+ +
+
+ + + + + + + +
+ +
+
+ + + + + + + +
+ +
+
+ + + + + + +
+ +
+
+ + + - +
+ + + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + +
+ + +