From 1da5219bf2c2ace82d01e3ef823a04c36f3cdedf Mon Sep 17 00:00:00 2001 From: mikeller Date: Sat, 27 Aug 2016 12:34:05 +1200 Subject: [PATCH] Added new rc rate calculation to rates curve. Removed SUPER_EXPO feature for >= 3.0. Added support for RC Expo Power setting. fixed titlebar in pid tuning tab request from @mikeller #252 fixed titlebar from pid tuning and accel --- _locales/en/messages.json | 22 +++---- js/Features.js | 29 ++++++--- js/RateCurve.js | 55 +++++++++------- js/fc.js | 3 +- js/msp/MSPHelper.js | 8 +++ tabs/pid_tuning.css | 37 ++--------- tabs/pid_tuning.html | 37 +++++------ tabs/pid_tuning.js | 133 +++++++++++++++++++------------------- 8 files changed, 165 insertions(+), 159 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 32232236..29abf7a5 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -850,6 +850,9 @@ "pidTuningRcRate": { "message": "RC Rate" }, + "pidTuningMaxVel": { + "message": "Max Vel (deg/s)" + }, "pidTuningRate": { "message": "Rate" }, @@ -872,19 +875,10 @@ "message": "Frequency" }, "pidTuningRatesCurve": { - "message": "Rates" - }, - "pidTuningMaxAngularVelRoll": { - "message": "Max roll speed (deg/s):" - }, - "pidTuningMaxAngularVelPitch": { - "message": "Max pitch speed (deg/s):" - }, - "pidTuningMaxAngularVelYaw": { - "message": "Max yaw speed (deg/s):" + "message": "Rates" }, "throttle": { - "message": "Throttle" + "message": "Throttle" }, "pidTuningButtonSave": { "message": "Save" @@ -1607,6 +1601,12 @@ "pidTuningYawJumpPreventionHelp": { "message": "Keeps the craft from jumping up at the end of yaws. Higher number gives more damping at the end of yaw moves (works like old yaw D, which was not a real D like on other axis)" }, + "pidTuningRcExpoPower": { + "message": "RC Expo Power" + }, + "pidTuningRcExpoPowerHelp": { + "message": "The exponent that is used when calculating RC Expo. In Betaflight versions prior to 3.0, value is fixed at 3." + }, "pidTuningLevel": { "message": "Angle/Horizon" }, diff --git a/js/Features.js b/js/Features.js index b8d39198..934cb1e9 100644 --- a/js/Features.js +++ b/js/Features.js @@ -46,17 +46,26 @@ var Features = function (config) { ); } - if (config.flightControllerVersion !== '' && semver.gte(config.flightControllerVersion, "3.0.0")) { - features.push( - {bit: 18, group: 'other', name: 'OSD', haveTip: true} - ); - } + if (config.flightControllerVersion !== '') { + if (semver.gte(config.flightControllerVersion, "2.8.0")) { + features.push( + {bit: 22, group: 'other', name: 'AIRMODE'} + ); + } + + if (semver.gte(config.flightControllerVersion, "2.8.0") && !semver.gte(config.flightControllerVersion, "3.0.0")) { + features.push( + {bit: 23, group: 'pidTuning', name: 'SUPEREXPO_RATES'} + ); + } + + if (semver.gte(config.flightControllerVersion, "3.0.0")) { + features.push( + {bit: 18, group: 'other', name: 'OSD', haveTip: true} + ); + } + - if (config.flightControllerVersion !== '' && semver.gte(config.flightControllerVersion, "2.8.0")) { - features.push( - {bit: 22, group: 'other', name: 'AIRMODE'}, - {bit: 23, group: 'pidTuning', name: 'SUPEREXPO_RATES'} - ); } self._features = features; diff --git a/js/RateCurve.js b/js/RateCurve.js index 92a76740..717adb7d 100755 --- a/js/RateCurve.js +++ b/js/RateCurve.js @@ -9,18 +9,24 @@ var RateCurve = function (useLegacyCurve) { this.constrain = function (value, min, max) { return Math.max(min, Math.min(value, max)); - } + }; - this.rcCommand = function (rcData, rcRate, rcExpo) { - var tmp = Math.min(Math.abs(rcData - midRc), 500) / 100; + this.rcCommand = function (rcData, rcRate) { + var tmp = Math.min(Math.abs(rcData - midRc), 500); + rcRate = rcRate; - var result = ((2500 + rcExpo * (tmp * tmp - 25)) * tmp * rcRate / 2500).toFixed(0); - if (rcData < midRc) { + if (rcRate > 2) { + rcRate = rcRate + (rcRate - 2) * 14.54; + } + + var result = tmp * rcRate; + + if (rcData < midRc) { result = -result; } return result; - } + }; this.drawRateCurve = function (rate, rcRate, rcExpo, superExpoActive, maxAngularVel, context, width, height) { var canvasHeightScale = height / (2 * maxAngularVel); @@ -42,7 +48,7 @@ var RateCurve = function (useLegacyCurve) { context.stroke(); context.restore(); - } + }; this.drawLegacyRateCurve = function (rate, rcRate, rcExpo, context, width, height) { // math magic by englishman @@ -55,28 +61,31 @@ var RateCurve = function (useLegacyCurve) { context.quadraticCurveTo(width * 11 / 20, height - ((rateY / 2) * (1 - rcExpo)), width, height - rateY); context.stroke(); } -} +}; RateCurve.prototype.rcCommandRawToDegreesPerSecond = function (rcData, rate, rcRate, rcExpo, superExpoActive) { var angleRate; if (rate !== undefined && rcRate !== undefined && rcExpo !== undefined) { - rate = rate * 100; - rcRate = rcRate * 100; - rcExpo = rcExpo * 100; - var inputValue = this.rcCommand(rcData, rcRate, rcExpo); + var inputValue = this.rcCommand(rcData, rcRate); + var maxRc = 500 * rcRate; - if (superExpoActive) { - var rcFactor = Math.abs(inputValue) / (500 * rcRate / 100); - rcFactor = 1 / this.constrain(1 - rcFactor * rate / 100, 0.01, 1); - - angleRate = rcFactor * 27 * inputValue / 16; - } else { - angleRate = (rate + 27) * inputValue / 16; + if (rcExpo > 0) { + var absRc = Math.abs(inputValue) / maxRc; + inputValue = inputValue * ((rcExpo * absRc * absRc * absRc) + absRc * (1-rcExpo)); // absRc should be wrapped in function using expo power } - angleRate = this.constrain(angleRate, -8190, 8190); // Rate limit protection - angleRate = angleRate >> 2; // the shift by 2 is to counterbalance the divide by 4 that occurs on the gyro to calculate the error + var rcInput = inputValue / maxRc; + + if (superExpoActive) { + var rcFactor = 1 / this.constrain(1 - Math.abs(rcInput) * rate, 0.01, 1); + angleRate = 200 * rcRate * rcInput; // 200 should be variable checked on version (older versions it's 205,9) + angleRate = angleRate * rcFactor; + } else { + angleRate = (((rate * 100) + 27) * inputValue / 16) / 4.1; // Only applies to old versions ? + } + + angleRate = this.constrain(angleRate, -1998, 1998); // Rate limit protection } return angleRate; @@ -89,7 +98,7 @@ RateCurve.prototype.getMaxAngularVel = function (rate, rcRate, rcExpo, superExpo } return maxAngularVel; -} +}; RateCurve.prototype.draw = function (rate, rcRate, rcExpo, superExpoActive, maxAngularVel, context) { if (rate !== undefined && rcRate !== undefined && rcExpo !== undefined) { @@ -102,4 +111,4 @@ RateCurve.prototype.draw = function (rate, rcRate, rcExpo, superExpoActive, maxA this.drawRateCurve(rate, rcRate, rcExpo, superExpoActive, maxAngularVel, context, width, height); } } -} +}; diff --git a/js/fc.js b/js/fc.js index bd237c23..812b0d60 100644 --- a/js/fc.js +++ b/js/fc.js @@ -112,7 +112,8 @@ var FC = { throttle_EXPO: 0, dynamic_THR_breakpoint: 0, RC_YAW_EXPO: 0, - rcYawRate: 0 + rcYawRate: 0, + rcExpoPower: 3 }; AUX_CONFIG = []; diff --git a/js/msp/MSPHelper.js b/js/msp/MSPHelper.js index 03979dc0..70d0b01a 100644 --- a/js/msp/MSPHelper.js +++ b/js/msp/MSPHelper.js @@ -140,6 +140,11 @@ MspHelper.prototype.process_data = function(dataHandler) { } else { RC_tuning.RC_YAW_EXPO = 0; } + if (semver.gte(CONFIG.apiVersion, "1.20.0")) { + RC_tuning.rcExpoPower = data.readU8(); + } else { + RC_tuning.rcExpoPower = 3; + } break; case MSPCodes.MSP_PID: // PID data arrived, we need to scale it and save to appropriate bank / array @@ -954,6 +959,9 @@ MspHelper.prototype.crunch = function(code) { buffer.push8(Math.round(RC_tuning.rcYawRate * 100)); } } + if (semver.gte(CONFIG.apiVersion, "1.20.0")) { + buffer.push8(RC_tuning.rcExpoPower); + } break; case MSPCodes.MSP_SET_RX_MAP: for (var i = 0; i < RC_MAP.length; i++) { diff --git a/tabs/pid_tuning.css b/tabs/pid_tuning.css index 5d59921a..69a10867 100644 --- a/tabs/pid_tuning.css +++ b/tabs/pid_tuning.css @@ -242,13 +242,13 @@ padding: 5px; text-align: left; border-right: 1px solid #ccc; - width: 14%; + width: 12.5%; } .tab-pid_tuning .pid_titlebar th:first-child { text-align: left; - width: 14%; + width: 12.5%; } .tab-pid_tuning .pid_titlebar th:last-child { @@ -288,7 +288,7 @@ .tab-pid_tuning table td { padding: 1px; - width: 14%; + width: 12.5%; border-right: 1px solid #ccc; } @@ -370,32 +370,8 @@ border-top-right-radius: 3px; } -.tab-pid_tuning .name { - width: 14%; -} - -.tab-pid_tuning .proportional { - width: 14%; -} - -.tab-pid_tuning .integral { - width: 14%; -} - -.tab-pid_tuning .derivative { - width: 14%; -} - -.tab-pid_tuning .rc_rate { - width: 14%; -} - -.tab-pid_tuning .rate { - width: 14%; -} - -.tab-pid_tuning .rc_expo { - width: 14%; +.tab-pid_tuning .new_rates { + text-align: left; } .tab-pid_tuning .tpa { @@ -711,7 +687,6 @@ width: 40%; .tab-pid_tuning .rc_curve_bg { float: left; - padding-bottom: 20px; background: #ddd; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; @@ -757,4 +732,4 @@ width: 40%; border-bottom-left-radius: 8px; border-top: 0px solid silver; background: #f9f9f9; -} \ No newline at end of file +} diff --git a/tabs/pid_tuning.html b/tabs/pid_tuning.html index f32cec1f..49d35a7e 100755 --- a/tabs/pid_tuning.html +++ b/tabs/pid_tuning.html @@ -72,6 +72,7 @@ + @@ -91,11 +92,12 @@ - +
+
@@ -108,6 +110,7 @@ + @@ -115,8 +118,9 @@ - + + @@ -127,7 +131,16 @@ - + + + + +
+
+
+
+ + @@ -208,7 +221,7 @@
- + @@ -371,26 +384,14 @@ - - - - - - - - - - - - -
-
+
+
diff --git a/tabs/pid_tuning.js b/tabs/pid_tuning.js index addd9cb8..25be672c 100755 --- a/tabs/pid_tuning.js +++ b/tabs/pid_tuning.js @@ -58,28 +58,6 @@ TABS.pid_tuning.initialize = function (callback) { self.setRateProfile(); } - if (semver.gte(CONFIG.flightControllerVersion, "2.8.1")) { - $('input[id="vbatpidcompensation"]').prop('checked', ADVANCED_TUNING.vbatPidCompensation !== 0); - } - - if (semver.gte(CONFIG.flightControllerVersion, "2.8.2")) { - $('#pid-tuning .delta select').val(ADVANCED_TUNING.deltaMethod); - } - - if (semver.gte(CONFIG.flightControllerVersion, '3.0.0')) { - $('select[name="rcInterpolation-select"]').val(RX_CONFIG.rcInterpolation); - - $('input[name="rcInterpolationInterval-number"]').val(RX_CONFIG.rcInterpolationInterval); - - $('input[name="ptermSetpoint-number"]').val(ADVANCED_TUNING.ptermSetpointWeight / 100); - $('input[name="ptermSetpoint-range"]').val(ADVANCED_TUNING.ptermSetpointWeight / 100); - - $('input[name="dtermSetpoint-number"]').val(ADVANCED_TUNING.dtermSetpointWeight / 100); - $('input[name="dtermSetpoint-range"]').val(ADVANCED_TUNING.dtermSetpointWeight / 100); - - self.updateRcInterpolationParameters(); - } - // Fill in the data from PIDs array var i = 0; $('.pid_tuning .ROLL input').each(function () { @@ -239,6 +217,14 @@ TABS.pid_tuning.initialize = function (callback) { $('.pid_tuning input[name="rc_expo"]').attr("rowspan", "3"); } + if (semver.gte(CONFIG.flightControllerVersion, "2.8.1")) { + $('input[id="vbatpidcompensation"]').prop('checked', ADVANCED_TUNING.vbatPidCompensation !== 0); + } + + if (semver.gte(CONFIG.flightControllerVersion, "2.8.2")) { + $('#pid-tuning .delta select').val(ADVANCED_TUNING.deltaMethod); + } + if (semver.gte(CONFIG.flightControllerVersion, '2.9.0')) { $('.pid_tuning input[name="rc_rate_yaw"]').val(RC_tuning.rcYawRate.toFixed(2)); $('.pid_filter input[name="gyroLowpassFrequency"]').val(FILTER_CONFIG.gyro_soft_lpf_hz); @@ -255,34 +241,28 @@ TABS.pid_tuning.initialize = function (callback) { $('.pid_filter input[name="gyroNotchCutoff"]').val(FILTER_CONFIG.gyro_soft_notch_cutoff); $('.pid_filter input[name="dTermNotchFrequency"]').val(FILTER_CONFIG.dterm_notch_hz); $('.pid_filter input[name="dTermNotchCutoff"]').val(FILTER_CONFIG.dterm_notch_cutoff); + + $('select[name="rcInterpolation-select"]').val(RX_CONFIG.rcInterpolation); + + $('input[name="rcInterpolationInterval-number"]').val(RX_CONFIG.rcInterpolationInterval); + + $('input[name="ptermSetpoint-number"]').val(ADVANCED_TUNING.ptermSetpointWeight / 100); + $('input[name="ptermSetpoint-range"]').val(ADVANCED_TUNING.ptermSetpointWeight / 100); + + $('input[name="dtermSetpoint-number"]').val(ADVANCED_TUNING.dtermSetpointWeight / 100); + $('input[name="dtermSetpoint-range"]').val(ADVANCED_TUNING.dtermSetpointWeight / 100); + + self.updateRcInterpolationParameters(); + + $('.pid_tuning input[name="rcExpoPower"]').val(RC_tuning.rcExpoPower.toFixed(0)).prop("readonly", false); } else { $('.pid_filter .newFilter').hide(); + + $('.pid_tuning input[name="rcExpoPower"]').val(3).prop("readonly", true); } } function form_to_pid_and_rc() { - if (semver.gte(CONFIG.flightControllerVersion, "2.8.0")) { - BF_CONFIG.features.updateData($('input[name="SUPEREXPO_RATES"]')); - } - - if (semver.gte(CONFIG.flightControllerVersion, "2.8.1")) { - ADVANCED_TUNING.vbatPidCompensation = $('input[id="vbatpidcompensation"]').is(':checked') ? 1 : 0; - } - - if (semver.gte(CONFIG.flightControllerVersion, "2.8.2")) { - ADVANCED_TUNING.deltaMethod = $('#pid-tuning .delta select').val(); - } - - if (semver.gte(CONFIG.flightControllerVersion, '3.0.0')) { - RX_CONFIG.rcInterpolation = parseInt($('select[name="rcInterpolation-select"]').val()); - - RX_CONFIG.rcInterpolationInterval = parseInt($('input[name="rcInterpolationInterval-number"]').val()); - - ADVANCED_TUNING.ptermSetpointWeight = parseInt($('input[name="ptermSetpoint-number"]').val() * 100); - - ADVANCED_TUNING.dtermSetpointWeight = parseInt($('input[name="dtermSetpoint-number"]').val() * 100); - } - // Fill in the data from PIDs array // Catch all the changes and stuff the inside PIDs array var i = 0; @@ -360,12 +340,33 @@ TABS.pid_tuning.initialize = function (callback) { FILTER_CONFIG.dterm_lpf_hz = parseInt($('.pid_filter input[name="dtermLowpassFrequency"]').val()); FILTER_CONFIG.yaw_lpf_hz = parseInt($('.pid_filter input[name="yawLowpassFrequency"]').val()); + if (semver.gte(CONFIG.flightControllerVersion, "2.8.0") && !semver.gte(CONFIG.flightControllerVersion, "3.0.0")) { + BF_CONFIG.features.updateData($('input[name="SUPEREXPO_RATES"]')); + } + + if (semver.gte(CONFIG.flightControllerVersion, "2.8.1")) { + ADVANCED_TUNING.vbatPidCompensation = $('input[id="vbatpidcompensation"]').is(':checked') ? 1 : 0; + } + + if (semver.gte(CONFIG.flightControllerVersion, "2.8.2")) { + ADVANCED_TUNING.deltaMethod = $('#pid-tuning .delta select').val(); + } + if (semver.gte(CONFIG.flightControllerVersion, '3.0.0')) { + RX_CONFIG.rcInterpolation = parseInt($('select[name="rcInterpolation-select"]').val()); + RX_CONFIG.rcInterpolationInterval = parseInt($('input[name="rcInterpolationInterval-number"]').val()); + + ADVANCED_TUNING.ptermSetpointWeight = parseInt($('input[name="ptermSetpoint-number"]').val() * 100); + ADVANCED_TUNING.dtermSetpointWeight = parseInt($('input[name="dtermSetpoint-number"]').val() * 100); + FILTER_CONFIG.gyro_soft_notch_hz = parseInt($('.pid_filter input[name="gyroNotchFrequency"]').val()); FILTER_CONFIG.gyro_soft_notch_cutoff = parseInt($('.pid_filter input[name="gyroNotchCutoff"]').val()); FILTER_CONFIG.dterm_notch_hz = parseInt($('.pid_filter input[name="dTermNotchFrequency"]').val()); FILTER_CONFIG.dterm_notch_cutoff = parseInt($('.pid_filter input[name="dTermNotchCutoff"]').val()); + + RC_tuning.rcExpoPower = parseInt($('.pid_tuning input[name="rcExpoPower"]').val()); } + } function showAllPids() { @@ -452,7 +453,7 @@ TABS.pid_tuning.initialize = function (callback) { self.rateCurve = new RateCurve(useLegacyCurve); function printMaxAngularVel(rate, rcRate, rcExpo, useSuperExpo, maxAngularVelElement) { - var maxAngularVel = self.rateCurve.getMaxAngularVel(rate, rcRate, rcExpo, useSuperExpo); + var maxAngularVel = self.rateCurve.getMaxAngularVel(rate, rcRate, rcExpo, useSuperExpo).toFixed(0); maxAngularVelElement.text(maxAngularVel); return maxAngularVel; @@ -486,15 +487,19 @@ TABS.pid_tuning.initialize = function (callback) { superexpo: BF_CONFIG.features.isEnabled('SUPEREXPO_RATES') }; - if (CONFIG.flightControllerIdentifier !== "BTFL" || semver.lt(CONFIG.flightControllerVersion, "2.8.1")) { - self.currentRates.rc_rate_yaw = self.currentRates.rc_rate; - } - if (semver.lt(CONFIG.apiVersion, "1.7.0")) { self.currentRates.roll_rate = RC_tuning.roll_pitch_rate; self.currentRates.pitch_rate = RC_tuning.roll_pitch_rate; } + if (semver.lt(CONFIG.flightControllerVersion, "2.8.1")) { + self.currentRates.rc_rate_yaw = self.currentRates.rc_rate; + } + + if (semver.gte(CONFIG.flightControllerVersion, "3.0.0")) { + self.currentRates.superexpo = true; + } + $('.tab-pid_tuning .tab_container .pid').on('click', function () { $('.tab-pid_tuning .subtab-pid').show(); $('.tab-pid_tuning .subtab-filter').hide(); @@ -673,9 +678,9 @@ TABS.pid_tuning.initialize = function (callback) { rcCurveElement.width = 1000; rcCurveElement.height = 1000; - var maxAngularVelRollElement = $('.rc_curve .maxAngularVelRoll'); - var maxAngularVelPitchElement = $('.rc_curve .maxAngularVelPitch'); - var maxAngularVelYawElement = $('.rc_curve .maxAngularVelYaw'); + var maxAngularVelRollElement = $('.pid_tuning .maxAngularVelRoll'); + var maxAngularVelPitchElement = $('.pid_tuning .maxAngularVelPitch'); + var maxAngularVelYawElement = $('.pid_tuning .maxAngularVelYaw'); var updateNeeded = true; @@ -684,13 +689,13 @@ TABS.pid_tuning.initialize = function (callback) { var targetElement = $(event.target), targetValue = checkInput(targetElement); - if (self.currentRates.hasOwnProperty(targetElement.attr('name')) && targetValue) { + if (self.currentRates.hasOwnProperty(targetElement.attr('name')) && targetValue !== undefined) { self.currentRates[targetElement.attr('name')] = targetValue; updateNeeded = true; } - if (targetElement.attr('name') === 'rc_rate' && CONFIG.flightControllerIdentifier !== "BTFL" || semver.lt(CONFIG.flightControllerVersion, "2.8.1")) { + if (targetElement.attr('name') === 'rc_rate' && semver.lt(CONFIG.flightControllerVersion, "2.8.1")) { self.currentRates.rc_rate_yaw = targetValue; } @@ -711,7 +716,7 @@ TABS.pid_tuning.initialize = function (callback) { var curveHeight = rcCurveElement.height; var curveWidth = rcCurveElement.width; - var maxAngularVel = Math.max( + var maxAngularVel = Math.max( printMaxAngularVel(self.currentRates.roll_rate, self.currentRates.rc_rate, self.currentRates.rc_expo, self.currentRates.superexpo, maxAngularVelRollElement), printMaxAngularVel(self.currentRates.pitch_rate, self.currentRates.rc_rate, self.currentRates.rc_expo, self.currentRates.superexpo, maxAngularVelPitchElement), printMaxAngularVel(self.currentRates.yaw_rate, self.currentRates.rc_rate_yaw, self.currentRates.rc_yaw_expo, self.currentRates.superexpo, maxAngularVelYawElement)); @@ -724,11 +729,9 @@ TABS.pid_tuning.initialize = function (callback) { curveContext.lineWidth = 4; - drawCurve(self.currentRates.roll_rate, self.currentRates.rc_rate, self.currentRates.rc_expo, self.currentRates.superexpo, maxAngularVel, '#ff0000', 0, curveContext); - - drawCurve(self.currentRates.pitch_rate, self.currentRates.rc_rate, self.currentRates.rc_expo, self.currentRates.superexpo, maxAngularVel, '#00ff00', -4, curveContext); - - drawCurve(self.currentRates.yaw_rate, self.currentRates.rc_rate_yaw, self.currentRates.rc_yaw_expo, self.currentRates.superexpo, maxAngularVel, '#0000ff', 4, curveContext); + drawCurve(self.currentRates.roll_rate, self.currentRates.rc_rate, self.currentRates.rc_expo, self.currentRates.superexpo, maxAngularVel, '#ff0000', 0, curveContext); + drawCurve(self.currentRates.pitch_rate, self.currentRates.rc_rate, self.currentRates.rc_expo, self.currentRates.superexpo, maxAngularVel, '#00ff00', -4, curveContext); + drawCurve(self.currentRates.yaw_rate, self.currentRates.rc_rate_yaw, self.currentRates.rc_yaw_expo, self.currentRates.superexpo, maxAngularVel, '#0000ff', 4, curveContext); updateNeeded = false; } @@ -737,8 +740,8 @@ TABS.pid_tuning.initialize = function (callback) { // UI Hooks // curves - $('.pid_tuning').on('input change', updateRates); - $('input.feature').on('input change', updateRates).trigger('input'); + $('input.feature').on('input change', updateRates); + $('.pid_tuning').on('input change', updateRates).trigger('input'); $('.throttle input').on('input change', function () { setTimeout(function () { // let global validation trigger and adjust the values first @@ -900,9 +903,9 @@ TABS.pid_tuning.renderModel = function () { if (RC.channels[0] && RC.channels[1] && RC.channels[2]) { var delta = this.clock.getDelta(); - var roll = delta * this.rateCurve.rcCommandRawToDegreesPerSecond(RC.channels[0], this.currentRates.roll_rate, this.currentRates.rc_rate, this.currentRates.rc_expo, this.currentRates.super_expo), - pitch = delta * this.rateCurve.rcCommandRawToDegreesPerSecond(RC.channels[1], this.currentRates.pitch_rate, this.currentRates.rc_rate, this.currentRates.rc_expo, this.currentRates.super_expo), - yaw = delta * this.rateCurve.rcCommandRawToDegreesPerSecond(RC.channels[2], this.currentRates.yaw_rate, this.currentRates.rc_rate_yaw, this.currentRates.rc_yaw_expo, this.currentRates.super_expo); + var roll = delta * this.rateCurve.rcCommandRawToDegreesPerSecond(RC.channels[0], this.currentRates.roll_rate, this.currentRates.rc_rate, this.currentRates.rc_expo, this.currentRates.superexpo), + pitch = delta * this.rateCurve.rcCommandRawToDegreesPerSecond(RC.channels[1], this.currentRates.pitch_rate, this.currentRates.rc_rate, this.currentRates.rc_expo, this.currentRates.superexpo), + yaw = delta * this.rateCurve.rcCommandRawToDegreesPerSecond(RC.channels[2], this.currentRates.yaw_rate, this.currentRates.rc_rate_yaw, this.currentRates.rc_yaw_expo, this.currentRates.superexpo); this.model.rotateBy(-degToRad(pitch), -degToRad(yaw), -degToRad(roll)); }