diff --git a/js/flightlog.js b/js/flightlog.js index 7d3c3887..24c6ca42 100644 --- a/js/flightlog.js +++ b/js/flightlog.js @@ -11,7 +11,7 @@ */ function FlightLog(logData) { var - ADDITIONAL_COMPUTED_FIELD_COUNT = 15, /** attitude + PID_SUM + PID_ERROR + RCCOMMAND_SCALED **/ + ADDITIONAL_COMPUTED_FIELD_COUNT = 23, /** attitude + PID_SUM + PID_ERROR + RCCOMMAND_SCALED + MOTOR_LEGACY **/ that = this, logIndex = false, @@ -232,6 +232,15 @@ function FlightLog(logData) { if (!(that.isFieldDisabled().GYRO || that.isFieldDisabled().PID)) { fieldNames.push("axisError[0]", "axisError[1]", "axisError[2]"); // Custom calculated error field } + if (!that.isFieldDisabled().MOTORS) { + for (let i = 0; i < MAX_MOTOR_NUMBER; i++) { + if (fieldNames.find(element => element === `motor[${i}]`)) { + fieldNames.push(`motorLegacy[${i}]`); + } else { + break; + } + } + } fieldNameToIndex = {}; for (let i = 0; i < fieldNames.length; i++) { @@ -240,10 +249,10 @@ function FlightLog(logData) { } function estimateNumMotors() { - var count = 0; + let count = 0; - for (var j = 0; j < 8; j++) { - if (that.getMainFieldIndexByName("motor[" + j + "]") !== undefined) { + for (let j = 0; j < MAX_MOTOR_NUMBER; j++) { + if (that.getMainFieldIndexByName(`motor[${j}]`) !== undefined) { count++; } } @@ -515,23 +524,27 @@ function FlightLog(logData) { * sourceChunks and destChunks can be the same array. */ function injectComputedFields(sourceChunks, destChunks) { - var - gyroADC = [fieldNameToIndex["gyroADC[0]"], fieldNameToIndex["gyroADC[1]"], fieldNameToIndex["gyroADC[2]"]], - accSmooth = [fieldNameToIndex["accSmooth[0]"], fieldNameToIndex["accSmooth[1]"], fieldNameToIndex["accSmooth[2]"]], - magADC = [fieldNameToIndex["magADC[0]"], fieldNameToIndex["magADC[1]"], fieldNameToIndex["magADC[2]"]], - rcCommand = [fieldNameToIndex["rcCommand[0]"], fieldNameToIndex["rcCommand[1]"], fieldNameToIndex["rcCommand[2]"], fieldNameToIndex["rcCommand[3]"]], - setpoint = [fieldNameToIndex["setpoint[0]"], fieldNameToIndex["setpoint[1]"], fieldNameToIndex["setpoint[2]"], fieldNameToIndex["setpoint[3]"]], - flightModeFlagsIndex = fieldNameToIndex["flightModeFlags"], // This points to the flightmode data + let gyroADC = [fieldNameToIndex["gyroADC[0]"], fieldNameToIndex["gyroADC[1]"], fieldNameToIndex["gyroADC[2]"]]; + let accSmooth = [fieldNameToIndex["accSmooth[0]"], fieldNameToIndex["accSmooth[1]"], fieldNameToIndex["accSmooth[2]"]]; + let magADC = [fieldNameToIndex["magADC[0]"], fieldNameToIndex["magADC[1]"], fieldNameToIndex["magADC[2]"]]; + let rcCommand = [fieldNameToIndex["rcCommand[0]"], fieldNameToIndex["rcCommand[1]"], fieldNameToIndex["rcCommand[2]"], fieldNameToIndex["rcCommand[3]"]]; + let setpoint = [fieldNameToIndex["setpoint[0]"], fieldNameToIndex["setpoint[1]"], fieldNameToIndex["setpoint[2]"], fieldNameToIndex["setpoint[3]"]]; + + const flightModeFlagsIndex = fieldNameToIndex["flightModeFlags"]; // This points to the flightmode data - sourceChunkIndex, destChunkIndex, + let axisPID = [[fieldNameToIndex["axisP[0]"], fieldNameToIndex["axisI[0]"], fieldNameToIndex["axisD[0]"], fieldNameToIndex["axisF[0]"]], + [fieldNameToIndex["axisP[1]"], fieldNameToIndex["axisI[1]"], fieldNameToIndex["axisD[1]"], fieldNameToIndex["axisF[1]"]], + [fieldNameToIndex["axisP[2]"], fieldNameToIndex["axisI[2]"], fieldNameToIndex["axisD[2]"], fieldNameToIndex["axisF[2]"]]]; - sysConfig, - attitude, + let motor = [fieldNameToIndex["motor[0]"], fieldNameToIndex["motor[1]"], fieldNameToIndex["motor[2]"], fieldNameToIndex["motor[3]"], + fieldNameToIndex["motor[4]"], fieldNameToIndex["motor[5]"], fieldNameToIndex["motor[6]"], fieldNameToIndex["motor[7]"]]; - axisPID = [[fieldNameToIndex["axisP[0]"], fieldNameToIndex["axisI[0]"], fieldNameToIndex["axisD[0]"], fieldNameToIndex["axisF[0]"]], - [fieldNameToIndex["axisP[1]"], fieldNameToIndex["axisI[1]"], fieldNameToIndex["axisD[1]"], fieldNameToIndex["axisF[1]"]], - [fieldNameToIndex["axisP[2]"], fieldNameToIndex["axisI[2]"], fieldNameToIndex["axisD[2]"], fieldNameToIndex["axisF[2]"]]]; + let sourceChunkIndex; + let destChunkIndex; + let attitude; + + const sysConfig = that.getSysConfig(); if (destChunks.length === 0) { return; @@ -562,7 +575,9 @@ function FlightLog(logData) { axisPID = false; } - sysConfig = that.getSysConfig(); + if (!motor[0]) { + motor = false; + } sourceChunkIndex = 0; destChunkIndex = 0; @@ -658,6 +673,16 @@ function FlightLog(logData) { } } + // Duplicate the motor field to show the motor legacy values + if (motor) { + for (let motorNumber = 0; motorNumber < numMotors; motorNumber++) { + destFrame[fieldIndex++] = srcFrame[motor[motorNumber]]; + } + } + + // Remove empty fields at the end + destFrame.splice(fieldIndex); + } } } @@ -1145,9 +1170,49 @@ FlightLog.prototype.rcCommandRawToThrottle = function(value) { return Math.min(Math.max(((value - this.getSysConfig().minthrottle) / (this.getSysConfig().maxthrottle - this.getSysConfig().minthrottle)) * 100.0, 0.0),100.0); }; -FlightLog.prototype.rcMotorRawToPct = function(value) { +FlightLog.prototype.rcmotorRawToPctEffective = function(value) { + // Motor displayed as percentage return Math.min(Math.max(((value - this.getSysConfig().motorOutput[0]) / (this.getSysConfig().motorOutput[1] - this.getSysConfig().motorOutput[0])) * 100.0, 0.0),100.0); + +}; + +FlightLog.prototype.rcmotorRawToPctPhysical = function(value) { + + // Motor displayed as percentage + let motorPct; + if (this.isDigitalProtocol()) { + motorPct = ((value - DSHOT_MIN_VALUE) / DSHOT_RANGE) * 100; + } else { + const MAX_ANALOG_VALUE = this.getSysConfig().maxthrottle; + const MIN_ANALOG_VALUE = this.getSysConfig().minthrottle; + const ANALOG_RANGE = MAX_ANALOG_VALUE - MIN_ANALOG_VALUE; + motorPct = ((value - MIN_ANALOG_VALUE) / ANALOG_RANGE) * 100; + } + return Math.min(Math.max(motorPct, 0.0), 100.0); + +}; + +FlightLog.prototype.isDigitalProtocol = function() { + let digitalProtocol; + switch(FAST_PROTOCOL[this.getSysConfig().fast_pwm_protocol]) { + case "PWM": + case "ONESHOT125": + case "ONESHOT42": + case "MULTISHOT": + case "BRUSHED": + digitalProtocol = false; + break; + case "DSHOT150": + case "DSHOT300": + case "DSHOT600": + case "DSHOT1200": + case "PROSHOT1000": + default: + digitalProtocol = true; + break; + } + return digitalProtocol; }; FlightLog.prototype.getPIDPercentage = function(value) { diff --git a/js/flightlog_fielddefs.js b/js/flightlog_fielddefs.js index a7d05990..686ff59e 100644 --- a/js/flightlog_fielddefs.js +++ b/js/flightlog_fielddefs.js @@ -10,6 +10,14 @@ function makeReadOnly(x) { return x; } +// Some constants used at different places +const MAX_MOTOR_NUMBER = 8; +const DSHOT_MIN_VALUE = 48; +const DSHOT_MAX_VALUE = 2047; +const DSHOT_RANGE = DSHOT_MAX_VALUE - DSHOT_MIN_VALUE; +const ANALOG_MIN_VALUE = 1000; + +// Fields definitions for lists var FlightLogEvent = makeReadOnly({ SYNC_BEEP: 0, diff --git a/js/flightlog_fields_presenter.js b/js/flightlog_fields_presenter.js index 6079e3f8..91652e41 100644 --- a/js/flightlog_fields_presenter.js +++ b/js/flightlog_fields_presenter.js @@ -4,7 +4,7 @@ function FlightLogFieldPresenter() { } (function() { - var FRIENDLY_FIELD_NAMES = { + const FRIENDLY_FIELD_NAMES = { 'axisP[all]': 'PID P', 'axisP[0]': 'PID P [roll]', @@ -58,15 +58,25 @@ function FlightLogFieldPresenter() { //End-users prefer 1-based indexing 'motor[all]': 'Motors', - 'motor[0]': 'Motor [1]', - 'motor[1]': 'Motor [2]', - 'motor[2]': 'Motor [3]', + 'motor[0]': 'Motor [1]', + 'motor[1]': 'Motor [2]', + 'motor[2]': 'Motor [3]', 'motor[3]': 'Motor [4]', - 'motor[4]': 'Motor [5]', - 'motor[5]': 'Motor [6]', - 'motor[6]': 'Motor [7]', + 'motor[4]': 'Motor [5]', + 'motor[5]': 'Motor [6]', + 'motor[6]': 'Motor [7]', 'motor[7]': 'Motor [8]', + 'motorLegacy[all]': 'Motors (Legacy)', + 'motorLegacy[0]': 'Motor (Legacy) [1]', + 'motorLegacy[1]': 'Motor (Legacy) [2]', + 'motorLegacy[2]': 'Motor (Legacy) [3]', + 'motorLegacy[3]': 'Motor (Legacy) [4]', + 'motorLegacy[4]': 'Motor (Legacy) [5]', + 'motorLegacy[5]': 'Motor (Legacy) [6]', + 'motorLegacy[6]': 'Motor (Legacy) [7]', + 'motorLegacy[7]': 'Motor (Legacy) [8]', + 'servo[all]': 'Servos', 'servo[5]': 'Servo Tail', @@ -96,7 +106,7 @@ function FlightLogFieldPresenter() { 'rxFlightChannelsValid': 'RX Flight Ch. Valid', 'rssi': 'RSSI', }; - + var DEBUG_FRIENDLY_FIELD_NAMES = { 'NONE' : { 'debug[all]':'Debug [all]', @@ -502,16 +512,26 @@ function FlightLogFieldPresenter() { return (value + 1500).toFixed(0) + " us"; case 'rcCommand[3]': return value.toFixed(0) + " us"; - + case 'motor[0]': - case 'motor[1]': - case 'motor[2]': - case 'motor[3]': - case 'motor[4]': - case 'motor[5]': - case 'motor[6]': - case 'motor[7]': - return Math.round(flightLog.rcMotorRawToPct(value)) + " %"; + case 'motor[1]': + case 'motor[2]': + case 'motor[3]': + case 'motor[4]': + case 'motor[5]': + case 'motor[6]': + case 'motor[7]': + return `${flightLog.rcmotorRawToPctPhysical(value).toFixed(2)} %`; + + case 'motorLegacy[0]': + case 'motorLegacy[1]': + case 'motorLegacy[2]': + case 'motorLegacy[3]': + case 'motorLegacy[4]': + case 'motorLegacy[5]': + case 'motorLegacy[6]': + case 'motorLegacy[7]': + return `${flightLog.rcmotorRawToPctEffective(value).toFixed(2)} % (${value})`; case 'rcCommands[0]': case 'rcCommands[1]': diff --git a/js/flightlog_parser.js b/js/flightlog_parser.js index d22e4d01..68d6dc68 100644 --- a/js/flightlog_parser.js +++ b/js/flightlog_parser.js @@ -621,6 +621,7 @@ var FlightLogParser = function(logData) { case "rates_type": case "vbat_sag_compensation": case "fields_disabled_mask": + case "motor_pwm_protocol": that.sysConfig[fieldName] = parseInt(fieldValue, 10); break; case "rc_expo": diff --git a/js/graph_config.js b/js/graph_config.js index def6cd8b..3020d7a4 100644 --- a/js/graph_config.js +++ b/js/graph_config.js @@ -174,7 +174,7 @@ GraphConfig.load = function(config) { (function() { GraphConfig.getDefaultSmoothingForField = function(flightLog, fieldName) { try{ - if (fieldName.match(/^motor\[/)) { + if (fieldName.match(/^motor(Raw)?\[/)) { return 5000; } else if (fieldName.match(/^servo\[/)) { return 5000; @@ -260,11 +260,20 @@ GraphConfig.load = function(config) { try { if (fieldName.match(/^motor\[/)) { + return { + offset: flightLog.isDigitalProtocol() ? + -(DSHOT_MIN_VALUE + DSHOT_RANGE / 2) : -(sysConfig.minthrottle + (sysConfig.maxthrottle - sysConfig.minthrottle) / 2), + power: 1.0, + inputRange: flightLog.isDigitalProtocol() ? + DSHOT_RANGE / 2 : (sysConfig.maxthrottle - sysConfig.minthrottle) / 2, + outputRange: 1.0, + }; + } else if (fieldName.match(/^motorLegacy\[/)) { return { offset: -(sysConfig.motorOutput[1] + sysConfig.motorOutput[0]) / 2, power: 1.0, inputRange: (sysConfig.motorOutput[1] - sysConfig.motorOutput[0]) / 2, - outputRange: 1.0 + outputRange: 1.0, }; } else if (fieldName.match(/^servo\[/)) { return {