From 70a8364e5cc828efec329e4725952d99ab3c9b4c Mon Sep 17 00:00:00 2001 From: fgiudice98 Date: Sat, 7 Mar 2020 12:50:54 +0100 Subject: [PATCH] Add rates type Add rates type selection with working graphs and max angular speed Fix deadband MSP changes and fix actual rates limit Small style changes and fixes Fixes Fixed the code pointed out in the review Various sonar fixes Updated the values of actual rates setting Reduced logo size Added analytics to rates type Minor fix + rounding by step value Now the calculation of the angle rate takes into account the values rounded by the step value (especially visible with values that are in deg/s) Various fixes Angle rate calculation in different functions Fix for value step validation Sonar fixes (mostly variables) Force refresh to prevent errors ... ... when changing rates type after saving to eeprom Logos refinement + minor changes Touch to trigger travis Fix Raceflight rate --- locales/en/messages.json | 36 +++ src/css/tabs/pid_tuning.css | 23 ++ src/images/rate_logos/actual.svg | 124 +++++++++ src/images/rate_logos/betaflight.svg | 141 ++++++++++ src/images/rate_logos/kiss.svg | 85 ++++++ src/images/rate_logos/quickrates.svg | 87 +++++++ src/images/rate_logos/raceflight.svg | 71 +++++ src/js/RateCurve.js | 98 ++++++- src/js/msp/MSPHelper.js | 6 + src/js/tabs/pid_tuning.js | 377 ++++++++++++++++++++++++++- src/js/tabs/receiver.js | 4 +- src/tabs/pid_tuning.html | 83 ++++-- 12 files changed, 1089 insertions(+), 46 deletions(-) create mode 100644 src/images/rate_logos/actual.svg create mode 100644 src/images/rate_logos/betaflight.svg create mode 100644 src/images/rate_logos/kiss.svg create mode 100644 src/images/rate_logos/quickrates.svg create mode 100644 src/images/rate_logos/raceflight.svg diff --git a/locales/en/messages.json b/locales/en/messages.json index 8f10ebbb..ddb8a937 100644 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -5598,5 +5598,41 @@ }, "darkTheme": { "message": "Enable dark theme" + }, + "pidTuningRatesType": { + "message": "Rates Type" + }, + "pidTuningRatesTypeTip": { + "message": "Changing rates type will change the rates curve and the way you can set it" + }, + "pidTuningRcRateRaceflight": { + "message": "Rate" + }, + "pidTuningRcExpoRaceflight": { + "message": "Expo" + }, + "pidTuningRateRaceflight": { + "message": "Acro+" + }, + "pidTuningRcExpoKISS": { + "message": "RC Curve" + }, + "pidTuningRateQuickRates": { + "message": "Max Rate" + }, + "pidTuningRcRateActual": { + "message": "Center Sensitivity" + }, + "dialogRatesTypeTitle": { + "message": "Rates type change" + }, + "dialogRatesTypeNote": { + "message": "WARNING: You are changing the rates type. Your rates will be set to a default curve.

Nothing is saved yet and you can still return to your previous values by setting the previous rates type.

Click the Save button to apply the changes." + }, + "dialogRatesTypeConfirm": { + "message": "Change" + }, + "dialogRatesTypeCancel": { + "message": "Return to saved values" } } diff --git a/src/css/tabs/pid_tuning.css b/src/css/tabs/pid_tuning.css index 85262cbc..c2a51594 100644 --- a/src/css/tabs/pid_tuning.css +++ b/src/css/tabs/pid_tuning.css @@ -908,3 +908,26 @@ .tab-pid_tuning .pid_titlebar .name-helpicon-flex .helpicon { margin-right: 0; } + +.tab-pid_tuning .cf .rates_logo_bg { + background-color: #ebeced; +} + +.tab-pid_tuning .rates_logo_div { + margin-top: -10%; + text-align: center; +} + +.tab-pid_tuning .rates_logo { + width: 80%; + height: 80%; +} + +.tab-pid_tuning .rates-tab-warning { + display: flex; + flex-flow: row wrap; +} + +.tab-pid_tuning .float-left { + float: left; +} diff --git a/src/images/rate_logos/actual.svg b/src/images/rate_logos/actual.svg new file mode 100644 index 00000000..ccd10479 --- /dev/null +++ b/src/images/rate_logos/actual.svg @@ -0,0 +1,124 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/images/rate_logos/betaflight.svg b/src/images/rate_logos/betaflight.svg new file mode 100644 index 00000000..fc9c7a7d --- /dev/null +++ b/src/images/rate_logos/betaflight.svg @@ -0,0 +1,141 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/images/rate_logos/kiss.svg b/src/images/rate_logos/kiss.svg new file mode 100644 index 00000000..6388a34d --- /dev/null +++ b/src/images/rate_logos/kiss.svg @@ -0,0 +1,85 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/images/rate_logos/quickrates.svg b/src/images/rate_logos/quickrates.svg new file mode 100644 index 00000000..7318771c --- /dev/null +++ b/src/images/rate_logos/quickrates.svg @@ -0,0 +1,87 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/images/rate_logos/raceflight.svg b/src/images/rate_logos/raceflight.svg new file mode 100644 index 00000000..1b91b644 --- /dev/null +++ b/src/images/rate_logos/raceflight.svg @@ -0,0 +1,71 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/js/RateCurve.js b/src/js/RateCurve.js index f9d71ff0..c1fda2fa 100644 --- a/src/js/RateCurve.js +++ b/src/js/RateCurve.js @@ -56,7 +56,7 @@ var RateCurve = function (useLegacyCurve) { context.moveTo(0, height); context.quadraticCurveTo(width * 11 / 20, height - ((rateY / 2) * (1 - rcExpo)), width, height - rateY); context.stroke(); - } + }; this.drawStickPosition = function (rcData, rate, rcRate, rcExpo, superExpoActive, deadband, limit, maxAngularVel, context, stickColor) { @@ -76,20 +76,15 @@ var RateCurve = function (useLegacyCurve) { context.restore(); } return (Math.abs(currentValue)<0.5)?0:currentValue.toFixed(0); // The calculated value in deg/s is returned from the function call for further processing. - } + }; -}; + this.getBetaflightRates = function (rcCommandf, rcCommandfAbs, rate, rcRate, rcExpo, superExpoActive, limit) { + let angularVel; -RateCurve.prototype.rcCommandRawToDegreesPerSecond = function (rcData, rate, rcRate, rcExpo, superExpoActive, deadband, limit) { - var angleRate; - if (rate !== undefined && rcRate !== undefined && rcExpo !== undefined) { if (rcRate > 2) { rcRate = rcRate + (rcRate - 2) * 14.54; } - var maxRc = 500 * rcRate; - var rcCommandf = this.rcCommand(rcData, rcRate, deadband) / maxRc; - var rcCommandfAbs = Math.abs(rcCommandf); var expoPower; var rcRateConstant; @@ -107,13 +102,90 @@ RateCurve.prototype.rcCommandRawToDegreesPerSecond = function (rcData, rate, rcR if (superExpoActive) { var rcFactor = 1 / this.constrain(1 - rcCommandfAbs * rate, 0.01, 1); - angleRate = rcRateConstant * rcRate * rcCommandf; // 200 should be variable checked on version (older versions it's 205,9) - angleRate = angleRate * rcFactor; + angularVel = rcRateConstant * rcRate * rcCommandf; // 200 should be variable checked on version (older versions it's 205,9) + angularVel = angularVel * rcFactor; } else { - angleRate = (((rate * 100) + 27) * rcCommandf / 16) / 4.1; // Only applies to old versions ? + angularVel = (((rate * 100) + 27) * rcCommandf / 16) / 4.1; // Only applies to old versions ? } - angleRate = this.constrain(angleRate, -1 * limit, limit); // Rate limit from profile + angularVel = this.constrain(angularVel, -1 * limit, limit); // Rate limit from profile + + return angularVel; + }; + + this.getRaceflightRates = function (rcCommandf, rate, rcRate, rcExpo) { + let angularVel = ((1 + 0.01 * rcExpo * (rcCommandf * rcCommandf - 1.0)) * rcCommandf); + angularVel = (angularVel * (rcRate + (Math.abs(angularVel) * rcRate * rate * 0.01))); + return angularVel; + }; + + this.getKISSRates = function (rcCommandf, rcCommandfAbs, rate, rcRate, rcExpo) { + const kissRpy = 1 - rcCommandfAbs * rate; + const kissTempCurve = rcCommandf * rcCommandf; + rcCommandf = ((rcCommandf * kissTempCurve) * rcExpo + rcCommandf * (1 - rcExpo)) * (rcRate / 10); + return ((2000.0 * (1.0 / kissRpy)) * rcCommandf); + }; + + this.getActualRates = function (rcCommandf, rcCommandfAbs, rate, rcRate, rcExpo) { + let angularVel; + const expof = rcCommandfAbs * ((Math.pow(rcCommandf, 5) * rcExpo) + (rcCommandf * (1 - rcExpo))); + + angularVel = Math.max(0, rate-rcRate); + angularVel = (rcCommandf * rcRate) + (angularVel * expof); + + return angularVel; + }; + + this.getQuickRates = function (rcCommandf, rcCommandfAbs, rate, rcRate, rcExpo) { + rcRate = rcRate * 200; + rate = Math.max(rate, rcRate); + + let angularVel; + const superExpoConfig = (((rate / rcRate) - 1) / (rate / rcRate)); + const curve = Math.pow(rcCommandfAbs, 3) * rcExpo + rcCommandfAbs * (1 - rcExpo); + + angularVel = 1.0 / (1.0 - (curve * superExpoConfig)); + angularVel = rcCommandf * rcRate * angularVel; + + return angularVel; + }; + +}; + +RateCurve.prototype.rcCommandRawToDegreesPerSecond = function (rcData, rate, rcRate, rcExpo, superExpoActive, deadband, limit) { + var angleRate; + + if (rate !== undefined && rcRate !== undefined && rcExpo !== undefined) { + const rcCommandf = this.rcCommand(rcData, 1, deadband) / 500; + var rcCommandfAbs = Math.abs(rcCommandf); + + switch(TABS.pid_tuning.currentRatesType) { + case TABS.pid_tuning.RATES_TYPE.RACEFLIGHT: + angleRate=this.getRaceflightRates(rcCommandf, rate, rcRate, rcExpo); + + break; + + case TABS.pid_tuning.RATES_TYPE.KISS: + angleRate=this.getKISSRates(rcCommandf, rcCommandfAbs, rate, rcRate, rcExpo); + + break; + + case TABS.pid_tuning.RATES_TYPE.ACTUAL: + angleRate=this.getActualRates(rcCommandf, rcCommandfAbs, rate, rcRate, rcExpo); + + break; + + case TABS.pid_tuning.RATES_TYPE.QUICKRATES: + angleRate=this.getQuickRates(rcCommandf, rcCommandfAbs, rate, rcRate, rcExpo); + + break; + + // add future rates types here + default: // BetaFlight + angleRate=this.getBetaflightRates(rcCommandf, rcCommandfAbs, rate, rcRate, rcExpo, superExpoActive, limit); + + break; + } } return angleRate; diff --git a/src/js/msp/MSPHelper.js b/src/js/msp/MSPHelper.js index 28c29ec9..9e3dd60d 100644 --- a/src/js/msp/MSPHelper.js +++ b/src/js/msp/MSPHelper.js @@ -357,6 +357,9 @@ MspHelper.prototype.process_data = function(dataHandler) { RC_tuning.pitch_rate_limit = data.readU16(); RC_tuning.yaw_rate_limit = data.readU16(); } + if (semver.gte(CONFIG.apiVersion, "1.43.0")) { + RC_tuning.rates_type = data.readU8(); + } break; case MSPCodes.MSP_PID: // PID data arrived, we need to scale it and save to appropriate bank / array @@ -1689,6 +1692,9 @@ MspHelper.prototype.crunch = function(code) { buffer.push16(RC_tuning.pitch_rate_limit); buffer.push16(RC_tuning.yaw_rate_limit); } + if (semver.gte(CONFIG.apiVersion, "1.43.0")) { + buffer.push8(RC_tuning.rates_type); + } break; case MSPCodes.MSP_SET_RX_MAP: for (let i = 0; i < RC_MAP.length; i++) { diff --git a/src/js/tabs/pid_tuning.js b/src/js/tabs/pid_tuning.js index 24f28f89..ddd28ea8 100644 --- a/src/js/tabs/pid_tuning.js +++ b/src/js/tabs/pid_tuning.js @@ -7,6 +7,14 @@ TABS.pid_tuning = { dirty: false, currentProfile: null, currentRateProfile: null, + currentRatesType: null, + RATES_TYPE: { + BETAFLIGHT: 0, + RACEFLIGHT: 1, + KISS: 2, + ACTUAL: 3, + QUICKRATES: 4, + }, SETPOINT_WEIGHT_RANGE_LOW: 2.55, SETPOINT_WEIGHT_RANGE_HIGH: 20, SETPOINT_WEIGHT_RANGE_LEGACY: 2.54, @@ -399,6 +407,29 @@ TABS.pid_tuning.initialize = function (callback) { $('.idleMinRpm').hide(); } + if (semver.gte(CONFIG.apiVersion, "1.43.0")) { + const ratesTypeListElement = $('select[id="ratesType"]'); // generates list + const ratesList = [ + {name: "Betaflight"}, + {name: "Raceflight"}, + {name: "KISS"}, + {name: "Actual"}, + {name: "QuickRates"}, + ]; + // add future rates types here with CONFIG.apiVersion check + for (let i = 0; i < ratesList.length; i++) { + ratesTypeListElement.append(``); + } + + self.currentRatesType = RC_tuning.rates_type; + ratesTypeListElement.val(self.currentRatesType); + + self.changeRatesType(self.currentRatesType); // update rate type code when updating the tab + + } else { + $('.rates_type').hide(); + } + $('input[id="useIntegratedYaw"]').change(function() { var checked = $(this).is(':checked'); $('#pidTuningIntegratedYawCaution').toggle(checked); @@ -649,16 +680,65 @@ TABS.pid_tuning.initialize = function (callback) { }); // catch RC_tuning changes - RC_tuning.RC_RATE = parseFloat($('.pid_tuning input[name="rc_rate"]').val()); + const pitch_rate_e = $('.pid_tuning input[name="pitch_rate"]'); + const roll_rate_e = $('.pid_tuning input[name="roll_rate"]'); + const yaw_rate_e = $('.pid_tuning input[name="yaw_rate"]'); + const rc_rate_pitch_e = $('.pid_tuning input[name="rc_rate_pitch"]'); + const rc_rate_e = $('.pid_tuning input[name="rc_rate"]'); + const rc_rate_yaw_e = $('.pid_tuning input[name="rc_rate_yaw"]'); + const rc_pitch_expo_e = $('.pid_tuning input[name="rc_pitch_expo"]'); + const rc_expo_e = $('.pid_tuning input[name="rc_expo"]'); + const rc_yaw_expo_e = $('.pid_tuning input[name="rc_yaw_expo"]'); + RC_tuning.roll_pitch_rate = parseFloat($('.pid_tuning input[name="roll_pitch_rate"]').val()); - RC_tuning.roll_rate = parseFloat($('.pid_tuning input[name="roll_rate"]').val()); - RC_tuning.pitch_rate = parseFloat($('.pid_tuning input[name="pitch_rate"]').val()); - RC_tuning.yaw_rate = parseFloat($('.pid_tuning input[name="yaw_rate"]').val()); - RC_tuning.RC_EXPO = parseFloat($('.pid_tuning input[name="rc_expo"]').val()); - RC_tuning.RC_YAW_EXPO = parseFloat($('.pid_tuning input[name="rc_yaw_expo"]').val()); - RC_tuning.rcYawRate = parseFloat($('.pid_tuning input[name="rc_rate_yaw"]').val()); - RC_tuning.rcPitchRate = parseFloat($('.pid_tuning input[name="rc_rate_pitch"]').val()); - RC_tuning.RC_PITCH_EXPO = parseFloat($('.pid_tuning input[name="rc_pitch_expo"]').val()); + RC_tuning.RC_RATE = parseFloat(rc_rate_e.val()); + RC_tuning.roll_rate = parseFloat(roll_rate_e.val()); + RC_tuning.pitch_rate = parseFloat(pitch_rate_e.val()); + RC_tuning.yaw_rate = parseFloat(yaw_rate_e.val()); + RC_tuning.RC_EXPO = parseFloat(rc_expo_e.val()); + RC_tuning.RC_YAW_EXPO = parseFloat(rc_yaw_expo_e.val()); + RC_tuning.rcYawRate = parseFloat(rc_rate_yaw_e.val()); + RC_tuning.rcPitchRate = parseFloat(rc_rate_pitch_e.val()); + RC_tuning.RC_PITCH_EXPO = parseFloat(rc_pitch_expo_e.val()); + + if (semver.gte(CONFIG.apiVersion, "1.43.0")) { + switch(self.currentRatesType) { + case self.RATES_TYPE.RACEFLIGHT: + RC_tuning.pitch_rate = parseFloat(pitch_rate_e.val()) / 100; + RC_tuning.roll_rate = parseFloat(roll_rate_e.val()) / 100; + RC_tuning.yaw_rate = parseFloat(yaw_rate_e.val()) / 100; + RC_tuning.rcPitchRate = parseFloat(rc_rate_pitch_e.val()) / 1000; + RC_tuning.RC_RATE = parseFloat(rc_rate_e.val()) / 1000; + RC_tuning.rcYawRate = parseFloat(rc_rate_yaw_e.val()) / 1000; + RC_tuning.RC_PITCH_EXPO = parseFloat(rc_pitch_expo_e.val()) / 100; + RC_tuning.RC_EXPO = parseFloat(rc_expo_e.val()) / 100; + RC_tuning.RC_YAW_EXPO = parseFloat(rc_yaw_expo_e.val()) / 100; + + break; + + case self.RATES_TYPE.ACTUAL: + RC_tuning.pitch_rate = parseFloat(pitch_rate_e.val()) / 1000; + RC_tuning.roll_rate = parseFloat(roll_rate_e.val()) / 1000; + RC_tuning.yaw_rate = parseFloat(yaw_rate_e.val()) / 1000; + RC_tuning.rcPitchRate = parseFloat(rc_rate_pitch_e.val()) / 1000; + RC_tuning.RC_RATE = parseFloat(rc_rate_e.val()) / 1000; + RC_tuning.rcYawRate = parseFloat(rc_rate_yaw_e.val()) / 1000; + + break; + + case self.RATES_TYPE.QUICKRATES: + RC_tuning.pitch_rate = parseFloat(pitch_rate_e.val()) / 1000; + RC_tuning.roll_rate = parseFloat(roll_rate_e.val()) / 1000; + RC_tuning.yaw_rate = parseFloat(yaw_rate_e.val()) / 1000; + + break; + + // add future rates types here + default: // BetaFlight + + break; + } + } RC_tuning.throttle_MID = parseFloat($('.throttle input[name="mid"]').val()); RC_tuning.throttle_EXPO = parseFloat($('.throttle input[name="expo"]').val()); @@ -779,6 +859,15 @@ TABS.pid_tuning.initialize = function (callback) { ADVANCED_TUNING.motorOutputLimit = parseInt($('.pid_tuning input[name="motorLimit"]').val()); ADVANCED_TUNING.autoProfileCellCount = parseInt($('.pid_tuning input[name="cellCount"]').val()); ADVANCED_TUNING.idleMinRpm = parseInt($('input[name="idleMinRpm-number"]').val()); + + const selectedRatesType = $('select[id="ratesType"]').val(); // send analytics for rates type + let selectedRatesTypeName = null; + if (selectedRatesType !== RC_tuning.rates_type) { + selectedRatesTypeName = $('select[id="ratesType"]').find('option:selected').text(); + } + self.analyticsChanges['RatesType'] = selectedRatesTypeName; + + RC_tuning.rates_type = selectedRatesType; } } @@ -941,6 +1030,45 @@ TABS.pid_tuning.initialize = function (callback) { self.currentRates.rc_expo_pitch = self.currentRates.rc_expo; } + if (semver.gte(CONFIG.apiVersion, "1.43.0")) { + switch(RC_tuning.rates_type) { + case self.RATES_TYPE.RACEFLIGHT: + self.currentRates.roll_rate *= 100; + self.currentRates.pitch_rate *= 100; + self.currentRates.yaw_rate *= 100; + self.currentRates.rc_rate *= 1000; + self.currentRates.rc_rate_yaw *= 1000; + self.currentRates.rc_rate_pitch *= 1000; + self.currentRates.rc_expo *= 100; + self.currentRates.rc_yaw_expo *= 100; + self.currentRates.rc_pitch_expo *= 100; + + break; + + case self.RATES_TYPE.ACTUAL: + self.currentRates.roll_rate *= 1000; + self.currentRates.pitch_rate *= 1000; + self.currentRates.yaw_rate *= 1000; + self.currentRates.rc_rate *= 1000; + self.currentRates.rc_rate_yaw *= 1000; + self.currentRates.rc_rate_pitch *= 1000; + + break; + + case self.RATES_TYPE.QUICKRATES: + self.currentRates.roll_rate *= 1000; + self.currentRates.pitch_rate *= 1000; + self.currentRates.yaw_rate *= 1000; + + break; + + // add future rates types here + default: // BetaFlight + + break; + } + } + $('.tab-pid_tuning .tab-container .pid').on('click', () => activateSubtab('pid')); $('.tab-pid_tuning .tab-container .rates').on('click', () => activateSubtab('rates')); @@ -1265,6 +1393,11 @@ TABS.pid_tuning.initialize = function (callback) { targetValue = checkInput(targetElement); if (self.currentRates.hasOwnProperty(targetElement.attr('name')) && targetValue !== undefined) { + const stepValue = parseFloat(targetElement.prop('step')); // adjust value to match step (change only the result, not the the actual value) + if (stepValue != null) { + targetValue = Math.round(targetValue / stepValue) * stepValue; + } + self.currentRates[targetElement.attr('name')] = targetValue; updateNeeded = true; @@ -1294,6 +1427,12 @@ TABS.pid_tuning.initialize = function (callback) { if (targetElement.attr('name') === 'rc_expo' && semver.lt(CONFIG.apiVersion, "1.37.0")) { self.currentRates.rc_pitch_expo = targetValue; } + + if (targetElement.attr('id') === 'ratesType' && semver.gte(CONFIG.apiVersion, "1.43.0")) { + self.changeRatesType(targetValue); + + updateNeeded = true; + } } else { // no event was passed, just force a graph update updateNeeded = true; } @@ -1752,6 +1891,8 @@ TABS.pid_tuning.initialize = function (callback) { self.setDirty(false); GUI.log(i18n.getMessage('pidTuningEepromSaved')); + + self.refresh(); }); analytics.sendChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges); @@ -1765,7 +1906,7 @@ TABS.pid_tuning.initialize = function (callback) { self.updating = false; // enable RC data pulling for rates preview - GUI.interval_add('receiver_pull', self.getRecieverData, true); + GUI.interval_add('receiver_pull', self.getReceiverData, true); // status data pulled via separate timer with static speed GUI.interval_add('status_pull', function status_pull() { @@ -1776,7 +1917,7 @@ TABS.pid_tuning.initialize = function (callback) { } }; -TABS.pid_tuning.getRecieverData = function () { +TABS.pid_tuning.getReceiverData = function () { MSP.send_message(MSPCodes.MSP_RC, false, false); }; @@ -2192,3 +2333,217 @@ TABS.pid_tuning.updatePIDColors = function(clear = false) { setTuningElementColor($('.pid_tuning .PITCH input[name="f"]'), ADVANCED_TUNING_ACTIVE.feedforwardPitch, ADVANCED_TUNING.feedforwardPitch); setTuningElementColor($('.pid_tuning .YAW input[name="f"]'), ADVANCED_TUNING_ACTIVE.feedforwardYaw, ADVANCED_TUNING.feedforwardYaw); }; + +TABS.pid_tuning.changeRatesType = function(rateTypeID) { + let self = this; + const dialogRatesType = $('.dialogRatesType')[0]; + let sameRatesType = true; + + self.currentRatesType = rateTypeID; + + if (self.currentRatesType !== RC_tuning.rates_type) { + sameRatesType = false; + dialogRatesType.showModal(); + + $('.dialogRatesType-cancelbtn').click(function() { + sameRatesType = true; + self.currentRatesType = RC_tuning.rates_type; + $('.rates_type select[id="ratesType"]').val(RC_tuning.rates_type); + self.changeRatesTypeLogo(); + self.changeRatesSystem(sameRatesType); + dialogRatesType.close(); + }); + + $('.dialogRatesType-confirmbtn').click(function() { + self.changeRatesTypeLogo(); + self.changeRatesSystem(sameRatesType); + dialogRatesType.close(); + }); + } else { + self.changeRatesTypeLogo(); + self.changeRatesSystem(sameRatesType); + } +}; + +TABS.pid_tuning.changeRatesSystem = function(sameType) { + let self = this; + + let rcRateMax = 2.55, rcRateMin = 0.01, rcRateStep = 0.01; + let rateMax = 1.0, rateMin = 0, rateStep = 0.01; + let expoMax = 1.0, expoMin = 0, expoStep = 0.01; + + const pitch_rate_e = $('.pid_tuning input[name="pitch_rate"]'); + const roll_rate_e = $('.pid_tuning input[name="roll_rate"]'); + const yaw_rate_e = $('.pid_tuning input[name="yaw_rate"]'); + const rc_rate_pitch_e = $('.pid_tuning input[name="rc_rate_pitch"]'); + const rc_rate_e = $('.pid_tuning input[name="rc_rate"]'); + const rc_rate_yaw_e = $('.pid_tuning input[name="rc_rate_yaw"]'); + const rc_pitch_expo_e = $('.pid_tuning input[name="rc_pitch_expo"]'); + const rc_expo_e = $('.pid_tuning input[name="rc_expo"]'); + const rc_yaw_expo_e = $('.pid_tuning input[name="rc_yaw_expo"]'); + + const rcRateLabel = $('#pid-tuning .pid_titlebar .rc_rate'); + const rateLabel = $('#pid-tuning .pid_titlebar .rate'); + const rcExpoLabel = $('#pid-tuning .pid_titlebar .rc_expo'); + + // default values for betaflight curve. all the default values produce the same betaflight default curve (or at least near enough) + let rcRateDefault = (1).toFixed(2), rateDefault = (0.7).toFixed(2), expoDefault = (0).toFixed(2); + + if (sameType) { // if selected rates type is different from the saved one, set values to default instead of reading + pitch_rate_e.val(RC_tuning.pitch_rate.toFixed(2)); + roll_rate_e.val(RC_tuning.roll_rate.toFixed(2)); + yaw_rate_e.val(RC_tuning.yaw_rate.toFixed(2)); + rc_rate_pitch_e.val(RC_tuning.rcPitchRate.toFixed(2)); + rc_rate_e.val(RC_tuning.RC_RATE.toFixed(2)); + rc_rate_yaw_e.val(RC_tuning.rcYawRate.toFixed(2)); + rc_pitch_expo_e.val(RC_tuning.RC_PITCH_EXPO.toFixed(2)); + rc_expo_e.val(RC_tuning.RC_EXPO.toFixed(2)); + rc_yaw_expo_e.val(RC_tuning.RC_YAW_EXPO.toFixed(2)); + } + + switch(self.currentRatesType) { + case self.RATES_TYPE.RACEFLIGHT: + rcRateLabel.text(i18n.getMessage("pidTuningRcRateRaceflight")); + rateLabel.text(i18n.getMessage("pidTuningRateRaceflight")); + rcExpoLabel.text(i18n.getMessage("pidTuningRcExpoRaceflight")); + + rcRateMax = 2000; + rcRateMin = 10; + rcRateStep = 10; + rateMax = 255; + rateStep = 1; + expoMax = 100; + expoStep = 1; + + if (sameType) { + pitch_rate_e.val((RC_tuning.pitch_rate * 100).toFixed(0)); + roll_rate_e.val((RC_tuning.roll_rate * 100).toFixed(0)); + yaw_rate_e.val((RC_tuning.yaw_rate * 100).toFixed(0)); + rc_rate_pitch_e.val((RC_tuning.rcPitchRate * 1000).toFixed(0)); + rc_rate_e.val((RC_tuning.RC_RATE * 1000).toFixed(0)); + rc_rate_yaw_e.val((RC_tuning.rcYawRate * 1000).toFixed(0)); + rc_pitch_expo_e.val((RC_tuning.RC_PITCH_EXPO * 100).toFixed(0)); + rc_expo_e.val((RC_tuning.RC_EXPO * 100).toFixed(0)); + rc_yaw_expo_e.val((RC_tuning.RC_YAW_EXPO * 100).toFixed(0)); + } else { + rcRateDefault = (370).toFixed(0); + rateDefault = (80).toFixed(0); + expoDefault = (50).toFixed(0); + } + + break; + + case self.RATES_TYPE.KISS: + rcRateLabel.text(i18n.getMessage("pidTuningRcRate")); + rateLabel.text(i18n.getMessage("pidTuningRcRateRaceflight")); + rcExpoLabel.text(i18n.getMessage("pidTuningRcExpoKISS")); + + rateMax = 0.99; + + break; + + case self.RATES_TYPE.ACTUAL: + rcRateLabel.text(i18n.getMessage("pidTuningRcRateActual")); + rateLabel.text(i18n.getMessage("pidTuningRateQuickRates")); + rcExpoLabel.text(i18n.getMessage("pidTuningRcExpoRaceflight")); + + rateMax = 2000; + rateStep = 10; + rcRateMax = 2000; + rcRateMin = 10; + rcRateStep = 10; + + if (sameType) { + pitch_rate_e.val((RC_tuning.pitch_rate * 1000).toFixed(0)); + roll_rate_e.val((RC_tuning.roll_rate * 1000).toFixed(0)); + yaw_rate_e.val((RC_tuning.yaw_rate * 1000).toFixed(0)); + rc_rate_pitch_e.val((RC_tuning.rcPitchRate * 1000).toFixed(0)); + rc_rate_e.val((RC_tuning.RC_RATE * 1000).toFixed(0)); + rc_rate_yaw_e.val((RC_tuning.rcYawRate * 1000).toFixed(0)); + } else { + rcRateDefault = (200).toFixed(0); + rateDefault = (670).toFixed(0); + expoDefault = (0.54).toFixed(2); + } + + break; + + case self.RATES_TYPE.QUICKRATES: + rcRateLabel.text(i18n.getMessage("pidTuningRcRate")); + rateLabel.text(i18n.getMessage("pidTuningRateQuickRates")); + rcExpoLabel.text(i18n.getMessage("pidTuningRcExpoRaceflight")); + + rateMax = 2000; + rateStep = 10; + + if (sameType) { + pitch_rate_e.val((RC_tuning.pitch_rate * 1000).toFixed(0)); + roll_rate_e.val((RC_tuning.roll_rate * 1000).toFixed(0)); + yaw_rate_e.val((RC_tuning.yaw_rate * 1000).toFixed(0)); + } else { + rateDefault = (670).toFixed(0); + } + + break; + + // add future rates types here + default: // BetaFlight + rcRateLabel.text(i18n.getMessage("pidTuningRcRate")); + rateLabel.text(i18n.getMessage("pidTuningRate")); + rcExpoLabel.text(i18n.getMessage("pidTuningRcExpo")); + + break; + } + + const rc_rate_input_c = $('#pid-tuning input[class="rc_rate_input"]'); + const rate_input_c = $('#pid-tuning input[class="rate_input"]'); + const expo_input_c = $('#pid-tuning input[class="expo_input"]'); + + if (!sameType) { + rate_input_c.val(rateDefault); + rc_rate_input_c.val(rcRateDefault); + expo_input_c.val(expoDefault); + } + + rc_rate_input_c.attr({"max":rcRateMax, "min":rcRateMin, "step":rcRateStep}).change(); + rate_input_c.attr({"max":rateMax, "min":rateMin, "step":rateStep}).change(); + expo_input_c.attr({"max":expoMax, "min":expoMin, "step":expoStep}).change(); + + if (sameType) { + self.setDirty(false); + } +}; + +TABS.pid_tuning.changeRatesTypeLogo = function() { + let self = this; + + const ratesLogoElement = $('.rates_type img[id="ratesLogo"]'); + + switch(self.currentRatesType) { + case self.RATES_TYPE.RACEFLIGHT: + ratesLogoElement.attr("src", "../images/rate_logos/raceflight.svg"); + + break; + + case self.RATES_TYPE.KISS: + ratesLogoElement.attr("src", "../images/rate_logos/kiss.svg"); + + break; + + case self.RATES_TYPE.ACTUAL: + ratesLogoElement.attr("src", "../images/rate_logos/actual.svg"); + + break; + + case self.RATES_TYPE.QUICKRATES: + ratesLogoElement.attr("src", "../images/rate_logos/quickrates.svg"); + + break; + + // add future rates types here + default: // BetaFlight + ratesLogoElement.attr("src", "../images/rate_logos/betaflight.svg"); + + break; + } +}; diff --git a/src/js/tabs/receiver.js b/src/js/tabs/receiver.js index 67f25c6b..f4f7c1ae 100644 --- a/src/js/tabs/receiver.js +++ b/src/js/tabs/receiver.js @@ -572,7 +572,7 @@ TABS.receiver.initialize = function (callback) { tab.renderModel(); // TODO: Combine two polls together - GUI.interval_add('receiver_pull_for_model_preview', tab.getRecieverData, 33, false); + GUI.interval_add('receiver_pull_for_model_preview', tab.getReceiverData, 33, false); // status data pulled via separate timer with static speed GUI.interval_add('status_pull', function status_pull() { @@ -583,7 +583,7 @@ TABS.receiver.initialize = function (callback) { } }; -TABS.receiver.getRecieverData = function () { +TABS.receiver.getReceiverData = function () { MSP.send_message(MSPCodes.MSP_RC, false, false); }; diff --git a/src/tabs/pid_tuning.html b/src/tabs/pid_tuning.html index b9715400..145b0322 100644 --- a/src/tabs/pid_tuning.html +++ b/src/tabs/pid_tuning.html @@ -107,7 +107,7 @@
-
+
@@ -142,7 +142,7 @@
-
+
@@ -319,7 +319,7 @@
-
+
@@ -366,7 +366,7 @@
-
+
@@ -376,13 +376,13 @@
-
+
-
+
@@ -656,7 +656,38 @@