From 1dbe298abd0e9c2a9018d582c1f662b4e08f0a73 Mon Sep 17 00:00:00 2001 From: Mark Haslinghuis Date: Fri, 20 Aug 2021 23:47:54 +0200 Subject: [PATCH] Change Sliders and defaults 0-1-2 ranges ff and dmax gui fixes Fix master slider Fix TODO Fix enable slider when PID has changed Fix RP mode editing manual values Restore backward compatibility Rearrange order of 4.3 sliders and add divider for expert mode d_lowpass slider range changed, 75-150 defaults Fix filter sliders Optimise FF, DMax and filter slider steps Fix doubleclick on pid sliders stop D lowpass slider position moving left on save update gyro and dterm lowpass filter messages fix some bugs Fix spacing in messages Little fixes Respect slider mode Fix legacy mode and slider values Code cleanup Add slider defaults rename dmin ratio to dmax gain Fix legacy sliders again Enable Expert Mode --- locales/en/messages.json | 249 +++++++++------- src/css/tabs/pid_tuning.css | 6 + src/js/TuningSliders.js | 369 ++++++++++++++++-------- src/js/fc.js | 55 +++- src/js/main.js | 6 + src/js/msp/MSPHelper.js | 18 +- src/js/tabs/motors.js | 4 - src/js/tabs/pid_tuning.js | 552 +++++++++++++++++++++++++----------- src/js/utils/common.js | 5 + src/tabs/pid_tuning.html | 292 ++++++++++++------- 10 files changed, 1048 insertions(+), 508 deletions(-) diff --git a/locales/en/messages.json b/locales/en/messages.json index 8392244d..3ba698bc 100644 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -202,7 +202,7 @@ }, "sensorDataFlashNotFound": { - "message": "No dataflash
chip found", + "message": "No dataflash
chip found", "description": "Text of the dataflash image in the header of the page." }, "sensorDataFlashFreeSpace": { @@ -255,10 +255,10 @@ "message": "Show update notifications for unstable versions of the configurator" }, "configuratorUpdateNotice": { - "message": "You are using an outdated version of the Betaflight Configurator.
$t(configuratorUpdateHelp.message)" + "message": "You are using an outdated version of the Betaflight Configurator.
$t(configuratorUpdateHelp.message)" }, "configuratorUpdateHelp": { - "message": "Using a newer version of the firmware with an outdated version of Configurator means that changing some settings will result in a corrupted firmware configuration and a non-working craft. Furthermore, some features of the firmware will only be configurable in CLI.
Betaflight Configurator version $1 is available for download online, please visit this page to download and install the latest version with fixes and improvements.
Please close the configurator window before updating." + "message": "Using a newer version of the firmware with an outdated version of Configurator means that changing some settings will result in a corrupted firmware configuration and a non-working craft. Furthermore, some features of the firmware will only be configurable in CLI.
Betaflight Configurator version $1 is available for download online, please visit this page to download and install the latest version with fixes and improvements.
Please close the configurator window before updating." }, "configuratorUpdateWebsite": { "message": "Go to Release Website" @@ -534,13 +534,13 @@ "message": "Please fix these problems before attempting to fly your craft." }, "reportProblemsDialogAPI_VERSION_MAX_SUPPORTED": { - "message": "the version of configurator that you are using ($3) is older than the firmware you are using ($4).
$t(configuratorUpdateHelp.message)" + "message": "the version of configurator that you are using ($3) is older than the firmware you are using ($4).
$t(configuratorUpdateHelp.message)" }, "reportProblemsDialogMOTOR_PROTOCOL_DISABLED": { - "message": "there is no motor output protocol selected.
Please select a motor output protocol appropriate for your ESCs in '$t(configurationEscFeatures.message)' on the '$t(tabMotorTesting.message)' tab.
$t(escProtocolDisabledMessage.message)" + "message": "there is no motor output protocol selected.
Please select a motor output protocol appropriate for your ESCs in '$t(configurationEscFeatures.message)' on the '$t(tabMotorTesting.message)' tab.
$t(escProtocolDisabledMessage.message)" }, "reportProblemsDialogACC_NEEDS_CALIBRATION": { - "message": "the accelerometer is enabled but it is not calibrated.
If you plan to use the accelerometer, please follow the instructions for '$t(initialSetupButtonCalibrateAccel.message)' on the '$t(tabSetup.message)' tab. If any function that requires the accelerometer (auto level modes, GPS rescue, ...) is enabled, arming of the craft will be disabled until the accelerometer has been calibrated.
If you are not planning on using the accelerometer it is recommended that you disable it in '$t(configurationSystem.message)' on the '$t(tabConfiguration.message)' tab." + "message": "the accelerometer is enabled but it is not calibrated.
If you plan to use the accelerometer, please follow the instructions for '$t(initialSetupButtonCalibrateAccel.message)' on the '$t(tabSetup.message)' tab. If any function that requires the accelerometer (auto level modes, GPS rescue, ...) is enabled, arming of the craft will be disabled until the accelerometer has been calibrated.
If you are not planning on using the accelerometer it is recommended that you disable it in '$t(configurationSystem.message)' on the '$t(tabConfiguration.message)' tab." }, "infoVersionOs": { @@ -763,7 +763,7 @@ }, "initialSetupBackupAndRestoreApiVersion": { - "message": "Backup and restore functionality disabled. You have firmware with API version $1, backup and restore requires $2. Please backup your settings via the CLI, see Betaflight documentation for procedure." + "message": "Backup and restore functionality disabled. You have firmware with API version $1, backup and restore requires $2. Please backup your settings via the CLI, see Betaflight documentation for procedure." }, "initialSetupButtonCalibrateAccel": { "message": "Calibrate Accelerometer" @@ -1192,7 +1192,7 @@ "message": "ESC/Motor Features" }, "configurationFeaturesHelp": { - "message": "Note: Not all combinations of features are valid. When the flight controller firmware detects invalid feature combinations conflicting features will be disabled.
Note: Configure serial ports before enabling the features that will use the ports." + "message": "Note: Not all combinations of features are valid. When the flight controller firmware detects invalid feature combinations conflicting features will be disabled.
Note: Configure serial ports before enabling the features that will use the ports." }, "configurationSerialRXHelp": { "message": "Note: Remember to configure a Serial Port (via Ports tab) and choose a Serial Receiver Provider when using RX_SERIAL feature." @@ -1282,7 +1282,7 @@ "message": "Motor Idle Throttle Value [percent]" }, "configurationDigitalIdlePercentHelp": { - "message": "The 'DShot idle' value is the percent of maximum throttle that is sent to the ESCs when the throttle at minimum stick position and the craft is armed. Increase it to gain more idle speed and avoid desyncs. Too high and the craft feels floaty." + "message": "The 'DShot idle' value is the percent of maximum throttle that is sent to the ESCs when the throttle at minimum stick position and the craft is armed. Increase it to gain more idle speed and avoid desyncs. Too high and the craft feels floaty." }, "configurationMotorPoles": { "message": "Motor poles", @@ -1493,7 +1493,7 @@ "message": "Dynamic Notch values change" }, "dialogDynFiltersChangeNote": { - "message": "WARNING: Some dynamic notch values have been changed to default values because the RPM filtering has been activated/deactivated.
Please, check before flying." + "message": "WARNING: Some dynamic notch values have been changed to default values because the RPM filtering has been activated/deactivated.
Please, check before flying." }, "dialogDynFiltersConfirm": { "message": "OK" @@ -1517,16 +1517,16 @@ "message": "Peripherals" }, "portsHelp": { - "message": "Note: not all combinations are valid. When the flight controller firmware detects this the serial port configuration will be reset." + "message": "Note: not all combinations are valid. When the flight controller firmware detects this the serial port configuration will be reset." }, "portsVtxTableNotSet": { "message": "WARNING: The VTX table has not been set up correctly and without it VTX control will not be possible. Please set up the VTX table in $t(tabVtx.message) tab." }, "portsMSPHelp": { - "message": "Note: Do NOT disable MSP on the first serial port unless you know what you are doing. You may have to reflash and erase your configuration if you do." + "message": "Note: Do NOT disable MSP on the first serial port unless you know what you are doing. You may have to reflash and erase your configuration if you do." }, "portsFirmwareUpgradeRequired": { - "message": "Firmware upgrade required. Serial port configurations of firmware < 1.8.0 is not supported." + "message": "Firmware upgrade required. Serial port configurations of firmware < 1.8.0 is not supported." }, "portsButtonSave": { "message": "Save and Reboot" @@ -1655,21 +1655,25 @@ "pidTuningDMinDisabledNote": { "message": "Note: D Min feature is disabled and its parameters are hidden. To use D Min please enable it in $t(pidTuningPidSettings.message)." }, + "pidTuningDMinFeatureTitle": { + "message": "Dynamic Damping", + "description": "Title for the options panel for the D Max feature" + }, "pidTuningDMinGain": { - "message": "Gain", - "description": "Gain of the D Min feature" + "message": "Gain", + "description": "Gain of the D Max feature" }, "pidTuningDMinAdvance": { - "message": "Advance", - "description": "Advance of the D Min feature" + "message": "Advance", + "description": "Advance of the D Max feature" }, "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 prop-wash events. Advance makes D go up earlier by using setpoint instead of gyro to determine sharp moves.", - "description": "D Min feature helpicon message" + "message": "The D Max boost algorithm brings D towards the D Max value during fast movements. It has two smoothed inputs, each with a 0-100 range, and both are additive. 'Advance' increases D towards D Max during stick movements, slightly ahead of 'Gain', which increases D towards D Max when the quad turns, or is shaking in propwash. Only 'Gain' lifts D with shaking or propwash. Both respond more strongly to faster than slower movement. Usually, only 'Gain' is needed. Advance can be added for low authority quads that tend to overshoot heavily. At default values of 30, D reaches D Max only during very fast movements. A value of 100 would bring D up to D Max very readily, so that the effective D during almost any movement would be the D Max value.", + "description": "D Max feature helpicon message" }, "pidTuningDMinHelp": { - "message": "Controls the strength of dampening (D-term) in normal forward flight.
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 D_max gains specified to the left.

Full D_max gains are reached on sharp stick inputs, but only partial are achieved during prop-wash.
Adjust the D_Min Gain and Advance to control the gain boost sensitivity and timing.", - "description": "D Min helpicon message on PID table titlebar" + "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.

Higher gains provide more dampening and reduce overshoot by P-term and FF.
However, the D-term is VERY sensitive to gyro high frequency vibrations (noise | magnifies by 10x to 100x).

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).

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 helpicon message on PID table titlebar" }, "pidTuningPidSettings": { "message": "PID Controller Settings" @@ -1688,7 +1692,7 @@ "description": "Auto Factor parameter for RC smoothing" }, "receiverRcSmoothingAutoFactorHelp": { - "message": "Adjusts the Auto factor calculation, 10 is the default factor to delay ratio. Increasing the number will smooth RC inputs more, while also adding delay. This may be useful for unreliable RC connections or for cinematic flying.
Be careful with numbers approaching 50, input delay will become noticeable.
Use the CLI command rc_smoothing_info while TX and RX are powered to see the automatically calculated RC smoothing cutoffs. ", + "message": "Adjusts the Auto factor calculation, 10 is the default factor to delay ratio. Increasing the number will smooth RC inputs more, while also adding delay. This may be useful for unreliable RC connections or for cinematic flying.
Be careful with numbers approaching 50, input delay will become noticeable.
Use the CLI command rc_smoothing_info while TX and RX are powered to see the automatically calculated RC smoothing cutoffs. ", "description": "Auto Factor parameter help message" }, "receiverRcFeedforwardTypeSelect": { @@ -1782,7 +1786,7 @@ "message": "Transition" }, "pidTuningFeedforwardTransitionHelp": { - "message": "With this parameter, the Feedforward term can be reduced near the center of the sticks, which results in smoother end of flips and rolls.
The value represents a point of stick deflection: 0 - stick centered, 1 - full deflection. When the stick is above that point, Feedforward is kept constant at its configured value. When the stick is positioned below that point, Feedforward is reduced proportionally, reaching 0 at the stick center position.
Value of 1 gives maximum smoothing effect, while value of 0 keeps the Feedforward fixed at its configured value over the whole stick range." + "message": "With this parameter, the Feedforward term can be reduced near the center of the sticks, which results in smoother end of flips and rolls.
The value represents a point of stick deflection: 0 - stick centered, 1 - full deflection. When the stick is above that point, Feedforward is kept constant at its configured value. When the stick is positioned below that point, Feedforward is reduced proportionally, reaching 0 at the stick center position.
Value of 1 gives maximum smoothing effect, while value of 0 keeps the Feedforward fixed at its configured value over the whole stick range." }, "pidTuningDtermSetpointTransition": { "message": "D Setpoint transition" @@ -1791,10 +1795,10 @@ "message": "D Setpoint Weight" }, "pidTuningDtermSetpointTransitionHelp": { - "message": "With this parameter, D Setpoint Weight can be reduced near the center of the sticks, which results in smoother end of flips and rolls.
The value represents a point of stick deflection: 0 - stick centered, 1 - full deflection. When the stick is above that point, Setpoint Weight is kept constant at its configured value. When the stick is positioned below that point, Setpoint Weight is reduced proportionally, reaching 0 at the stick center position.
Value of 1 gives maximum smoothing effect, while value of 0 keeps the Setpoint Weight fixed at its configured value over the whole stick range." + "message": "With this parameter, D Setpoint Weight can be reduced near the center of the sticks, which results in smoother end of flips and rolls.
The value represents a point of stick deflection: 0 - stick centered, 1 - full deflection. When the stick is above that point, Setpoint Weight is kept constant at its configured value. When the stick is positioned below that point, Setpoint Weight is reduced proportionally, reaching 0 at the stick center position.
Value of 1 gives maximum smoothing effect, while value of 0 keeps the Setpoint Weight fixed at its configured value over the whole stick range." }, "pidTuningDtermSetpointHelp": { - "message": "This parameter determines the stick accelerating effect within derivative component.
Value of 0 equals to old Measuemenent method where D only tracks gyro, while value of 1 equals to old Error method with equal gyro and stick tracking ratio.
Lower value equals to slower/smoother stick response, while higher value provides more stick acceleration response.
Note that RC interpolation is recommended to be enabled with higher values to prevent control kicks making noise." + "message": "This parameter determines the stick accelerating effect within derivative component.
Value of 0 equals to old Measuemenent method where D only tracks gyro, while value of 1 equals to old Error method with equal gyro and stick tracking ratio.
Lower value equals to slower/smoother stick response, while higher value provides more stick acceleration response.
Note that RC interpolation is recommended to be enabled with higher values to prevent control kicks making noise." }, "pidTuningDtermSetpointTransitionWarning": { "message": "$t(warningTitle.message):<\/strong> The use of a D Setpoint transition greater than 0 and less than 0.1 is highly discouraged. Doing so may lead instability and reduced stick responsiveness as the sticks cross the centre point.<\/span>" @@ -1830,14 +1834,14 @@ "message": "Proportional" }, "pidTuningProportionalHelp": { - "message": "Controls the strength of how tightly the machine tracks the sticks (the Setpoint).

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.", + "message": "Controls the strength of how tightly the machine tracks the sticks (the Setpoint).

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.
Similar to Proportional, but for longer biases on the craft such as an offset center of gravity (CoG) or persistent outside influence (steady wind).

Higher gains provide tighter tracking (e.g.: in sweeping turns), but can make the craft feel stiff for commanded stick inputs.
If extremely high in proportion to the D-term, can cause slow oscillations.", + "message": "Controls the strength of how tightly the machine holds the overall position of the Setpoint.
Similar to Proportional, but for longer biases on the craft such as an offset center of gravity (CoG) or persistent outside influence (steady wind).

Higher gains provide tighter tracking (e.g.: in sweeping turns), but can make the craft feel stiff for commanded stick inputs.
If extremely high in proportion to the D-term, can cause slow oscillations.", "description": "Integral Term helpicon message on PID table titlebar" }, "pidTuningDerivative": { @@ -1847,14 +1851,14 @@ "message": "D Max" }, "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.

Higher gains provide more dampening and reduce overshoot by P-term and FF.
However, the D-term is VERY sensitive to gyro high frequency vibrations (noise | magnifies by 10x to 100x).

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).

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" + "message": "D Max provides a higher level of D for quick maneuvers that might otherwise cause overshoot, like flips and rolls. It is particularly useful on noisy builds or low authority machines. D Max allows the basic D, or Damping, value to be set lower than otherwise might be needed, helping keep motors cooler, and turn-in faster. D Max also brings D up during prop-wash. D Max Advance and Gain values control the timing and strength of the increase. HD Freestyle and Cinematic builds pilots typically run a relatively high Derivative value to achieve stability in forward flight, and don't need so much of an increase from D Max. Race pilots typically care about keeping motors cool even with bent props, so they run lower basic D values and keep D Max up to control overshoot.", + "description": "D Max 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.

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.

Higher values (gains) will result in a more sharp machine response to stick input.
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).
Lower or zero (0) values will result in a slower and smoother response to stick inputs.", + "message": "Is an additional pushing term (spring) based on stick input. FF helps the P-term push the craft for commanded stick moves.

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.

Higher values (gains) will result in a more sharp machine response to stick input.
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).
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" }, "pidTuningMaxRateWarning": { @@ -1962,6 +1966,9 @@ "pidTuningResetProfile": { "message": "Reset all profile values" }, + "pidTuningResetWarning": { + "message": "Warning:

Resets profile values to defaults and permanently saves PID and D Filter settings.

This action is irreversible." + }, "pidTuningProfileReset": { "message": "Loaded default profile values." }, @@ -1983,20 +1990,27 @@ "pidTuningEepromSaved": { "message": "EEPROM saved" }, - - "receiverHelp": { - "message": "Please read receiver chapter of the documentation. Configure serial port (if required), receiver mode (serial/ppm/pwm), provider (for serial receivers), bind receiver, set channel map, configure channel endpoints/range on TX so that all channels go from ~1000 to ~2000. Set midpoint (default 1500), trim channels to 1500, configure stick deadband, verify behaviour when TX is off or out of range.
IMPORTANT: Before flying read failsafe chapter of documentation and configure failsafe." - }, "tuningHelp": { - "message": "Tuning tips
IMPORTANT: It is important to verify motor temperatures during first flights. The higher the filter value gets the better it may fly, but you also will get more noise into the motors.
Default value of 100Hz is optimal, but for noiser setups you can try lowering Dterm filter to 50Hz and possibly also the gyro filter." + "message": "Tuning tips
IMPORTANT: It is important to verify motor temperatures during first flights. The higher the filter value gets the better it may fly, but you also will get more noise into the motors.
Default value of 100Hz is optimal, but for noiser setups you can try lowering Dterm filter to 50Hz and possibly also the gyro filter." }, "tuningHelpSliders": { - "message": "IMPORTANT: We recommend using the sliders to change filter settings. Move both sliders together.
It is best to make relatively small changes and test fly after each change. Check the motor temperatures closely before making further changes.
Less filtering (sliders to the right, higher cutoff values) will improve prop-wash, but will let more noise through to the motors, making them hotter, possibly hot enough to burn out. Less filtering is possible on most clean builds and if rpm filtering is enabled.
Unusually high or low filter settings may cause flyaways on arming. The defaults are safe for typical 5\" quads.
Note: Changing profiles will only change the D-term filter settings. Gyro filter settings are the same for all profiles.", + "message": "We recommend using the sliders to adjust filtering.
Make relatively small changes, test fly and check motor temperature after each change.
Moving the sliders to the right gives higher cutoff values; this may improve prop-wash, but lets more noise through to the motors, making them hotter, possibly hot enough to burn out.
Most clean builds with rpm filtering will be OK with gyro filtering hard right.
In contrast, be very cautious when moving D filter sliders to the right!
Unusually high or low filter settings may cause flyaways on arming. The defaults are safe for typical 5\" quads.
Note: Changing profiles will only change the D-term filter settings. Gyro filter settings are the same for all profiles.", "description": "Filter tuning subtab note" }, "filterWarning": { "message": "Warning: The amount of filtering you are using is dangerously low. This is likely to make the craft hard to control, and can result in flyaways. It is highly recommended that you enable at least one of Gyro Dynamic Lowpass or Gyro Lowpass 1 and at least one of D-Term Dynamic Lowpass or D Term Lowpass 1." }, + "sliderPidsModeSelect": { + "message": "Mode:", + "description": "Pidtuning slider mode can be OFF, RP or RPY" + }, + "pidTuningSliderModeHelp": { + "message": "Pid Tuning Slider Mode

Pidtuning slider mode can be:

• OFF - no sliders, enter values manually
• RP - sliders control Roll and Pitch only, enter Yaw values manually
• RPY - sliders control all PID values

Important:

Please save after changing slider mode before changing other settings." + }, + + "receiverHelp": { + "message": "Please read receiver chapter of the documentation. Configure serial port (if required), receiver mode (serial/ppm/pwm), provider (for serial receivers), bind receiver, set channel map, configure channel endpoints/range on TX so that all channels go from ~1000 to ~2000. Set midpoint (default 1500), trim channels to 1500, configure stick deadband, verify behaviour when TX is off or out of range.
IMPORTANT: Before flying read failsafe chapter of documentation and configure failsafe." + }, "receiverThrottleMid": { "message": "Throttle MID" }, @@ -2293,7 +2307,7 @@ "message": "Your flight controller's firmware does not support transponder functionality." }, "transponderInformation": { - "message": "Transponders systems allow race organizers to time your laps. The transponder is fitted to your aircraft and when your aircraft passes the timing gate the track-side receiver registers your code and records your laptime. When fitting an IR based transponder your should ensure that it points outward from your aircraft towards the track-side receivers and that the light beam is not obstructed by your airframe, battery-straps, cables, propellers, etc." + "message": "Transponders systems allow race organizers to time your laps. The transponder is fitted to your aircraft and when your aircraft passes the timing gate the track-side receiver registers your code and records your laptime. When fitting an IR based transponder your should ensure that it points outward from your aircraft towards the track-side receivers and that the light beam is not obstructed by your airframe, battery-straps, cables, propellers, etc." }, "transponderConfigurationType": { "message": "Transponder type" @@ -2332,7 +2346,7 @@ "message": "Hexadecimal digits only, 0-9, A-F" }, "transponderHelp1": { - "message": "Configure your transponder code here. Note: Only valid codes will be recognised by race timing systems. Valid transponder codes can be obtained from Seriously Pro." + "message": "Configure your transponder code here. Note: Only valid codes will be recognised by race timing systems. Valid transponder codes can be obtained from Seriously Pro." }, "transponderHelp2": { "message": "For more information please visit aRCiTimer site" @@ -2737,7 +2751,7 @@ }, "cliInfo": { - "message": "Note: Leaving CLI tab or pressing Disconnect will automatically send \"exit\" to the board. With the latest firmware this will make the controller restart and unsaved changes will be lost.

Warning: Some commands in CLI can result in arbitrary signals being sent on the motor output pins. This can cause motors to spin up if a battery is connected. Therefore it is highly recommended to make sure that no battery is connected before entering commands in CLI." + "message": "Note: Leaving CLI tab or pressing Disconnect will automatically send \"exit\" to the board. With the latest firmware this will make the controller restart and unsaved changes will be lost.

Warning: Some commands in CLI can result in arbitrary signals being sent on the motor output pins. This can cause motors to spin up if a battery is connected. Therefore it is highly recommended to make sure that no battery is connected before entering commands in CLI." }, "cliInputPlaceholder": { "message": "Write your command here. Press Tab for AutoComplete." @@ -2870,7 +2884,7 @@ "message": "Save flash to file... (unsupported)" }, "dataflashSavetoFileNote": { - "message": "Directly saving flash to file is slow and inherently prone to error / file corruption.
In some cases it will work for small files, but this is not supported and support requests for it will be closed without comment - use Mass Storage mode instead." + "message": "Directly saving flash to file is slow and inherently prone to error / file corruption.
In some cases it will work for small files, but this is not supported and support requests for it will be closed without comment - use Mass Storage mode instead." }, "dataflashSaveFileDepreciationHint": { "message": "This method is slow and inherently prone to error / file corruption, because the MSP connection itself has intrinsic, fundamental limitations that make it unsuitable for file transfers. It may work for small log files only. Do not create support requests if file transfers fail when saved using this method. The recommended method is to use '$t(onboardLoggingRebootMscText.message)' (below) to activate the Mass Storage Mode, and access your flight controller as a storage device to download the log files." @@ -2913,7 +2927,7 @@ "message": "No card inserted" }, "sdcardStatusReboot": { - "message": "Fatal error
Reboot to retry" + "message": "Fatal error
Reboot to retry" }, "sdcardStatusReady": { "message": "Card ready" @@ -2965,7 +2979,7 @@ "message": "Download manually." }, "firmwareFlasherTargetWarning": { - "message": "IMPORTANT: Ensure you flash a file appropriate for your target. Flashing a binary for the wrong target can cause bad things to happen." + "message": "IMPORTANT: Ensure you flash a file appropriate for your target. Flashing a binary for the wrong target can cause bad things to happen." }, "firmwareFlasherPath": { @@ -2996,7 +3010,7 @@ "message": "Select or auto-detect your board to see available online firmware releases - Select the correct firmware appropriate for your board." }, "firmwareFlasherOnlineSelectBoardHint": { - "message": "Starting with Betaflight 4.1, Betaflight is introducing support for Unified Targets. The concept of Unified Targets means that the same firmware .hex file can be used for all boards using the same MCU (F4, F7). To make the different boards work with the same firmware, a specific configuration file is deployed alongside the firmware when a Unified Target is flashed.
This version of Betaflight configurator supports flashing of Unified Targets with the respective board specific configurations in one step. The different firmware types that are available for each board are shown in the drop-down as follows:

<board name> or
<board name> (Legacy):
non-unified target, or pre-4.1 versions of the firmware for Unified Targets.

<board name> (<manufacturer id>):
(4 character manufacturer id)
Unified Target.

Please use Unified Targets where available. If you encounter problems using a Unified Target, please open an issue and then use the non-unified target until the issue has been resolved." + "message": "Starting with Betaflight 4.1, Betaflight is introducing support for Unified Targets. The concept of Unified Targets means that the same firmware .hex file can be used for all boards using the same MCU (F4, F7). To make the different boards work with the same firmware, a specific configuration file is deployed alongside the firmware when a Unified Target is flashed.
This version of Betaflight configurator supports flashing of Unified Targets with the respective board specific configurations in one step. The different firmware types that are available for each board are shown in the drop-down as follows:

<board name> or
<board name> (Legacy):
non-unified target, or pre-4.1 versions of the firmware for Unified Targets.

<board name> (<manufacturer id>):
(4 character manufacturer id)
Unified Target.

Please use Unified Targets where available. If you encounter problems using a Unified Target, please open an issue and then use the non-unified target until the issue has been resolved." }, "firmwareFlasherOnlineSelectFirmwareVersionDescription": { "message": "Select firmware version for your board." @@ -3567,7 +3581,7 @@ "message": "Scale Factor [%]" }, "pidTuningMotorLimitHelp": { - "message": "Motor output linear scale factor (as percentage). Reduces ESC current and motor heat when using higher cell count batteries, e.g. When using a 6S battery on a craft that has motors, props and tuning designed for 4S, try setting the value at 66%; when using a 4S battery on a craft intended for 3S, try 75%.
Always make sure that all of your components can support the voltage of the battery you are using." + "message": "Motor output linear scale factor (as percentage). Reduces ESC current and motor heat when using higher cell count batteries, e.g. When using a 6S battery on a craft that has motors, props and tuning designed for 4S, try setting the value at 66%; when using a 4S battery on a craft intended for 3S, try 75%.
Always make sure that all of your components can support the voltage of the battery you are using." }, "pidTuningCellCount": { "message": "Cell Count" @@ -3579,8 +3593,7 @@ "message": "Profile independent Filter Settings" }, "pidTuningFilterSlidersHelp": { - "message": "Sliders to adjust the quad gyro and D-term filtering.

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.

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).
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" + "message": "Sliders to adjust the gyro and D-term filters.

Stronger filtering (sliders to left, lower cutoff frequencies) keeps motors cooler by removing more noise, but also increases gyro signal delay (phase delay) to the PID loop. This may worsen prop-wash and can make resonant oscillations worse. Less responsive quads eg X-Class often do well with stronger filtering.

Less Filtering (sliders to the right, higher cutoff frequencies) reduces gyro signal delay, and often improves propwash. Moving the gyro lowpass filter right is usually OK, but motors may get warm. Moving the D filter to the right is usually not required, and can quickly result in very hot motors." }, "pidTuningSliderLowFiltering": { "message": "Less Filtering", @@ -3599,7 +3612,7 @@ "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.
General motor noise ranges per quad class:

6\"+ quads - generally within 100hz to 330hz
5\" quads - generally within 220hz to 500hz
Whoop to 3\" quads - generally within 300hz to 850hz

Generally, you want to set the slider to have the Gyro Lowpass 1 Dynamic Min/Max Cutoff range cover the above.
However, for smoother flights use More Filtering on the slider. To get a more aggressive filter tune, use Less Filtering on the slider.

With Less Filtering BE CAREFUL to not get radical as to cause a fly-away or burn out motors.
Note frame resonance issues, bad bearings, and beat up props may cause you to need more filtering.", + "message": "Raises or Lowers the default Gyro Lowpass Filters in proportion to each-other. The gyro filtering is applied before the PID loop.
General motor noise ranges per quad class:

6\"+ quads - generally within 100hz to 330hz
5\" quads - generally within 220hz to 500hz
Whoop to 3\" quads - generally within 300hz to 850hz

Generally, you want to set the slider to have the Gyro Lowpass 1 Dynamic Min/Max Cutoff range cover the above.
However, for smoother flights use More Filtering on the slider. To get a more aggressive filter tune, use Less Filtering on the slider.

With Less Filtering BE CAREFUL to not get radical as to cause a fly-away or burn out motors.
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": { @@ -3607,11 +3620,11 @@ "description": "D Term filter tuning slider label" }, "pidTuningDTermFilterSliderHelp": { - "message": "Raises or Lower the default D-term Lowpass Filters in proportion to each-other.
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.

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.
That recommended differential is built into the default and slider scaling.", + "message": "Changes the D-term Lowpass Filter cutoffs.
Moving the slider to the left gives stronger D filtering (lower cutoff frequency); to the right gives less filtering (higher cutoff frequency).

D-term is the most sensitive PID element to noise and resonance. It can amplify any high frequency noise by 10x to 100x plus. That's why the cutoffs for the D filters are much lower than the gyro filters.

D-term filtering is applied after - in addition to - the gyro filtering. Strong D filtering will reduce motor heat on noisy quads and can be useful with high PID 'D' values to minimise D resonance at medium to high frequencies. However, strong D filtering may delay the D signal, worsening propwash handling and encouraging lower frequency D resonances. The default D filtering is optimal for most quads. Larger machines with high D may do better with stronger D filtering than defaults. Moving the D lowpass filter slider to the right is generally not required. On very clean builds, going to the right can attenuate propwash. It should be done very cautiously since having less filtering on D can result in sudden resonances (including motor grinding or taking off on arming) and extreme motor heat.", "description": "D Term filtering tuning slider helpicon message" }, "pidTuningPidSlidersHelp": { - "message": "Sliders to adjust the quad flight characteristics (PID gains)

Master Multiplier: Raises or Lowers all the PID gains (above) holding the proportional difference between the gains.

PD Balance: Adjusts the balance (ratio \\ proportional difference) between the P and D terms ('the spring' [p-term] and 'shock absorber' [d-term]).

PD Gain: Raises or Lowers the P&D gains together - holding the ratio (balance) between the two - for more (or less) PID control authority.

Stick Response Gain: Raises or Lowers the FeedForward gains to control the stick response feel of the quad.", + "message": "Sliders to adjust the quad flight characteristics (PID gains)

Damping (D gain): Resists fast movement, minimises P oscillation.

Tracking (P and I gain): Enchances the responsiveness of the quad, if too high may cause trilling or oscillation.

Stick Response (Feedforward): Increases the responsiveness of the quad to faster stick movements.

Drift - Wobble (I gain, expert): Fine adjustment of I.

Dynamic D (D Max, expert): Sets the maximum amount that D can be boosted to during fast movements.

Pitch Damping (Pitch:Roll D ratio, expert): Increases the amount of damping on pitch relative to roll.

Pitch Tracking (Pitch:Roll P, I and F ratio, expert): Increases stabilising strenght on pitch relative to roll.

Master Multiplier (all gains, expert): Raises or Lowers all the PID gains, keeping their proportions constant.", "description": "Overall helpicon message for PID tuning sliders" }, "pidTuningSliderWarning": { @@ -3646,58 +3659,91 @@ "message": "Master Multiplier:", "description": "Master tuning slider label" }, - "pidTuningRollPitchRatioSlider": { - "message": "Pitch-Roll Ratio:", - "description": "Pitch-Roll Ratio slider label" - }, - "pidTuningRollPitchRatioSliderHelp": { - "message": "The Pitch-Roll Ratio is the balance of Moment of Inertia (MoI) between the Pitch and Roll axis.

Generally, the Pitch axis has a higher MoI and therefore it may be appropriate to have PID gains higher on the Pitch axis vs the Roll axis. However, on 'Stretched X', or other configurations, this may not be the case.

Generally for tuning, you are moving up the 'P and D Gain' slider until one axis begins to show D-term oscillation (a 'trilling' noise) and then back it down some. Blackbox is the easies method to determine which axis is 'trilling'. Once you find which axis is at the D-term limit, you can use the Pitch-Roll Gain slider to bring the other axis to just short of the same limit to balance out the quad for peak flight performance.", - "description": "Pitch-Roll Ratio tuning slider helpicon message" - }, - "pidTuningIGainSlider": { - "message": "I-term Gain:", - "description": "I-term slider label" - }, - "pidTuningIGainSliderHelp": { - "message": "I-term needs to be in balance with the P-term; similar to how the P-term needs to be in balance with the D-term (Tuning sequence: Filters -> D-term -> P-term -> I-term).

The I-term Gain sliders adjust I-term gains while holding P-term gains constant to adjust the ratio between the two terms.

If you are getting slow wobbles when you drop to 0% throttle, that is an idication the I-term gains is too high and you should lower the I-term Gain slider OR raise the P and D Gain slider if you have not tuned D-term and PD Balance yet (which you should first before loweing I-Term).

This said, genereally you want the I-term gains as strong as they can be (but within balance) to keep the quad tracking on the sticks in spirrel turns, orbits, ect...", - "description": "I-gain Gain tuning slider helpicon message" + "pidTuningMasterSliderHelp": { + "message": "Increases all PID parameters equally. Don't change this slider unless you run out of adjustment on the other sliders. Typically this is only needed for low authority or high moment of inertia (MoI) quads like X-Class or cinelifter builds. Too much master gain may cause trilling oscillations or hot motors.", + "description": "Master Gain tuning slider helpicon message" }, "pidTuningPDRatioSlider": { "message": "PD Balance:", "description": "PD balance tuning slider label" }, + "pidTuningPDRatioSliderHelp": { + "message": "Changes D and D max. Relatively high D will dampen stick responsiveness and may make motors hot, but should help control P-term oscillations and will improve prop-wash oscillation.

Relatively low D-term gives quicker stick responsiveness, but will weaken prop-wash performance and reacting to external forces (wind).", + "description": "D_term tuning slider helpicon message" + }, "pidTuningPDGainSlider": { "message": "P and D Gain:", "description": "P and D Gain tuning slider label" }, - "pidTuningDMinRatioSlider": { - "message": "D_min Gain drop:", - "description": "D Min slider label" - }, - "pidTuningDMinRatioSliderHelp": { - "message": "Controls how much D-gains are suppressed in normal forward flight. Lower the slider to drop the D-gains MORE in normal forward flight. Raise the slider to drop D-gains LESS in normal forward flight.

With D_min enabled, the Active D-gain changes during flight. In normal forward flight (with D_min enabled) the Active D-gain hovers just above the D_min Gain values. During sharp stick moves or prop-wash, the Active D-gain raises to the D_max gains. See the D_min / D_max tips above for more detials.

Lower D-gains can help smooth out forward flight, negating the need to increase filtering on the Gyro and/or D-term in the Filters Setting tab; while it boost the Active D-gains to the D_max values when more D-term is needed to control overshooting and/or to stabiliize the quad in prop-wash conditions or to resist outside forces (wind).", - "description": "D_min slider helpicon message" - }, - "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 Moment of Inertia (MoI) ratio.

Smaller quads (micros) generally need lower PID gains due to a higher power to MoI ratio.

Higher values are for lower authority quads. Lower values are for higher authority quads.", - "description": "Master Gain tuning slider helpicon message" - }, - "pidTuningPDRatioSliderHelp":{ - "message": "Relatively high D-term will dampen stick responsiveness and may make motors hot, but should help control P-term oscillations and will improve prop-wash oscillation.

Relatively low D-term gives quicker stick responsiveness, but will weaken prop-wash performance and reacting to external forces (wind).", - "description": "PD balance tuning slider helpicon message" - }, "pidTuningPDGainSliderHelp":{ "message": "Lower P and D Gain will result in cooler motors but also in more prop-wash oscillation. Too low value may cause the quad to be unstable.

P and D terms work together to reduce prop-wash.

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":{ + "pidTuningResponseSliderLegacy": { + "message": "Stick Response Gain:", + "description": "Response tuning slider label" + }, + "pidTuningResponseSliderLegacyHelp": { "message": "Lower FF values will worsen the stick response and may result in slow bounceback at the end of a flip or roll due to the quad lagging the sticks too much and I-term winding up and cousing 'I-term Bounceback'.

Higher FF values will give snappier stick responses in sharp moves. Excessively high FF values can cause overshoots and fast bounceback at the end of a flip or roll.

Note:
The feature I-term Relax can stop the I-term from winding up on stick move for a low authority quads or if low Stick Response Gains are used.", "description": "Stick response gain tuning slider helpicon message" }, + + "pidTuningDGainSlider": { + "message": "Damping:
D Gains", + "description": "D Gain (Damping) tuning slider label" + }, + "pidTuningDGainSliderHelp": { + "message": "Relatively high D-gain will dampen stick responsiveness and may make motors hot, but should help control fast oscillations and willimprove prop-wash.

Relatively low D-term gives quicker stick responsiveness, but will weaken prop-wash performance and reacting to external forces (wind).", + "description": "D gain balance tuning slider helpicon message" + }, + "pidTuningPIGainSlider": { + "message": "Tracking:
P & I Gains", + "description": "P and I Gain (Stability) tuning slider label" + }, + "pidTuningPIGainSliderHelp": { + "message": "Increase the Tracking slider to sharpen the quads response to your commands and also outside influences; avoiding the nose of the quad going off course in any condition.

Lower ‘Tracking’ values will have lots of bobbles and will go off course on stick moves and in prop wash. High ‘Tracking’ may result in oscillation and fast bounceback (hard to see, but you canhear). Excessive Tracking may result in oscillations and hot motors.", + "description": "P and I gain tuning slider helpicon message" + }, + "pidTuningResponseSlider": { + "message": "Stick Response:
FF Gains", + "description": "Response tuning slider label" + }, + "pidTuningResponseSliderHelp": { + "message": "Lower Stick Response will increase the latency of the quad movements to commands and may result in slow bounceback at the end of a flip or roll. Higher Stick Response will give snappier quad response to sharp stick moves. Excessively high Stick Response can cause overshoots and fast bounceback at the end of a flip or roll.

Note:
The feature “I-term Relax” can stop bounceback for low authority quads or if low Stick Response Gains are used.", + "description": "Stick response gain tuning slider helpicon message" + }, + "pidTuningIGainSlider": { + "message": "Drift - Wobble:
I Gains", + "description": "I-term slider label" + }, + "pidTuningIGainSliderHelp": { + "message": "Increases or decreases I. Higher I may improve tracking in spiral turns, orbits, or 0% throttle commands. Too much I, particularly with not enough P, may cause wobbles or bounceback after flips/rolls or on chopping the throttle to 0%.

Generally you want the ‘Drift – Wobble’ slider to be as high as it can be to keep the quad tracking in spiral turns, orbits, ect... but not so high that you start to see wobbles on chopping the throttleto 0%.

Note:
If you experience bounceback at any time that is easy to see, make sure that “I-term Relax” is enabled, and try lowering the iterm_relax_cutoff value.", + "description": "I-gain Gain tuning slider helpicon message" + }, + "pidTuningDMaxGainSlider": { + "message": "Dynamic Damping:
D Max", + "description": "D Min slider label" + }, + "pidTuningDMaxGainSliderHelp": { + "message": "Increases D max, the maximum amount that D can increase to during faster movements.

For race quads, where the main Damping slider has been set low to minimize motor heat, moving this slider to the right will improve overshoot control for quick direction changes.

For HD or cinematic quads, instability in forward flight is best addressed by moving the Damping slider (not the Damping Boost slider) to the right. Always check for motor heat and listen for weird noises during quick inputs when adjusting this slider to the right.

For freestyle quads, especially heavier builds, moving this slider to the right may help control overshoot in flips and rolls.

Note:
Generally overshoot in flips and rolls is due to not enough 'i-Term Relax', or motor desyncs, or inadequate authority (a.k.a. Motor Saturation). If you find that moving the Damping Boost slider to the right doesn't improve flip or roll overshoot, put it back to the normal position, and seek out the reason for the overshoot or wobble.", + "description": "D_min slider helpicon message" + }, + "pidTuningRollPitchRatioSlider": { + "message": "Pitch Damping:
Pitch:Roll D", + "description": "Pitch-Roll Ratio slider label" + }, + "pidTuningRollPitchRatioSliderHelp": { + "message": "Increases Damping (D) on the Pitch axis ONLY, i.e, for Pitch relative to Roll. Helps control Pitch specific overshooting or bounce-back.

Quads with 'heavier' moment of inertia on the Pitch axis generally need more Damping authority (since Pitch has more inertia and accumulates more momentum).

Tune the master 'Damping' and/or 'Tracking' sliders first, until you get good Roll axis behavior. Then use the Pitch sliders (increase or decrease) to fine tune the Pitch axis without affecting Roll.", + "description": "Pitch-Roll Ratio tuning slider helpicon message" + }, + "pidTuningPitchPIGainSlider": { + "message": "Pitch Tracking:
Pitch:Roll P & I", + "description": "Pitch P & I slider label" + }, + "pidTuningPitchPIGainSliderHelp": { + "message": "Increases the Tracking strength on the Pitch axis ONLY, by changing Pitch P and I values relative to Roll. Allows stronger tracking authority on the Pitch axis relative to Roll.

Increase to stabilise pitch (nose) bobble with sharp pitch inputs or throttle chops. Also consider raising Anti-Gravity gains.

Tune the master 'Damping' and/or 'Tracking' sliders first, until you get good Roll axis behaviour. Then use the Pitch sliders (increase or decrease) to fine tune the Pitch axis without affecting Roll.", + "description": "Pitch P & I Gain tuning slider helpicon message" + }, "pidTuningGyroLowpassFiltersGroup": { "message": "Gyro Lowpass Filters" }, @@ -3722,8 +3768,11 @@ "pidTuningGyroLowpass2Type": { "message": "Gyro Lowpass 2 Filter Type" }, - "pidTuningLowpassFilterHelp": { - "message": "The Lowpass Filters can have two variants: static and dynamic. For a determined lowpass filter number only one (static or dynamic) can be enabled at the same time. The static only has a Cutoff that is a value that defines in some way where the filter starts. The dynamic defines a min and max values, that is the range where the Cutoff is placed. This Cutoff moves from min to max at the same time than you move the throttle stick." + "pidTuningGyroLowpassFilterHelp": { + "message": "Gyro lowpass filters attenuate higher frequency noise to keep it out of the PID loop. There are two independently configurable gyro filters; by default both are active.

The first D lowpass can be static (fixed cutoff) or dynamic; the second D lowpass is always static. When a lowpass is in dynamic mode, filter will be stronger at low throttle, and the cutoff will go higher (less filtering) as throttle increases.

Without RPM filtering, both PT1 filters should be enabled at default (or stronger) cutoffs, with lowpass 1 in dynamic mode.

With RPM filtering, the gyro filter slider can often be moved some way to the right. On clean quads it can go all the way right, or alternatively a single static gyro lowpass filter at 500hz may be sufficient.

A quad will have less propwash with the least gyro filter delay (sliders to the right, higher cutoff values).

Always check for motor heat when shifting to less gyro filtering (sliders to the right). With minimal gyro filtering, it is essential to have enough D filtering! Take care!" + }, + "pidTuningDTermLowpassFilterHelp": { + "message": "D-term lowpass filters attenuate higher frequency noise and resonances that would otherwise be amplified by D gain.

There are two D filters, and their effects are additive. By default, both are active and the filter type is PT1. Both are required in nearly all quads, though a single PT2 may be used in place of dual PT1's.

The first D lowpass can be static (fixed frequency) or dynamic; the second D lowpass is always static. When a lowpass is in dynamic mode, filtering will be stronger (lower cutoff frequency) at low throttle, and the cutoff will go higher (less filtering and less delay) as throttle increases.

Dynamic lowpass filtering is useful to provide strong D filtering at idle, where there is a risk of 'motor grinding' or unexpected flyways on arming, while giving less delay once in the air, for better propwash performance.

The transition from low to high cutoff will happen earlier, as throttle is increased, with higher D-term lowpass expo values. D lowpass expo can be used to fine-tune the amount of D filtering at different throttle points.

Generally, the quad will fly best and have least propwash with the lowest filter delay (sliders to the right, higher cutoff values), BUT, particularly with D filters, this will greatly increase the chance of getting hot motors.

It is very easy to burn motors if you don't have enough D filtering. Take care!" }, "pidTuningGyroNotchFiltersGroup": { "message": "Gyro Notch Filters" @@ -3933,7 +3982,7 @@ "description": "Cutoff value of the I Term Relax" }, "pidTuningItermRelaxCutoffHelp": { - "message": "Lower values suppress bounce-back after flips in low authority quads, high values increase high-rate turn precision for racing.
Set to 30-40 for racing, 15 for responsive freestyle builds, 10 for heavier freestyle quads, 3-5 for X-class." + "message": "Lower values suppress bounce-back after flips in low authority quads, high values increase high-rate turn precision for racing.
Set to 30-40 for racing, 15 for responsive freestyle builds, 10 for heavier freestyle quads, 3-5 for X-class." }, "pidTuningAbsoluteControlGain": { "message": "Absolute Control" @@ -4186,7 +4235,7 @@ "message": "To calibrate, use a multimeter to measure the actual voltage / current draw on your craft (with a battery plugged in), and enter the values below. Then, with the same battery still plugged in, click [Calibrate]." }, "powerCalibrationManagerNote": { - "message": "Note: Before calibrating the scale make sure that divider and multiplier for voltage and offset for amperage is set properly.
Leaving the values at 0 will not apply calibration.
Remember to remove propellers before plugging in a battery!" + "message": "Note: Before calibrating the scale make sure that divider and multiplier for voltage and offset for amperage is set properly.
Leaving the values at 0 will not apply calibration.
Remember to remove propellers before plugging in a battery!" }, "powerCalibrationManagerWarning": { "message": "Warning: The battery is not plugged in or voltage and amperage meter sources are not set properly. Make sure that the voltage and/or amperage are reading a value above 0. Otherwise you will not be able to calibrate using this tool." @@ -4207,7 +4256,7 @@ "message": "Discard Calibration" }, "powerCalibrationConfirmHelp": { - "message": "New calibrated scales are shown here.
Applying them will set the scales but will not save them.

After saving make sure that the new voltage and current are correct.
" + "message": "New calibrated scales are shown here.
Applying them will set the scales but will not save them.

After saving make sure that the new voltage and current are correct.
" }, "powerVoltageHead": { "message": "Voltage Meter" @@ -5087,7 +5136,7 @@ "description": "One of the elements of the OSD" }, "osdDescElementEfficiency": { - "message": "Instantaneous battery consumption in mAh/distance. (Requires valid GPS fix)" + "message": "Instantaneous battery consumption in mAh/distance. (Requires valid GPS fix)" }, "osdTextTotalFlights": { "message": "Total flights", @@ -5535,7 +5584,7 @@ }, "vtxHelp": { - "message": "Here you can configure the values for your Video Transmitter (VTX). You can view and change the transmission values, including the VTX Tables, if the flight controller and the VTX support it.
To set up your VTX use the following steps:
1. Go to this page;
2. Find the appropriate VTX configuration file for your country and your VTX model and download it;
3. Click '$t(vtxButtonLoadFile.message)' below, select the VTX configuration file, load it;
4. Verify that the settings are correct;
5. Click '$t(vtxButtonSave.message)' to store the VTX settings on the flight controller.
6. Optionally click '$t(vtxButtonSaveLua.message)' to save a lua configuration file you can use with the betaflight lua scripts (See more here.)", + "message": "Here you can configure the values for your Video Transmitter (VTX). You can view and change the transmission values, including the VTX Tables, if the flight controller and the VTX support it.
To set up your VTX use the following steps:
1. Go to this page;
2. Find the appropriate VTX configuration file for your country and your VTX model and download it;
3. Click '$t(vtxButtonLoadFile.message)' below, select the VTX configuration file, load it;
4. Verify that the settings are correct;
5. Click '$t(vtxButtonSave.message)' to store the VTX settings on the flight controller.
6. Optionally click '$t(vtxButtonSaveLua.message)' to save a lua configuration file you can use with the betaflight lua scripts (See more here.)", "description": "Introduction message in the VTX tab" }, "vtxMessageNotSupported": { @@ -5703,7 +5752,7 @@ "description": "Help for the number of power levels field of the VTX Table element in the VTX tab" }, "vtxTablePowerLevelsTableHelp": { - "message": "This table represents the different values of power that can be used for the VTX. They are divided into two:
- $t(vtxTablePowerLevelsValue.message): each power level requires a value that is defined by the hardware manufacturer. Ask your manufacturer for the correct value or consult the Betaflight wiki of VTX Tables to grab some samples.
- $t(vtxTablePowerLevelsLabel.message): you can put here the label you want for each power level value. It can be numbers (25, 200, 600, 1.2), letters (OFF, MIN, MAX) or a mix of them.

You must configure only the power levels that are legal at your country.", + "message": "This table represents the different values of power that can be used for the VTX. They are divided into two:
- $t(vtxTablePowerLevelsValue.message): each power level requires a value that is defined by the hardware manufacturer. Ask your manufacturer for the correct value or consult the Betaflight wiki of VTX Tables to grab some samples.
- $t(vtxTablePowerLevelsLabel.message): you can put here the label you want for each power level value. It can be numbers (25, 200, 600, 1.2), letters (OFF, MIN, MAX) or a mix of them.

You must configure only the power levels that are legal at your country.", "description": "Help for the table of power levels (value-label) that appears in the VTX tab" }, "vtxTablePowerLevelsValue": { @@ -5739,7 +5788,7 @@ "description": "Text of one of the titles of the VTX Table element in the VTX tab" }, "vtxTableBandsChannelsTableHelp": { - "message": "This table represents all the frequencies that can be used for your VTX. You can have several bands and for each band you must configure:
- $t(vtxTableBandTitleName.message): Name that you want to assign to this band, like BOSCAM_A, FATSHARK or RACEBAND.
- $t(vtxTableBandTitleLetter.message): Short letter that references the band.
- $t(vtxTableBandTitleFactory.message): This indicates if it is a factory band. If enabled Betaflight sends to the VTX a band and channel number. The VTX will then use its built-in frequency table and the frequencies configured here are only to show the value in the OSD and other places. If it is not enabled, then Betaflight will send to the VTX the real frequency configured here.
- Frequencies: Frequencies for this band.

Remember that not all frequencies are legal at your country. You must put a value of zero to each frequency index that you are not allowed to use to disable it.", + "message": "This table represents all the frequencies that can be used for your VTX. You can have several bands and for each band you must configure:
- $t(vtxTableBandTitleName.message): Name that you want to assign to this band, like BOSCAM_A, FATSHARK or RACEBAND.
- $t(vtxTableBandTitleLetter.message): Short letter that references the band.
- $t(vtxTableBandTitleFactory.message): This indicates if it is a factory band. If enabled Betaflight sends to the VTX a band and channel number. The VTX will then use its built-in frequency table and the frequencies configured here are only to show the value in the OSD and other places. If it is not enabled, then Betaflight will send to the VTX the real frequency configured here.
- Frequencies: Frequencies for this band.

Remember that not all frequencies are legal at your country. You must put a value of zero to each frequency index that you are not allowed to use to disable it.", "description": "Help for the table of bands-channels that appears in the VTX tab" }, @@ -5776,7 +5825,7 @@ "description": "Save Lua script button in the VTX tab" }, "vtxLuaFileHelp" :{ - "message": "The '$t(vtxButtonSaveLua.message)' button will allow you to save a mcuid.lua file containing the VTX table configuration that can be used with the Betaflight TX Lua Scripts.

Version 1.6.0 and above can use the file as is, but for older versions of the scripts it should be renamed to match the modelname on the TX.", + "message": "The '$t(vtxButtonSaveLua.message)' button will allow you to save a mcuid.lua file containing the VTX table configuration that can be used with the Betaflight TX Lua Scripts.

Version 1.6.0 and above can use the file as is, but for older versions of the scripts it should be renamed to match the modelname on the TX.", "description": "Tooltip message for the Save Lua script button in the VTX tab" }, "vtxButtonLoadFile": { @@ -5813,10 +5862,10 @@ "message": "ESC/Motor protocol" }, "configurationEscProtocolHelp": { - "message": "Select your motor protocol.
Make sure to verify the protocol is supported by your ESC, this information should be on the makers website.
Be carefull using DSHOT900 and DSHOT1200 as not many ESC's support it!" + "message": "Select your motor protocol.
Make sure to verify the protocol is supported by your ESC, this information should be on the makers website.
Be carefull using DSHOT900 and DSHOT1200 as not many ESC's support it!" }, "configurationEscProtocolHelpNoDSHOT1200": { - "message": "Select your motor protocol.
Make sure to verify the protocol is supported by your ESC, this information should be on the makers website." + "message": "Select your motor protocol.
Make sure to verify the protocol is supported by your ESC, this information should be on the makers website." }, "configurationunsyndePwm": { "message": "Motor PWM speed Separated from PID speed" @@ -5829,7 +5878,7 @@ "description": "Feature for the ESC/Motor" }, "configurationDshotBidirHelp": { - "message": "Sends ESC data to the FC via DShot telemetry. Required by RPM Filtering and dynamic idle.

Note: Requires a compatible ESC with appropriate firmware, eg JESC, Jazzmac, BLHeli-32.", + "message": "Sends ESC data to the FC via DShot telemetry. Required by RPM Filtering and dynamic idle.

Note: Requires a compatible ESC with appropriate firmware, eg JESC, Jazzmac, BLHeli-32.", "description": "Description of the Bidirectional DShot feature of the ESC/Motor" }, "configurationGyroSyncDenom": { @@ -5930,10 +5979,10 @@ "message": "Derivative from Error provides more direct stick response and is mostly prefered for Racing.

Derivative from Measurement provides smoother stick response what is more usefull for freestyling" }, "pidTuningPidControllerTip": { - "message": "Legacy vs Betaflight (float): PID scaling and PID logic is exactly the same. Not necessarily retune needed. Legacy is old betaflight evolved rewrite, which is basic PID controller based on integer math. Betaflight PID controller uses floating point math and has many new features specifically designed for multirotor applications
Float vs Integer: PID scaling and PID logic is exactly the same. No retune needed. F1 boards have no onboard FPU and floating point math increases CPU load and integer math will improve performance, but float math might gain slightly more precision." + "message": "Legacy vs Betaflight (float): PID scaling and PID logic is exactly the same. Not necessarily retune needed. Legacy is old betaflight evolved rewrite, which is basic PID controller based on integer math. Betaflight PID controller uses floating point math and has many new features specifically designed for multirotor applications
Float vs Integer: PID scaling and PID logic is exactly the same. No retune needed. F1 boards have no onboard FPU and floating point math increases CPU load and integer math will improve performance, but float math might gain slightly more precision." }, "pidTuningFilterTip": { - "message": "Gyro Soft Filter: Lowpass filter for gyro. Use lower value for more filtering.
D Term Filter: Lowpass filter for Dterm. Can affect D tuning. Use lower value for more filtering.
Yaw Filter: Filters yaw output. It can help on setups with noisy yaw axis." + "message": "Gyro Soft Filter: Lowpass filter for gyro. Use lower value for more filtering.
D Term Filter: Lowpass filter for Dterm. Can affect D tuning. Use lower value for more filtering.
Yaw Filter: Filters yaw output. It can help on setups with noisy yaw axis." }, "pidTuningRatesTip": { "message": "Play with the rates and see how those affect the stick curve" diff --git a/src/css/tabs/pid_tuning.css b/src/css/tabs/pid_tuning.css index 61d80af0..cf5297ee 100644 --- a/src/css/tabs/pid_tuning.css +++ b/src/css/tabs/pid_tuning.css @@ -93,6 +93,12 @@ border-bottom: 0 solid var(--subtleAccent); } +.tab-pid_tuning .sliderDivider { + padding: 3px; + border-top: 1px solid var(--subtleAccent); + border-bottom: 1px solid var(--subtleAccent); +} + .tab-pid_tuning table th { padding: 0; border: 0; diff --git a/src/js/TuningSliders.js b/src/js/TuningSliders.js index ecc8cb0b..6687d5d1 100644 --- a/src/js/TuningSliders.js +++ b/src/js/TuningSliders.js @@ -1,14 +1,22 @@ 'use strict'; const TuningSliders = { - sliderPidsMode: 2, - sliderMasterMultiplier: 1, - sliderRollPitchRatio: 1, - sliderIGain: 1, + // Legacy Sliders + sliderMasterMultiplierLegacy: 1, sliderPDRatio: 1, sliderPDGain: 1, - sliderDMinRatio: 1, + sliderFeedforwardGainLegacy: 1, + // Firmware Sliders introduced in API 1.44 + sliderPidsMode: 2, + sliderDGain: 1, + sliderPIGain: 1, sliderFeedforwardGain: 1, + sliderDMaxGain: 1, + sliderIGain: 1, + sliderRollPitchRatio: 1, + sliderPitchPIGain: 1, + sliderMasterMultiplier: 1, + pidSlidersUnavailable: false, GyroSliderUnavailable: false, DTermSliderUnavailable: false, @@ -23,6 +31,8 @@ const TuningSliders = { defaultPDRatio: 0, PID_DEFAULT: [], FILTER_DEFAULT: {}, + SLIDER_DEFAULT: {}, + initialSettings: {}, cachedPidSliderValues: false, cachedGyroSliderValues: false, @@ -33,6 +43,60 @@ const TuningSliders = { const D_MIN_RATIO = 0.85; +TuningSliders.saveInitialSettings = function () { + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + this.initialSettings.sliderPidsMode = FC.TUNING_SLIDERS.slider_pids_mode; + this.initialSettings.sliderDGain = FC.TUNING_SLIDERS.slider_d_gain / 100; + this.initialSettings.sliderPIGain = FC.TUNING_SLIDERS.slider_pi_gain / 100; + this.initialSettings.sliderFeedforwardGain = FC.TUNING_SLIDERS.slider_feedforward_gain / 100; + this.initialSettings.sliderDMaxGain = FC.TUNING_SLIDERS.slider_dmax_gain / 100; + this.initialSettings.sliderIGain = FC.TUNING_SLIDERS.slider_i_gain / 100; + this.initialSettings.sliderRollPitchRatio = FC.TUNING_SLIDERS.slider_roll_pitch_ratio / 100; + this.initialSettings.sliderPitchPIGain = FC.TUNING_SLIDERS.slider_pitch_pi_gain / 100; + this.initialSettings.sliderMasterMultiplier = FC.TUNING_SLIDERS.slider_master_multiplier / 100; + this.initialSettings.sliderGyroFilter = FC.TUNING_SLIDERS.slider_gyro_filter; + this.initialSettings.sliderGyroFilterMultiplier = FC.TUNING_SLIDERS.slider_gyro_filter_multiplier / 100; + this.initialSettings.sliderDTermFilter = FC.TUNING_SLIDERS.slider_dterm_filter; + this.initialSettings.sliderDTermFilterMultiplier = FC.TUNING_SLIDERS.slider_dterm_filter_multiplier / 100; + } +}; + +TuningSliders.restoreInitialSettings = function () { + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + if (this.sliderModeHasChanged && this.initialSetting.sliderPidsMode !== this.sliderPidsmode) { + $('#sliderPidsModeSelect').val(this.initialSettings.sliderPidsMode).trigger('change'); + } + + FC.TUNING_SLIDERS.slider_pids_mode = this.initialSettings.sliderPidsMode; + + FC.TUNING_SLIDERS.slider_d_gain = Math.round(this.initialSettings.sliderDGain * 20) * 5; + FC.TUNING_SLIDERS.slider_pi_gain = Math.round(this.initialSettings.sliderPIGain * 20) * 5; + FC.TUNING_SLIDERS.slider_feedforward_gain = Math.round(this.initialSettings.sliderFeedforwardGain * 20) * 5; + FC.TUNING_SLIDERS.slider_dmax_gain = Math.round(this.initialSettings.sliderDMaxGain * 20) * 5; + FC.TUNING_SLIDERS.slider_i_gain = Math.round(this.initialSettings.sliderIGain * 20) * 5; + FC.TUNING_SLIDERS.slider_roll_pitch_ratio = Math.round(this.initialSettings.sliderRollPitchRatio * 20) * 5; + FC.TUNING_SLIDERS.slider_pitch_pi_gain = Math.round(this.initialSettings.sliderPitchPIGain * 20) * 5; + FC.TUNING_SLIDERS.slider_master_multiplier = Math.round(this.initialSettings.sliderMasterMultiplier * 20) * 5; + + FC.TUNING_SLIDERS.slider_gyro_filter = this.initialSettings.sliderGyroFilter; + FC.TUNING_SLIDERS.slider_gyro_filter_multiplier = this.initialSettings.sliderGyroFilterMultiplier * 100; + FC.TUNING_SLIDERS.slider_dterm_filter = this.initialSettings.sliderDTermFilter; + FC.TUNING_SLIDERS.slider_dterm_filter_multiplier = this.initialSettings.sliderDTermFilterMultiplier * 100; + + MSP.promise(MSPCodes.MSP_SET_TUNING_SLIDERS, mspHelper.crunch(MSPCodes.MSP_SET_TUNING_SLIDERS)) + .then(() => MSP.promise(MSPCodes.MSP_PID)) + .then(() => MSP.promise(MSPCodes.MSP_PID_ADVANCED)) + .then(() => MSP.promise(MSPCodes.MSP_FILTER_CONFIG)) + .then(() => { + TABS.pid_tuning.configChanges = {}; + if (GUI.active_tab === 'pid_tuning') { + this.updateFormPids(); + TABS.pid_tuning.updatePIDColors(); + } + }); + } +}; + TuningSliders.setDMinFeatureEnabled = function(dMinFeatureEnabled) { this.dMinFeatureEnabled = dMinFeatureEnabled; if (this.dMinFeatureEnabled) { @@ -45,6 +109,7 @@ TuningSliders.setDMinFeatureEnabled = function(dMinFeatureEnabled) { TuningSliders.initialize = function() { this.PID_DEFAULT = FC.getPidDefaults(); this.FILTER_DEFAULT = FC.getFilterDefaults(); + this.SLIDER_DEFAULT = FC.getSliderDefaults(); if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { this.setDMinFeatureEnabled($('#dMinSwitch').is(':checked')); @@ -67,20 +132,27 @@ TuningSliders.initialize = function() { TuningSliders.setExpertMode = function() { this.expertMode = isExpertModeEnabled(); + $('#slidersPidsBox, #slidersFilterBox').toggleClass('nonExpertModeSliders', !this.expertMode); if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - const dMinShow = parseInt($('.pid_tuning input[name="dMinRoll"]').val()) !== 0; - $('.tab-pid_tuning .MasterSlider').toggle(this.expertMode); - $('.tab-pid_tuning .DMinRatioSlider').toggle(this.expertMode && dMinShow); + // TODO: reset nonExpertModeSliders - changes after first movement + + $('.tab-pid_tuning .DMaxGainSlider').toggle(this.expertMode); $('.tab-pid_tuning .advancedSlider').toggle(this.expertMode); + $('.tab-pid_tuning .masterSlider').toggle(this.expertMode); + $('.tab-pid_tuning .legacySlider').hide(); + $('.subtab-pid .nonExpertModeSlidersNote').toggle(!this.pidSlidersUnavailable && !this.expertMode); + $('.subtab-filter .nonExpertModeSlidersNote').toggle((!this.GyroSliderUnavailable || !this.DTermSliderUnavailable) && !this.expertMode); } else { - $('#slidersPidsBox, #slidersFilterBox').toggleClass('nonExpertModeSliders', !this.expertMode); + const dMinShow = parseInt($('.pid_tuning input[name="dMinRoll"]').val()) !== 0; + $('.tab-pid_tuning .DMaxGainSlider').toggle(this.expertMode && dMinShow); $('.tab-pid_tuning .advancedSlider').hide(); - $('.tab-pid_tuning .DMinRatioSlider').hide(); + $('.tab-pid_tuning .DMaxGainSlider').hide(); + $('.tab-pid_tuning .baseSlider').hide(); } }; TuningSliders.scaleSliderValue = function(value) { - if (value > 1) { + if (value > 0) { return Math.round(((value - 1) * 2 + 1) * 100) / 100; } else { return value; @@ -88,7 +160,7 @@ TuningSliders.scaleSliderValue = function(value) { }; TuningSliders.downscaleSliderValue = function(value) { - if (value > 1) { + if (value > 0) { return (value - 1) / 2 + 1; } else { return value; @@ -96,43 +168,56 @@ TuningSliders.downscaleSliderValue = function(value) { }; TuningSliders.initPidSlidersPosition = function() { - if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + this.sliderPidsMode = FC.TUNING_SLIDERS.slider_pids_mode; + this.sliderDGain = FC.TUNING_SLIDERS.slider_d_gain / 100; + this.sliderPIGain = FC.TUNING_SLIDERS.slider_pi_gain / 100; + this.sliderFeedforwardGain = FC.TUNING_SLIDERS.slider_feedforward_gain / 100; + this.sliderDMaxGain = FC.TUNING_SLIDERS.slider_dmax_gain / 100; + this.sliderIGain = FC.TUNING_SLIDERS.slider_i_gain / 100; + this.sliderRollPitchRatio = FC.TUNING_SLIDERS.slider_roll_pitch_ratio / 100; + this.sliderPitchPIGain = FC.TUNING_SLIDERS.slider_pitch_pi_gain / 100; + this.sliderMasterMultiplier = FC.TUNING_SLIDERS.slider_master_multiplier / 100; + + $('output[name="sliderDGain-number"]').val(this.sliderDGain); + $('output[name="sliderPIGain-number"]').val(this.sliderPIGain); + $('output[name="sliderFeedforwardGain-number"]').val(this.sliderFeedforwardGain); + $('output[name="sliderDMaxGain-number"]').val(this.sliderDMaxGain); + $('output[name="sliderIGain-number"]').val(this.sliderIGain); + $('output[name="sliderRollPitchRatio-number"]').val(this.sliderRollPitchRatio); + $('output[name="sliderPitchPIGain-number"]').val(this.sliderPitchPIGain); + $('output[name="sliderMasterMultiplier-number"]').val(this.sliderMasterMultiplier); + + $('#sliderDGain').val(this.downscaleSliderValue(this.sliderDGain)); + $('#sliderPIGain').val(this.downscaleSliderValue(this.sliderPIGain)); + $('#sliderFeedforwardGain').val(this.sliderFeedforwardGain); + $('#sliderDMaxGain').val(this.sliderDMaxGain); + $('#sliderIGain').val(this.downscaleSliderValue(this.sliderIGain)); + $('#sliderRollPitchRatio').val(this.downscaleSliderValue(this.sliderRollPitchRatio)); + $('#sliderPitchPIGain').val(this.downscaleSliderValue(this.sliderPitchPIGain)); + $('#sliderMasterMultiplier').val(this.downscaleSliderValue(this.sliderMasterMultiplier)); + } else { // 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.sliderMasterMultiplier = Math.round(FC.PIDS[2][1] / this.PID_DEFAULT[11] * 10) / 10; + this.sliderMasterMultiplierLegacy = Math.round(FC.PIDS[2][1] / this.PID_DEFAULT[11] * 10) / 10; this.sliderPDRatio = Math.round(FC.PIDS[0][2] / FC.PIDS[0][0] / this.defaultPDRatio * 10) / 10; if (this.dMinFeatureEnabled) { - this.sliderPDGain = Math.round(FC.ADVANCED_TUNING.dMinRoll / this.sliderPDRatio / this.sliderMasterMultiplier / this.PID_DEFAULT[3] * 10) / 10; + this.sliderPDGain = Math.round(FC.ADVANCED_TUNING.dMinRoll / this.sliderPDRatio / this.sliderMasterMultiplierLegacy / this.PID_DEFAULT[3] * 10) / 10; } else { - this.sliderPDGain = Math.round(FC.PIDS[0][0] / this.sliderMasterMultiplier / (this.PID_DEFAULT[2] * (1 / D_MIN_RATIO)) * 10) / 10; + this.sliderPDGain = Math.round(FC.PIDS[0][0] / this.sliderMasterMultiplierLegacy / (this.PID_DEFAULT[2] * (1 / D_MIN_RATIO)) * 10) / 10; } - this.sliderFeedforwardGain = Math.round(FC.ADVANCED_TUNING.feedforwardRoll / this.sliderMasterMultiplier / this.PID_DEFAULT[4] * 10) / 10; - } else { - this.sliderPidsMode = FC.TUNING_SLIDERS.slider_pids_mode; - this.sliderMasterMultiplier = FC.TUNING_SLIDERS.slider_master_multiplier / 100; - this.sliderRollPitchRatio = FC.TUNING_SLIDERS.slider_roll_pitch_ratio / 100; - this.sliderIGain = FC.TUNING_SLIDERS.slider_i_gain / 100; - this.sliderPDRatio = FC.TUNING_SLIDERS.slider_pd_ratio / 100; - this.sliderPDGain = FC.TUNING_SLIDERS.slider_pd_gain / 100; - this.sliderDMinRatio = FC.TUNING_SLIDERS.slider_dmin_ratio / 100; - this.sliderFeedforwardGain = FC.TUNING_SLIDERS.slider_feedforward_gain / 100; + this.sliderFeedforwardGainLegacy = Math.round(FC.ADVANCED_TUNING.feedforwardRoll / this.sliderMasterMultiplierLegacy / this.PID_DEFAULT[4] * 10) / 10; + + $('output[name="sliderMasterMultiplierLegacy-number"]').val(this.sliderMasterMultiplierLegacy); + $('output[name="sliderPDRatio-number"]').val(this.sliderPDRatio); + $('output[name="sliderPDGain-number"]').val(this.sliderPDGain); + $('output[name="sliderFeedforwardGainLegacy-number"]').val(this.sliderFeedforwardGainLegacy); + + $('#sliderMasterMultiplierLegacy').val(this.downscaleSliderValue(this.sliderMasterMultiplierLegacy)); + $('#sliderPDRatio').val(this.downscaleSliderValue(this.sliderPDRatio)); + $('#sliderPDGain').val(this.downscaleSliderValue(this.sliderPDGain)); + $('#sliderFeedforwardGainLegacy').val(this.downscaleSliderValue(this.sliderFeedforwardGainLegacy)); } - - $('output[name="sliderMasterMultiplier-number"]').val(this.sliderMasterMultiplier); - $('output[name="sliderRollPitchRatio-number"]').val(this.sliderRollPitchRatio); - $('output[name="sliderIGain-number"]').val(this.sliderIGain); - $('output[name="sliderPDRatio-number"]').val(this.sliderPDRatio); - $('output[name="sliderPDGain-number"]').val(this.sliderPDGain); - $('output[name="sliderDMinRatio-number"]').val(this.sliderDMinRatio); - $('output[name="sliderFeedforwardGain-number"]').val(this.sliderFeedforwardGain); - - $('#sliderMasterMultiplier').val(this.downscaleSliderValue(this.sliderMasterMultiplier)); - $('#sliderRollPitchRatio').val(this.downscaleSliderValue(this.sliderRollPitchRatio)); - $('#sliderIGain').val(this.downscaleSliderValue(this.sliderIGain)); - $('#sliderPDRatio').val(this.downscaleSliderValue(this.sliderPDRatio)); - $('#sliderPDGain').val(this.downscaleSliderValue(this.sliderPDGain)); - $('#sliderDMinRatio').val(this.downscaleSliderValue(this.sliderDMinRatio)); - $('#sliderFeedforwardGain').val(this.downscaleSliderValue(this.sliderFeedforwardGain)); }; TuningSliders.initGyroFilterSliderPosition = function() { @@ -158,30 +243,57 @@ TuningSliders.initDTermFilterSliderPosition = function() { } $('output[name="sliderDTermFilterMultiplier-number"]').val(this.sliderDTermFilterMultiplier); - $('#sliderDTermFilterMultiplier').val(this.downscaleSliderValue(this.sliderDTermFilterMultiplier)); + $('#sliderDTermFilterMultiplier').val(this.sliderDTermFilterMultiplier); +}; + +TuningSliders.resetDefault = function() { + FC.TUNING_SLIDERS.slider_pids_mode = this.SLIDER_DEFAULT.slider_pids_mode; + FC.TUNING_SLIDERS.slider_d_gain = this.SLIDER_DEFAULT.slider_d_gain; + FC.TUNING_SLIDERS.slider_pi_gain = this.SLIDER_DEFAULT.slider_pi_gain; + FC.TUNING_SLIDERS.slider_feedforward_gain = this.SLIDER_DEFAULT.slider_feedforward_gain; + FC.TUNING_SLIDERS.slider_dmax_gain = this.SLIDER_DEFAULT.slider_dmax_gain; + FC.TUNING_SLIDERS.slider_i_gain = this.SLIDER_DEFAULT.slider_i_gain; + FC.TUNING_SLIDERS.slider_roll_pitch_ratio = this.SLIDER_DEFAULT.slider_roll_pitch_ratio; + FC.TUNING_SLIDERS.slider_pitch_pi_gain = this.SLIDER_DEFAULT.slider_pitch_pi_gain; + FC.TUNING_SLIDERS.slider_master_multiplier = this.SLIDER_DEFAULT.slider_master_multiplier; + + FC.TUNING_SLIDERS.slider_gyro_filter = this.SLIDER_DEFAULT.slider_gyro_filter; + FC.TUNING_SLIDERS.slider_gyro_filter_multiplier = this.SLIDER_DEFAULT.slider_gyro_filter_multiplier; + FC.TUNING_SLIDERS.slider_dterm_filter = this.SLIDER_DEFAULT.slider_dterm_filter; + FC.TUNING_SLIDERS.slider_dterm_filter_multiplier = this.SLIDER_DEFAULT.slider_dterm_filter_multiplier; }; TuningSliders.resetPidSliders = function() { if (!this.cachedPidSliderValues) { - this.sliderMasterMultiplier = 1; - this.sliderRollPitchRatio = 1; - this.sliderIGain = 1; - this.sliderPDRatio = 1; - this.sliderPDGain = 1; - this.sliderDMinRatio = 1; - this.sliderFeedforwardGain = 1; + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + this.sliderDGain = this.SLIDER_DEFAULT.slider_d_gain / 100; + this.sliderPIGain = this.SLIDER_DEFAULT.slider_pi_gain / 100; + this.sliderFeedforwardGain = this.SLIDER_DEFAULT.slider_feedforward_gain / 100; + this.sliderDMaxGain = this.SLIDER_DEFAULT.slider_dmax_gain / 100; + this.sliderIGain = this.SLIDER_DEFAULT.slider_i_gain / 100; + this.sliderRollPitchRatio = this.SLIDER_DEFAULT.slider_roll_pitch_ratio / 100; + this.sliderPitchPIGain = this.SLIDER_DEFAULT.slider_pitch_pi_gain / 100; + this.sliderMasterMultiplier = this.SLIDER_DEFAULT.slider_master_multiplier / 100; + } else { + this.sliderMasterMultiplierLegacy = 1; + this.sliderPDRatio = 1; + this.sliderPDGain = 1; + this.sliderFeedforwardGainLegacy = 1; + } } - if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - $('#sliderMasterMultiplier').val(this.downscaleSliderValue(this.sliderMasterMultiplier)); + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + this.calculateNewPids(); + this.updateFormPids(); + this.initPidSlidersPosition(); + this.updatePidSlidersDisplay(); + } else { + $('#sliderMasterMultiplierLegacy').val(this.downscaleSliderValue(this.sliderMasterMultiplierLegacy)); $('#sliderPDRatio').val(this.downscaleSliderValue(this.sliderPDRatio)); $('#sliderPDGain').val(this.downscaleSliderValue(this.sliderPDGain)); - $('#sliderFeedforwardGain').val(this.downscaleSliderValue(this.sliderFeedforwardGain)); - } else { - this.initPidSlidersPosition(); + $('#sliderFeedforwardGainLegacy').val(this.downscaleSliderValue(this.sliderFeedforwardGainLegacy)); + this.calculateNewPids(); } - - this.calculateNewPids(); }; TuningSliders.resetGyroFilterSlider = function() { @@ -252,24 +364,57 @@ TuningSliders.legacyUpdateFilterSlidersDisplay = function() { } }; +TuningSliders.updateSwitchBoxes = function() { + const FF_SWITCH = FC.ADVANCED_TUNING.feedforwardRoll || FC.ADVANCED_TUNING.feedforwardPitch || FC.ADVANCED_TUNING.feedforwardYaw; + $('input[id="feedforwardGroup"]').prop('checked', FF_SWITCH).trigger('change'); + + const DMIN_SWITCH = FC.PIDS[0][2] !== FC.ADVANCED_TUNING.dMinRoll || FC.PIDS[1][2] !== FC.ADVANCED_TUNING.dMinPitch || FC.PIDS[2][2] !== FC.ADVANCED_TUNING.dMinYaw; + $('#dMinSwitch').prop('checked', DMIN_SWITCH).trigger('change'); +}; + +TuningSliders.updateSlidersWarning = function(slidersUnavailable = false) { + const WARNING_P_GAIN = 70; + let WARNING_I_GAIN = 120; + const WARNING_DMAX_GAIN = 60; + const WARNING_DMIN_GAIN = 40; + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + WARNING_I_GAIN = 2.5 * FC.PIDS[1][0]; + } + $('.subtab-pid .slidersWarning').toggle((FC.PIDS[1][0] > WARNING_P_GAIN || FC.PIDS[1][1] > WARNING_I_GAIN || FC.PIDS[1][2] > WARNING_DMAX_GAIN || + FC.ADVANCED_TUNING.dMinPitch > WARNING_DMIN_GAIN) && !slidersUnavailable); +}; + +TuningSliders.updateFilterSlidersWarning = function(gyroSliderUnavailable = false, DTermSliderUnavailable = false) { + const WARNING_FILTER_LOW_GAIN = 0.7; + let WARNING_FILTER_GYRO_HIGH_GAIN = 1.4; + let WARNING_FILTER_DTERM_HIGH_GAIN = 1.4; + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + WARNING_FILTER_GYRO_HIGH_GAIN = 1.5; + WARNING_FILTER_DTERM_HIGH_GAIN = 1.1; + } + $('.subtab-filter .slidersWarning').toggle(((this.sliderGyroFilterMultiplier >= WARNING_FILTER_GYRO_HIGH_GAIN || + this.sliderGyroFilterMultiplier <= WARNING_FILTER_LOW_GAIN) && !gyroSliderUnavailable) || + ((this.sliderDTermFilterMultiplier >= WARNING_FILTER_DTERM_HIGH_GAIN || + this.sliderDTermFilterMultiplier <= WARNING_FILTER_LOW_GAIN) && !DTermSliderUnavailable)); +}; + + TuningSliders.updatePidSlidersDisplay = function() { // check if pid values changed manually by comparing the current values with those calculated by the sliders, // if all of them are equal the values haven't been changed manually - const WARNING_P_GAIN = 70; - const WARNING_I_GAIN = 120; - const WARNING_DMAX_GAIN = 60; - const WARNING_DMIN_GAIN = 40; - this.pidSlidersUnavailable = false; - if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + let rows = 3; + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + rows = FC.TUNING_SLIDERS.slider_pids_mode === 1 ? 2 : 3; + } else { this.calculateNewPids(true); } FC.PID_NAMES.forEach(function (elementPid, indexPid) { const pidElements = $(`.pid_tuning .${elementPid} input`); pidElements.each(function (indexInput) { - if (indexPid < 3 && indexInput < 3) { + if (indexPid < rows && indexInput < rows) { if (parseInt($(this).val()) !== FC.PIDS[indexPid][indexInput]) { TuningSliders.pidSlidersUnavailable = true; } @@ -281,7 +426,7 @@ TuningSliders.updatePidSlidersDisplay = function() { this.pidSlidersUnavailable = true; } - if (!this.pidSlidersUnavailable && !semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + if (!this.pidSlidersUnavailable) { this.cachedPidSliderValues = true; } @@ -294,28 +439,22 @@ TuningSliders.updatePidSlidersDisplay = function() { $('.tuningPIDSliders').toggle(!this.pidSlidersUnavailable); $('.subtab-pid .slidersDisabled').toggle(this.pidSlidersUnavailable); - $('.subtab-pid .nonExpertModeSlidersNote').toggle(!this.pidSlidersUnavailable && !this.expertMode && !semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)); - $('.subtab-pid .slidersWarning').toggle((FC.PIDS[1][0] > WARNING_P_GAIN || FC.PIDS[1][1] > WARNING_I_GAIN || FC.PIDS[1][2] > WARNING_DMAX_GAIN || - FC.ADVANCED_TUNING.dMinPitch > WARNING_DMIN_GAIN) && !this.pidSlidersUnavailable); + $('.subtab-pid .nonExpertModeSlidersNote').toggle(!this.pidSlidersUnavailable && !this.expertMode); + + this.updateSlidersWarning(); }; TuningSliders.updateFilterSlidersDisplay = function() { - // check if filters changed manually by comapring current value and those based on slider position - const WARNING_FILTER_HIGH_GAIN = 1.4; - const WARNING_FILTER_LOW_GAIN = 0.7; - + // check if filters changed manually by comparing current value and those based on slider position this.GyroSliderUnavailable = false; this.DTermSliderUnavailable = false; if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - if (FC.TUNING_SLIDERS.slider_gyro_filter === 0) { - this.GyroSliderUnavailable = true; - } - if (FC.TUNING_SLIDERS.slider_dterm_filter === 0) { - this.DTermSliderUnavailable = true; - } + this.GyroSliderUnavailable = !FC.TUNING_SLIDERS.slider_gyro_filter; + this.DTermSliderUnavailable = !FC.TUNING_SLIDERS.slider_dterm_filter; + if (parseInt($('.pid_filter input[name="gyroLowpassDynMinFrequency"]').val()) !== - Math.round(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz * this.sliderGyroFilterMultiplier) || + Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_min_hz * this.sliderGyroFilterMultiplier) || parseInt($('.pid_filter input[name="gyroLowpassDynMaxFrequency"]').val()) !== Math.floor(this.FILTER_DEFAULT.gyro_lowpass_dyn_max_hz * this.sliderGyroFilterMultiplier) || parseInt($('.pid_filter select[name="gyroLowpassDynType"]').val()) !== this.FILTER_DEFAULT.gyro_lowpass_type || @@ -346,7 +485,6 @@ TuningSliders.updateFilterSlidersDisplay = function() { this.legacyUpdateFilterSlidersDisplay(); } - if (this.GyroSliderUnavailable) { $('.tuningFilterSliders .sliderLabels tr:nth-child(2)').hide(); } else { @@ -362,10 +500,7 @@ TuningSliders.updateFilterSlidersDisplay = function() { $('.tuningFilterSliders').toggle(!(this.GyroSliderUnavailable && this.DTermSliderUnavailable)); $('.subtab-filter .slidersDisabled').toggle(this.GyroSliderUnavailable || this.DTermSliderUnavailable); $('.subtab-filter .nonExpertModeSlidersNote').toggle((!this.GyroSliderUnavailable || !this.DTermSliderUnavailable) && !this.expertMode); - $('.subtab-filter .slidersWarning').toggle(((this.sliderGyroFilterMultiplier >= WARNING_FILTER_HIGH_GAIN || - this.sliderGyroFilterMultiplier <= WARNING_FILTER_LOW_GAIN) && !this.GyroSliderUnavailable) || - ((this.sliderDTermFilterMultiplier >= WARNING_FILTER_HIGH_GAIN || - this.sliderDTermFilterMultiplier <= WARNING_FILTER_LOW_GAIN) && !this.DTermSliderUnavailable)); + this.updateFilterSlidersWarning(this.GyroSliderUnavailable, this.DTermSliderUnavailable); }; TuningSliders.updateFormPids = function(updateSlidersOnly = false) { @@ -387,14 +522,21 @@ TuningSliders.updateFormPids = function(updateSlidersOnly = false) { $('.pid_tuning .YAW input[name="f"]').val(FC.ADVANCED_TUNING.feedforwardYaw); } - $('output[name="sliderMasterMultiplier-number"]').val(this.sliderMasterMultiplier); - $('output[name="sliderRollPitchRatio-number"]').val(this.sliderRollPitchRatio); - $('output[name="sliderIGain-number"]').val(this.sliderIGain); - $('output[name="sliderPDRatio-number"]').val(this.sliderPDRatio); - $('output[name="sliderPDGain-number"]').val(this.sliderPDGain); - $('output[name="sliderDMinRatio-number"]').val(this.sliderDMinRatio); - $('output[name="sliderFeedforwardGain-number"]').val(this.sliderFeedforwardGain); - + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + $('output[name="sliderDGain-number"]').val(this.sliderDGain); + $('output[name="sliderPIGain-number"]').val(this.sliderPIGain); + $('output[name="sliderFeedforwardGain-number"]').val(this.sliderFeedforwardGain); + $('output[name="sliderDMaxGain-number"]').val(this.sliderDMaxGain); + $('output[name="sliderIGain-number"]').val(this.sliderIGain); + $('output[name="sliderRollPitchRatio-number"]').val(this.sliderRollPitchRatio); + $('output[name="sliderPitchPIGain-number"]').val(this.sliderPitchPIGain); + $('output[name="sliderMasterMultiplier-number"]').val(this.sliderMasterMultiplier); + } else { + $('output[name="sliderMasterMultiplierLegacy-number"]').val(this.sliderMasterMultiplierLegacy); + $('output[name="sliderPDRatio-number"]').val(this.sliderPDRatio); + $('output[name="sliderPDGain-number"]').val(this.sliderPDGain); + $('output[name="sliderFeedforwardGainLegacy-number"]').val(this.sliderFeedforwardGainLegacy); + } }; TuningSliders.legacyCalculatePids = function(updateSlidersOnly = false) { @@ -421,9 +563,9 @@ TuningSliders.legacyCalculatePids = function(updateSlidersOnly = false) { FC.PIDS[1][0] = Math.round(this.PID_DEFAULT[5] * this.sliderPDGain); FC.PIDS[2][0] = Math.round(this.PID_DEFAULT[10] * this.sliderPDGain); // feedforward - FC.ADVANCED_TUNING.feedforwardRoll = Math.round(this.PID_DEFAULT[4] * this.sliderFeedforwardGain); - FC.ADVANCED_TUNING.feedforwardPitch = Math.round(this.PID_DEFAULT[9] * this.sliderFeedforwardGain); - FC.ADVANCED_TUNING.feedforwardYaw = Math.round(this.PID_DEFAULT[14] * this.sliderFeedforwardGain); + FC.ADVANCED_TUNING.feedforwardRoll = Math.round(this.PID_DEFAULT[4] * this.sliderFeedforwardGainLegacy); + FC.ADVANCED_TUNING.feedforwardPitch = Math.round(this.PID_DEFAULT[9] * this.sliderFeedforwardGainLegacy); + FC.ADVANCED_TUNING.feedforwardYaw = Math.round(this.PID_DEFAULT[14] * this.sliderFeedforwardGainLegacy); // master slider part // these are not calculated anywhere other than master slider multiplier therefore set at default before every calculation FC.PIDS[0][1] = this.PID_DEFAULT[1]; @@ -436,18 +578,18 @@ TuningSliders.legacyCalculatePids = function(updateSlidersOnly = false) { //master slider multiplication, max value 200 for main PID values for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { - FC.PIDS[j][i] = Math.min(Math.round(FC.PIDS[j][i] * this.sliderMasterMultiplier), MAX_PID_GAIN); + FC.PIDS[j][i] = Math.min(Math.round(FC.PIDS[j][i] * this.sliderMasterMultiplierLegacy), MAX_PID_GAIN); } } - FC.ADVANCED_TUNING.feedforwardRoll = Math.min(Math.round(FC.ADVANCED_TUNING.feedforwardRoll * this.sliderMasterMultiplier), MAX_FEEDFORWARD_GAIN); - FC.ADVANCED_TUNING.feedforwardPitch = Math.min(Math.round(FC.ADVANCED_TUNING.feedforwardPitch * this.sliderMasterMultiplier), MAX_FEEDFORWARD_GAIN); - FC.ADVANCED_TUNING.feedforwardYaw = Math.min(Math.round(FC.ADVANCED_TUNING.feedforwardYaw * this.sliderMasterMultiplier), MAX_FEEDFORWARD_GAIN); + FC.ADVANCED_TUNING.feedforwardRoll = Math.min(Math.round(FC.ADVANCED_TUNING.feedforwardRoll * this.sliderMasterMultiplierLegacy), MAX_FEEDFORWARD_GAIN); + FC.ADVANCED_TUNING.feedforwardPitch = Math.min(Math.round(FC.ADVANCED_TUNING.feedforwardPitch * this.sliderMasterMultiplierLegacy), MAX_FEEDFORWARD_GAIN); + FC.ADVANCED_TUNING.feedforwardYaw = Math.min(Math.round(FC.ADVANCED_TUNING.feedforwardYaw * this.sliderMasterMultiplierLegacy), MAX_FEEDFORWARD_GAIN); if (this.dMinFeatureEnabled) { - FC.ADVANCED_TUNING.dMinRoll = Math.min(Math.round(FC.ADVANCED_TUNING.dMinRoll * this.sliderMasterMultiplier), MAX_DMIN_GAIN); - FC.ADVANCED_TUNING.dMinPitch = Math.min(Math.round(FC.ADVANCED_TUNING.dMinPitch * this.sliderMasterMultiplier), MAX_DMIN_GAIN); - FC.ADVANCED_TUNING.dMinYaw = Math.min(Math.round(FC.ADVANCED_TUNING.dMinYaw * this.sliderMasterMultiplier), MAX_DMIN_GAIN); + FC.ADVANCED_TUNING.dMinRoll = Math.min(Math.round(FC.ADVANCED_TUNING.dMinRoll * this.sliderMasterMultiplierLegacy), MAX_DMIN_GAIN); + FC.ADVANCED_TUNING.dMinPitch = Math.min(Math.round(FC.ADVANCED_TUNING.dMinPitch * this.sliderMasterMultiplierLegacy), MAX_DMIN_GAIN); + FC.ADVANCED_TUNING.dMinYaw = Math.min(Math.round(FC.ADVANCED_TUNING.dMinYaw * this.sliderMasterMultiplierLegacy), MAX_DMIN_GAIN); } this.updateFormPids(updateSlidersOnly); @@ -458,28 +600,29 @@ TuningSliders.legacyCalculatePids = function(updateSlidersOnly = false) { TuningSliders.calculateNewPids = function(updateSlidersOnly = false) { // 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 (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - this.legacyCalculatePids(updateSlidersOnly); - } if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { FC.TUNING_SLIDERS.slider_pids_mode = parseInt($('#sliderPidsModeSelect').val()); //rounds slider values to nearies multiple of 5 and passes to the FW. Avoid dividing calc by (* x 100)/5 = 20 - FC.TUNING_SLIDERS.slider_master_multiplier = Math.round(this.sliderMasterMultiplier * 20) * 5; - FC.TUNING_SLIDERS.slider_roll_pitch_ratio = Math.round(this.sliderRollPitchRatio * 20) * 5; - FC.TUNING_SLIDERS.slider_i_gain = Math.round(this.sliderIGain * 20) * 5; - FC.TUNING_SLIDERS.slider_pd_ratio = Math.round(this.sliderPDRatio * 20) * 5; - FC.TUNING_SLIDERS.slider_pd_gain = Math.round(this.sliderPDGain * 20) * 5; - FC.TUNING_SLIDERS.slider_dmin_ratio = Math.round(this.sliderDMinRatio * 20) * 5; + FC.TUNING_SLIDERS.slider_d_gain = Math.round(this.sliderDGain * 20) * 5; + FC.TUNING_SLIDERS.slider_pi_gain = Math.round(this.sliderPIGain * 20) * 5; FC.TUNING_SLIDERS.slider_feedforward_gain = Math.round(this.sliderFeedforwardGain * 20) * 5; + FC.TUNING_SLIDERS.slider_dmax_gain = Math.round(this.sliderDMaxGain * 20) * 5; + FC.TUNING_SLIDERS.slider_i_gain = Math.round(this.sliderIGain * 20) * 5; + FC.TUNING_SLIDERS.slider_roll_pitch_ratio = Math.round(this.sliderRollPitchRatio * 20) * 5; + FC.TUNING_SLIDERS.slider_pitch_pi_gain = Math.round(this.sliderPitchPIGain * 20) * 5; + FC.TUNING_SLIDERS.slider_master_multiplier = Math.round(this.sliderMasterMultiplier * 20) * 5; MSP.promise(MSPCodes.MSP_SET_TUNING_SLIDERS, mspHelper.crunch(MSPCodes.MSP_SET_TUNING_SLIDERS)) .then(() => MSP.promise(MSPCodes.MSP_PID)) .then(() => MSP.promise(MSPCodes.MSP_PID_ADVANCED)) .then(() => { this.updateFormPids(updateSlidersOnly); - TABS.pid_tuning.updatePIDColors(); + this.updateSlidersWarning(); + this.updateSwitchBoxes(); }); + } else { + this.legacyCalculatePids(updateSlidersOnly); } }; @@ -533,10 +676,10 @@ TuningSliders.calculateNewDTermFilters = function() { TuningSliders.writeFilterSliders = function () { MSP.promise(MSPCodes.MSP_SET_TUNING_SLIDERS, mspHelper.crunch(MSPCodes.MSP_SET_TUNING_SLIDERS)) - .then(() => MSP.promise(MSPCodes.MSP_EEPROM_WRITE)) .then(() => MSP.promise(MSPCodes.MSP_FILTER_CONFIG)) .then(() => { TuningSliders.updateLowpassValues(); + TuningSliders.updateFilterSlidersWarning(); if (this.FilterReset) { this.FilterReset = false; this.updateFilterSlidersDisplay(); diff --git a/src/js/fc.js b/src/js/fc.js index e769dcda..42171e93 100644 --- a/src/js/fc.js +++ b/src/js/fc.js @@ -656,18 +656,39 @@ const FC = { this.VTX_DEVICE_STATUS = null; this.TUNING_SLIDERS = { - slider_pids_mode: 0, - slider_master_multiplier: 0, - slider_roll_pitch_ratio: 0, - slider_i_gain: 0, slider_pd_ratio: 0, slider_pd_gain: 0, - slider_dmin_ratio: 0, slider_feedforward_gain: 0, + slider_master_multiplier: 0, slider_dterm_filter: 0, slider_dterm_filter_multiplier: 0, slider_gyro_filter: 0, slider_gyro_filter_multiplier: 0, + // introduced in 4.3 + slider_pids_mode: 0, + slider_d_gain: 0, + slider_pi_gain: 0, + slider_dmax_gain: 0, + slider_i_gain: 0, + slider_roll_pitch_ratio: 0, + slider_pitch_pi_gain: 0, + }; + + this.DEFAULT_TUNING_SLIDERS = { + slider_pids_mode: 2, + slider_d_gain: 100, + slider_pi_gain: 100, + slider_feedforward_gain: 100, + slider_dmax_gain: 100, + slider_i_gain: 100, + slider_roll_pitch_ratio: 100, + slider_pitch_pi_gain: 100, + slider_master_multiplier: 100, + + slider_dterm_filter: 1, + slider_dterm_filter_multiplier: 100, + slider_gyro_filter: 1, + slider_gyro_filter_multiplier: 100, }; }, @@ -800,7 +821,7 @@ const FC = { getFilterDefaults() { const versionFilterDefaults = this.DEFAULT; - + // Change filter defaults depending on API version here if (semver.eq(this.CONFIG.apiVersion, API_VERSION_1_40)) { versionFilterDefaults.dterm_lowpass2_hz = 200; } else if (semver.gte(this.CONFIG.apiVersion, API_VERSION_1_41)) { @@ -829,6 +850,11 @@ const FC = { if (semver.gte(this.CONFIG.apiVersion, API_VERSION_1_44)) { versionFilterDefaults.dyn_notch_q_rpm = 500; versionFilterDefaults.dyn_notch_q = 300; + versionFilterDefaults.gyro_lowpass_hz = 250; + versionFilterDefaults.gyro_lowpass_dyn_min_hz = 250; + versionFilterDefaults.gyro_lowpass2_hz = 500; + versionFilterDefaults.dterm_lowpass_dyn_min_hz = 75; + versionFilterDefaults.dterm_lowpass_dyn_max_hz = 150; } } return versionFilterDefaults; @@ -843,7 +869,24 @@ const FC = { 46, 90, 38, 25, 95, 45, 90, 0, 0, 90, ]; + } else if (semver.gte(this.CONFIG.apiVersion, API_VERSION_1_44)) { + versionPidDefaults = [ + 45, 90, 40, 30, 120, + 47, 94, 46, 34, 125, + 45, 90, 0, 0, 120, + ]; } return versionPidDefaults; }, + + getSliderDefaults() { + const sliderDefaults = this.DEFAULT_TUNING_SLIDERS; + // change slider defaults here + if (semver.gte(this.CONFIG.apiVersion, API_VERSION_1_44)) { + sliderDefaults.slider_roll_pitch_ratio = 115; + sliderDefaults.slider_pitch_pi_gain = 105; + } + + return sliderDefaults; + }, }; diff --git a/src/js/main.js b/src/js/main.js index 7f6cb60b..483c8e27 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -251,6 +251,12 @@ function startProcess() { const tab = tabClass.substring(4); const tabName = $(self).text(); + if (GUI.active_tab === 'pid_tuning') { + if (TABS.pid_tuning.sliderPositionHasChanged || TABS.pid_tuning.sliderModeHasChanged) { + TuningSliders.restoreInitialSettings(); + } + } + if (tabRequiresConnection && !CONFIGURATOR.connectionValid) { GUI.log(i18n.getMessage('tabSwitchConnectionRequired')); return; diff --git a/src/js/msp/MSPHelper.js b/src/js/msp/MSPHelper.js index deb9126a..d9916015 100644 --- a/src/js/msp/MSPHelper.js +++ b/src/js/msp/MSPHelper.js @@ -645,8 +645,9 @@ MspHelper.prototype.process_data = function(dataHandler) { console.log('Voltage config saved'); break; case MSPCodes.MSP_DEBUG: - for (let i = 0; i < 4; i++) + for (let i = 0; i < 4; i++) { FC.SENSOR_DATA.debug[i] = data.read16(); + } break; case MSPCodes.MSP_SET_MOTOR: console.log('Motor Speeds Updated'); @@ -1491,10 +1492,11 @@ MspHelper.prototype.process_data = function(dataHandler) { FC.TUNING_SLIDERS.slider_master_multiplier = data.readU8(); FC.TUNING_SLIDERS.slider_roll_pitch_ratio = data.readU8(); FC.TUNING_SLIDERS.slider_i_gain = data.readU8(); - FC.TUNING_SLIDERS.slider_pd_ratio = data.readU8(); - FC.TUNING_SLIDERS.slider_pd_gain = data.readU8(); - FC.TUNING_SLIDERS.slider_dmin_ratio = data.readU8(); + FC.TUNING_SLIDERS.slider_d_gain = data.readU8(); + FC.TUNING_SLIDERS.slider_pi_gain = data.readU8(); + FC.TUNING_SLIDERS.slider_dmax_gain = data.readU8(); FC.TUNING_SLIDERS.slider_feedforward_gain = data.readU8(); + FC.TUNING_SLIDERS.slider_pitch_pi_gain = data.readU8(); FC.TUNING_SLIDERS.slider_dterm_filter = data.readU8(); FC.TUNING_SLIDERS.slider_dterm_filter_multiplier = data.readU8(); FC.TUNING_SLIDERS.slider_gyro_filter = data.readU8(); @@ -2313,15 +2315,15 @@ MspHelper.prototype.crunch = function(code) { .push8(FC.TUNING_SLIDERS.slider_master_multiplier) .push8(FC.TUNING_SLIDERS.slider_roll_pitch_ratio) .push8(FC.TUNING_SLIDERS.slider_i_gain) - .push8(FC.TUNING_SLIDERS.slider_pd_ratio) - .push8(FC.TUNING_SLIDERS.slider_pd_gain) - .push8(FC.TUNING_SLIDERS.slider_dmin_ratio) + .push8(FC.TUNING_SLIDERS.slider_d_gain) + .push8(FC.TUNING_SLIDERS.slider_pi_gain) + .push8(FC.TUNING_SLIDERS.slider_dmax_gain) .push8(FC.TUNING_SLIDERS.slider_feedforward_gain) + .push8(FC.TUNING_SLIDERS.slider_pitch_pi_gain) .push8(FC.TUNING_SLIDERS.slider_dterm_filter) .push8(FC.TUNING_SLIDERS.slider_dterm_filter_multiplier) .push8(FC.TUNING_SLIDERS.slider_gyro_filter) .push8(FC.TUNING_SLIDERS.slider_gyro_filter_multiplier); - break; default: diff --git a/src/js/tabs/motors.js b/src/js/tabs/motors.js index 5f938f10..3e0dfeb4 100644 --- a/src/js/tabs/motors.js +++ b/src/js/tabs/motors.js @@ -237,10 +237,6 @@ TABS.motors.initialize = function (callback) { } } - function isInt(n) { - return n % 1 === 0; - } - function setContentButtons(motorsTesting=false) { $('.btn .tool').toggleClass("disabled", self.configHasChanged || motorsTesting); $('.btn .save').toggleClass("disabled", !self.configHasChanged); diff --git a/src/js/tabs/pid_tuning.js b/src/js/tabs/pid_tuning.js index a203ed74..1b3dd88a 100644 --- a/src/js/tabs/pid_tuning.js +++ b/src/js/tabs/pid_tuning.js @@ -21,6 +21,10 @@ TABS.pid_tuning = { SETPOINT_WEIGHT_RANGE_LEGACY: 2.54, activeSubtab: 'pid', analyticsChanges: {}, + + sliderPositionHasChanged: false, + sliderChanges: {}, + sliderModeHasChanged: false, }; TABS.pid_tuning.initialize = function (callback) { @@ -80,9 +84,7 @@ TABS.pid_tuning.initialize = function (callback) { self.setRateProfile(); } - // Fill in the data from PIDs array - - // For each pid name + // Fill in the data from PIDs array for each pid name FC.PID_NAMES.forEach(function(elementPid, indexPid) { // Look into the PID table to a row with the name of the pid @@ -482,30 +484,34 @@ TABS.pid_tuning.initialize = function (callback) { } if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - // Feedforward - const feedforwardGroupCheck = $('input[id="feedforwardGroup"]'); - const PID_FEEDFORWARD = (FC.ADVANCED_TUNING.feedforwardRoll || - FC.ADVANCED_TUNING.feedforwardPitch || - FC.ADVANCED_TUNING.feedforwardYaw); + $('.resetwarning').attr("title", i18n.getMessage("pidTuningResetWarning")); + } else { + // Previous html attributes for legacy sliders + $('.pid_tuning .ROLL input[name="p"]').attr("max", "200"); + $('.pid_tuning .ROLL input[name="i"]').attr("max", "200"); + $('.pid_tuning .ROLL input[name="d"]').attr("max", "200"); + $('.pid_tuning .ROLL input[name="dMinPitch"]').attr("max", "100"); + $('.pid_tuning .PITCH input[name="p"]').attr("max", "200"); + $('.pid_tuning .PITCH input[name="i"]').attr("max", "200"); + $('.pid_tuning .PITCH input[name="d"]').attr("max", "200"); + $('.pid_tuning .PITCH input[name="dMinPitch"]').attr("max", "100"); + $('.pid_tuning .YAW input[name="p"]').attr("max", "200"); + $('.pid_tuning .YAW input[name="i"]').attr("max", "200"); + $('.pid_tuning .YAW input[name="d"]').attr("max", "200"); + $('.pid_tuning .YAW input[name="dMinPitch"]').attr("max", "1000"); + $('#sliderDTermFilterMultiplier').attr({ "min": "0.5", "max": "1.5", "step": "0.025" }); + } - feedforwardGroupCheck.prop('checked', PID_FEEDFORWARD !== 0); + // Feedforward + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + const feedforwardGroupCheck = $('input[id="feedforwardGroup"]'); + const PID_FEEDFORWARD = FC.ADVANCED_TUNING.feedforwardRoll || FC.ADVANCED_TUNING.feedforwardPitch || FC.ADVANCED_TUNING.feedforwardYaw; + feedforwardGroupCheck.prop('checked', PID_FEEDFORWARD); + $('.feedforwardGroupCheckbox').addClass('switchery-disabled'); $('select[id="feedforwardAveraging"]').val(FC.ADVANCED_TUNING.feedforward_averaging); $('input[name="feedforwardSmoothFactor"]').val(FC.ADVANCED_TUNING.feedforward_smooth_factor); $('input[name="feedforwardBoost"]').val(FC.ADVANCED_TUNING.feedforward_boost); - feedforwardGroupCheck.change(function() { - const checked = $(this).is(':checked'); - $('.feedforwardGroup .suboption').toggle(checked); - if (!checked) { - $('.pid_tuning .ROLL input[name="f"]').val(0); - $('.pid_tuning .PITCH input[name="f"]').val(0); - $('.pid_tuning .YAW input[name="f"]').val(0); - } else { - $('.pid_tuning .ROLL input[name="f"]').val(FC.ADVANCED_TUNING.feedforwardRoll > 0 ? FC.ADVANCED_TUNING.feedforwardRoll : PID_DEFAULT[4]); - $('.pid_tuning .PITCH input[name="f"]').val(FC.ADVANCED_TUNING.feedforwardPitch > 0 ? FC.ADVANCED_TUNING.feedforwardPitch : PID_DEFAULT[9]); - $('.pid_tuning .YAW input[name="f"]').val(FC.ADVANCED_TUNING.feedforwardYaw > 0 ? FC.ADVANCED_TUNING.feedforwardYaw : PID_DEFAULT[14]); - } - }).change(); // Vbat Sag Compensation const vbatSagCompensationCheck = $('input[id="vbatSagCompensation"]'); @@ -528,11 +534,21 @@ TABS.pid_tuning.initialize = function (callback) { $('.thrustLinearization .suboption').toggle(checked); }).change(); } else { - $('.feedforwardOption').hide(); + const checkbox = document.getElementById('feedforwardGroup'); + if (checkbox.parentNode) { + checkbox.parentNode.removeChild(checkbox); + } $('.vbatSagCompensation').hide(); $('.thrustLinearization').hide(); - $('.feedforwardGroupCheckbox').addClass('switchery-disabled'); - $('input[id="feedforwardGroup"]').prop('checked', true); + + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_40)) { + $('.pid_tuning .ROLL input[name="f"]').val(FC.ADVANCED_TUNING.feedforwardRoll > 0 ? FC.ADVANCED_TUNING.feedforwardRoll : PID_DEFAULT[4]); + $('.pid_tuning .PITCH input[name="f"]').val(FC.ADVANCED_TUNING.feedforwardPitch > 0 ? FC.ADVANCED_TUNING.feedforwardPitch : PID_DEFAULT[9]); + $('.pid_tuning .YAW input[name="f"]').val(FC.ADVANCED_TUNING.feedforwardYaw > 0 ? FC.ADVANCED_TUNING.feedforwardYaw : PID_DEFAULT[14]); + $('span.feedforwardOption').hide(); + } else { + $('.feedforwardGroup').hide(); + } } $('input[id="useIntegratedYaw"]').change(function() { @@ -540,16 +556,19 @@ TABS.pid_tuning.initialize = function (callback) { $('#pidTuningIntegratedYawCaution').toggle(checked); }).change(); + // if user decreases Dmax, don't allow Dmin above Dmax function adjustDMin(dElement, dMinElement) { const dValue = parseInt(dElement.val()); const dMinValue = parseInt(dMinElement.val()); - - const dMinLimit = Math.min(Math.max(dValue - 1, 0), 100); + let dMinLimit = Math.min(Math.max(dValue - 1, 0), 100); + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + dMinLimit = Math.min(Math.max(dValue, 0), 250); + } else { + dMinElement.attr("max", dMinLimit); + } if (dMinValue > dMinLimit) { dMinElement.val(dMinLimit); } - - dMinElement.attr("max", dMinLimit); } $('.pid_tuning .ROLL input[name="d"]').change(function() { @@ -567,56 +586,95 @@ TABS.pid_tuning.initialize = function (callback) { adjustDMin($(this), dMinElement); }).change(); - //dMinSwitch toggle + // if user increases Dmin, don't allow Dmax below Dmin + function adjustD(dMinElement, dElement) { + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + const dValue2 = parseInt(dElement.val()); + const dMinValue2 = parseInt(dMinElement.val()); + const dLimit = Math.min(Math.max(dMinValue2, 0), 250); + if (dValue2 < dLimit) { + dElement.val(dLimit); + } + } + } + + $('.pid_tuning input[name="dMinRoll"]').change(function() { + const dElement= $('.pid_tuning .ROLL input[name="d"]'); + adjustD($(this), dElement); + }).change(); + + $('.pid_tuning input[name="dMinPitch"]').change(function() { + const dElement= $('.pid_tuning .PITCH input[name="d"]'); + adjustD($(this), dElement); + }).change(); + + $('.pid_tuning input[name="dMinYaw"]').change(function() { + const dElement= $('.pid_tuning .YAW input[name="d"]'); + adjustD($(this), dElement); + }).change(); + + $('.pid_tuning .ROLL input[name="d"]').change(function() { + const dMinElement= $('.pid_tuning input[name="dMinRoll"]'); + adjustDMin($(this), dMinElement); + }).change(); + + $('.pid_tuning .PITCH input[name="d"]').change(function() { + const dMinElement= $('.pid_tuning input[name="dMinPitch"]'); + adjustDMin($(this), dMinElement); + }).change(); + + $('.pid_tuning .YAW input[name="d"]').change(function() { + const dMinElement= $('.pid_tuning input[name="dMinYaw"]'); + adjustDMin($(this), dMinElement); + }).change(); + + // dMinSwitch toggle - renamed to Dynamic Damping and disabled in 4.3 if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_41)) { const dMinSwitch = $('#dMinSwitch'); - dMinSwitch.prop('checked', FC.ADVANCED_TUNING.dMinRoll > 0 || FC.ADVANCED_TUNING.dMinPitch > 0 || FC.ADVANCED_TUNING.dMinYaw > 0); - dMinSwitch.change(function() { - const checked = $(this).is(':checked'); - if (checked) { - if (FC.TUNING_SLIDERS.slider_pids_mode !== 0 && semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - TuningSliders.sliderDMinRatio = 1; - $('output[name="sliderDMinRatio-number"]').val(1); - $('#sliderDMinRatio').val(1); - } - if ($('.pid_tuning input[name="dMinRoll"]').val() == 0 && $('.pid_tuning input[name="dMinPitch"]').val() == 0 && $('.pid_tuning input[name="dMinYaw"]').val() == 0) { - // when enabling dmin set its value based on 0.57x of actual dmax, dmin is limited to 100 - $('.pid_tuning input[name="dMinRoll"]').val(Math.min(Math.round($('.pid_tuning .ROLL input[name="d"]').val() * 0.57), 100)); - $('.pid_tuning input[name="dMinPitch"]').val(Math.min(Math.round($('.pid_tuning .PITCH input[name="d"]').val() * 0.57), 100)); - $('.pid_tuning input[name="dMinYaw"]').val(Math.min(Math.round($('.pid_tuning .YAW input[name="d"]').val() * 0.57), 100)); - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_43)) { - $('.pid_tuning input[name="dMinRoll"]').val(Math.min(Math.round($('.pid_tuning .ROLL input[name="d"]').val() * 0.65), 100)); - $('.pid_tuning input[name="dMinPitch"]').val(Math.min(Math.round($('.pid_tuning .PITCH input[name="d"]').val() * 0.65), 100)); - $('.pid_tuning input[name="dMinYaw"]').val(Math.min(Math.round($('.pid_tuning .YAW input[name="d"]').val() * 0.65), 100)); + + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + $('.dMinGroupCheckbox').addClass('switchery-disabled'); + $('.dMinDisabledNote').hide(); + self.updateGuiElements(); + } else { + dMinSwitch.prop('checked', FC.ADVANCED_TUNING.dMinRoll > 0 || FC.ADVANCED_TUNING.dMinPitch > 0 || FC.ADVANCED_TUNING.dMinYaw > 0); + + dMinSwitch.on('change', function() { + const checked = $(this).is(':checked'); + if (checked) { + if ($('.pid_tuning input[name="dMinRoll"]').val() == 0 && $('.pid_tuning input[name="dMinPitch"]').val() == 0 && $('.pid_tuning input[name="dMinYaw"]').val() == 0) { + // when enabling dmin set its value based on 0.57x of actual dmax, dmin is limited to 100 + $('.pid_tuning input[name="dMinRoll"]').val(Math.min(Math.round($('.pid_tuning .ROLL input[name="d"]').val() * 0.57), 100)); + $('.pid_tuning input[name="dMinPitch"]').val(Math.min(Math.round($('.pid_tuning .PITCH input[name="d"]').val() * 0.57), 100)); + $('.pid_tuning input[name="dMinYaw"]').val(Math.min(Math.round($('.pid_tuning .YAW input[name="d"]').val() * 0.57), 100)); + if (semver.eq(FC.CONFIG.apiVersion, API_VERSION_1_43)) { + $('.pid_tuning input[name="dMinRoll"]').val(Math.min(Math.round($('.pid_tuning .ROLL input[name="d"]').val() * 0.65), 100)); + $('.pid_tuning input[name="dMinPitch"]').val(Math.min(Math.round($('.pid_tuning .PITCH input[name="d"]').val() * 0.65), 100)); + $('.pid_tuning input[name="dMinYaw"]').val(Math.min(Math.round($('.pid_tuning .YAW input[name="d"]').val() * 0.65), 100)); + } + } else { + $('.pid_tuning input[name="dMinRoll"]').val(FC.ADVANCED_TUNING.dMinRoll); + $('.pid_tuning input[name="dMinPitch"]').val(FC.ADVANCED_TUNING.dMinPitch); + $('.pid_tuning input[name="dMinYaw"]').val(FC.ADVANCED_TUNING.dMinYaw); } + $('.dMinDisabledNote').hide(); + $('.dminGroup .suboption').show(); + $('#pid_main tr :nth-child(5)').show(); + $('#pid_main .pid_titlebar2 th').attr('colspan', 6); + $('.derivativeText').text(i18n.getMessage("pidTuningDMax")); } else { - $('.pid_tuning input[name="dMinRoll"]').val(FC.ADVANCED_TUNING.dMinRoll); - $('.pid_tuning input[name="dMinPitch"]').val(FC.ADVANCED_TUNING.dMinPitch); - $('.pid_tuning input[name="dMinYaw"]').val(FC.ADVANCED_TUNING.dMinYaw); + $('.dMinDisabledNote').show(); + $('.dminGroup .suboption').hide(); + $('#pid_main tr :nth-child(5)').hide(); + $('#pid_main .pid_titlebar2 th').attr('colspan', 5); + $('.derivativeText').text(i18n.getMessage("pidTuningDerivative")); + $('.pid_tuning input[name="dMinRoll"]').val(0); + $('.pid_tuning input[name="dMinPitch"]').val(0); + $('.pid_tuning input[name="dMinYaw"]').val(0); } - $('.dMinDisabledNote').hide(); - $('.dminGroup .suboption').show(); - $('#pid_main tr :nth-child(5)').show(); - $('#pid_main .pid_titlebar2 th').attr('colspan', 6); - $('.derivativeText').text(i18n.getMessage("pidTuningDMax")); - } else { - if (FC.TUNING_SLIDERS.slider_pids_mode !== 0 && semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - TuningSliders.sliderDMinRatio = 2; - } - $('.pid_tuning input[name="dMinRoll"]').val(0); - $('.pid_tuning input[name="dMinPitch"]').val(0); - $('.pid_tuning input[name="dMinYaw"]').val(0); - $('.dMinDisabledNote').show(); - $('.dminGroup .suboption').hide(); - $('#pid_main tr :nth-child(5)').hide(); - $('#pid_main .pid_titlebar2 th').attr('colspan', 5); - $('.derivativeText').text(i18n.getMessage("pidTuningDerivative")); - } - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - TuningSliders.updatePidSlidersDisplay(); - } - }); - dMinSwitch.change(); + }); + } + dMinSwitch.trigger('change'); } $('input[id="gyroNotch1Enabled"]').change(function() { @@ -1016,22 +1074,20 @@ TABS.pid_tuning.initialize = function (callback) { FC.ADVANCED_TUNING.vbat_sag_compensation = $('input[id="vbatSagCompensation"]').is(':checked') ? parseInt($('input[name="vbatSagValue"]').val()) : 0; FC.ADVANCED_TUNING.thrustLinearization = $('input[id="thrustLinearization"]').is(':checked') ? parseInt($('input[name="thrustLinearValue"]').val()) : 0; FC.FILTER_CONFIG.dyn_notch_count = parseInt($('.pid_filter input[name="dynamicNotchCount"]').val()); - } - if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - FC.TUNING_SLIDERS.slider_pids_mode = parseInt($('#sliderPidsModeSelect').val()); + FC.TUNING_SLIDERS.slider_pids_mode = TuningSliders.sliderPidsMode; //rounds slider values to nearies multiple of 5 and passes to the FW. Avoid dividing calc by (* x 100)/5 = 20 FC.TUNING_SLIDERS.slider_master_multiplier = Math.round(TuningSliders.sliderMasterMultiplier * 20) * 5; - FC.TUNING_SLIDERS.slider_roll_pitch_ratio = Math.round(TuningSliders.sliderRollPitchRatio * 20) * 5; - FC.TUNING_SLIDERS.slider_i_gain = Math.round(TuningSliders.sliderIGain * 20) * 5; - FC.TUNING_SLIDERS.slider_pd_ratio = Math.round(TuningSliders.sliderPDRatio * 20) * 5; - FC.TUNING_SLIDERS.slider_pd_gain = Math.round(TuningSliders.sliderPDGain * 20) * 5; - FC.TUNING_SLIDERS.slider_dmin_ratio = Math.round(TuningSliders.sliderDMinRatio * 20) * 5; + FC.TUNING_SLIDERS.slider_d_gain = Math.round(TuningSliders.sliderDGain * 20) * 5; + FC.TUNING_SLIDERS.slider_pi_gain = Math.round(TuningSliders.sliderPIGain * 20) * 5; FC.TUNING_SLIDERS.slider_feedforward_gain = Math.round(TuningSliders.sliderFeedforwardGain * 20) * 5; + FC.TUNING_SLIDERS.slider_i_gain = Math.round(TuningSliders.sliderIGain * 20) * 5; + FC.TUNING_SLIDERS.slider_dmax_gain = Math.round(TuningSliders.sliderDMaxGain * 20) * 5; + FC.TUNING_SLIDERS.slider_roll_pitch_ratio = Math.round(TuningSliders.sliderRollPitchRatio * 20) * 5; + FC.TUNING_SLIDERS.slider_pitch_pi_gain = Math.round(TuningSliders.sliderPitchPIGain * 20) * 5; FC.TUNING_SLIDERS.slider_dterm_filter = TuningSliders.sliderDTermFilter ? 1 : 0; FC.TUNING_SLIDERS.slider_dterm_filter_multiplier = Math.round(TuningSliders.sliderDTermFilterMultiplier * 20) * 5; - FC.TUNING_SLIDERS.slider_gyro_filter = TuningSliders.sliderGyroFilter ? 1 : 0; FC.TUNING_SLIDERS.slider_gyro_filter_multiplier = Math.round(TuningSliders.sliderGyroFilterMultiplier * 20) * 5; } @@ -1313,14 +1369,32 @@ TABS.pid_tuning.initialize = function (callback) { updatePidDisplay(); }); - $('#resetProfile').on('click', function(){ + $('#resetProfile').on('click', function() { self.updating = true; - MSP.promise(MSPCodes.MSP_SET_RESET_CURR_PID).then(function () { - self.refresh(function () { + + function refresh () { + self.refresh(() => { self.updating = false; GUI.log(i18n.getMessage('pidTuningProfileReset')); }); + } + + MSP.promise(MSPCodes.MSP_SET_RESET_CURR_PID).then(() => { + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + TuningSliders.resetDefault(); + MSP.promise(MSPCodes.MSP_SET_TUNING_SLIDERS, mspHelper.crunch(MSPCodes.MSP_SET_TUNING_SLIDERS)).then(() => { + MSP.promise(MSPCodes.MSP_EEPROM_WRITE).then(() => { + self.sliderPositionHasChanged = false; + self.sliderModeHasChanged = false; + self.sliderChanges = {}; + GUI.log(i18n.getMessage('pidTuningEepromSaved')); + refresh(); + }); + }); + } else { + refresh(); + } }); }); @@ -1398,7 +1472,6 @@ TABS.pid_tuning.initialize = function (callback) { } }); - // DTerm filter options function loadFilterTypeValues() { const filterTypeValues = []; @@ -1422,10 +1495,7 @@ TABS.pid_tuning.initialize = function (callback) { } // Added in API 1.42.0 function loadDynamicNotchRangeValues() { - const dynamicNotchRangeValues = [ - "HIGH", "MEDIUM", "LOW", "AUTO", - ]; - return dynamicNotchRangeValues; + return [ "HIGH", "MEDIUM", "LOW", "AUTO" ]; } function populateDynamicNotchRangeSelect(selectDynamicNotchRangeValues) { const dynamicNotchRangeSelect = $('select[name="dynamicNotchRange"]'); @@ -1772,12 +1842,14 @@ TABS.pid_tuning.initialize = function (callback) { const selectRateProfile = $('.selectRateProfile'); $.each(selectProfileValues, function(key, value) { - if (key != FC.CONFIG.profile) + if (key !== FC.CONFIG.profile) { selectProfile.append(new Option(value, key)); + } }); $.each(selectRateProfileValues, function(key, value) { - if (key != FC.CONFIG.rateProfile) + if (key !== FC.CONFIG.rateProfile) { selectRateProfile.append(new Option(value, key)); + } }); $('.copyprofilebtn').click(function() { @@ -1832,20 +1904,74 @@ TABS.pid_tuning.initialize = function (callback) { $('.copyrateprofilebtn').hide(); } + /* + * TuningSliders + */ + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_42)) { // filter and tuning sliders TuningSliders.initialize(); // UNSCALED non expert slider constrain values - const NON_EXPERT_SLIDER_MAX = 1.25; - const NON_EXPERT_SLIDER_MIN = 0.7; + const NON_EXPERT_SLIDER_MAX = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44) ? 1.2 : 1.25; + const NON_EXPERT_SLIDER_MIN = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44) ? 0.85 : 0.7; + const NON_EXPERT_SLIDER_MIN_FF = 0.7; + const NON_EXPERT_SLIDER_MAX_FF = 1.35; const SLIDER_STEP_LOWER = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44) ? 0.025 : 0.05; const SLIDER_STEP_UPPER = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44) ? 0.05 : 0.1; - $('#sliderPidsModeSelect').val(FC.TUNING_SLIDERS.slider_pids_mode); + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + TuningSliders.saveInitialSettings(); + const initialConfiguration = TuningSliders.initialSettings; - if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + // we only target the range target type. + function sliderHandler(e) { + if (e.target !== e.currentTarget) { + const item = e.target.id === '' ? e.target.name : e.target.id; + const value = isInt(e.target.value) ? parseInt(e.target.value) : parseFloat(e.target.value); + self.sliderChanges[item] = value; + + if (item in initialConfiguration) { + if (value !== initialConfiguration[item]) { + self.sliderPositionHasChanged = true; + } else { + delete self.sliderChanges[item]; + if (Object.keys(self.sliderChanges).length === 0) { + self.sliderPositionHasChanged = false; + } + } + } + } + e.stopPropagation(); + } + + function disableSlideronManualChange(e, angle) { + const sliderPidsModeSelectElement = $('#sliderPidsModeSelect'); + const mode = parseInt(sliderPidsModeSelectElement.val()); + if (mode > 0) { + if (mode === 1 && angle === 'YAW') { + e.preventDefault(); + } else { + sliderPidsModeSelectElement.val(0).trigger('change'); + self.sliderModeHasChanged = true; + } + } else { + self.updateGuiElements(); + } + } + + function HandleEventParams(param) { + return (e) => disableSlideronManualChange(e, param); + } + + document.querySelectorAll('.sliderLabels').forEach(elem => elem.addEventListener('change', sliderHandler)); + document.querySelectorAll('.sliderMode').forEach(elem => elem.addEventListener('change', sliderHandler)); + document.querySelectorAll('.ROLL').forEach(elem => elem.addEventListener('change', HandleEventParams('ROLL'))); + document.querySelectorAll('.PITCH').forEach(elem => elem.addEventListener('change', HandleEventParams('PITCH'))); + document.querySelectorAll('.YAW').forEach(elem => elem.addEventListener('change', HandleEventParams('YAW'))); + $('#sliderPidsModeSelect').val(FC.TUNING_SLIDERS.slider_pids_mode); + } else { $('#dMinSwitch').change(function() { TuningSliders.setDMinFeatureEnabled($(this).is(':checked')); // switch dmin and dmax values on dmin on/off if sliders available @@ -1876,76 +2002,125 @@ TABS.pid_tuning.initialize = function (callback) { } let allPidTuningSliders; - if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - allPidTuningSliders = $('#sliderMasterMultiplier, #sliderPDRatio, #sliderPDGain, #sliderFeedforwardGain'); - $('.tab-pid_tuning .advancedSlider').hide(); - $('.tab-pid_tuning .sliderMode').hide(); + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + allPidTuningSliders = $('#sliderMasterMultiplier, #sliderDGain, #sliderPIGain, #sliderFeedforwardGain, #sliderIGain, #sliderDMaxGain, #sliderRollPitchRatio, #sliderPitchPIGain'); + $('.tab-pid-tuning .legacySlider').hide(); } else { - allPidTuningSliders = $('#sliderMasterMultiplier, #sliderRollPitchRatio, #sliderIGain, #sliderPDRatio, #sliderPDGain, #sliderDMinRatio, #sliderFeedforwardGain'); - $('.tab-pid-tuning .baseSlider').show(); - $('.tab-pid-tuning .MasterSlider').show(); + allPidTuningSliders = $('#sliderMasterMultiplierLegacy, #sliderPDRatio, #sliderPDGain, #sliderFeedforwardGainLegacy'); + $('.tab-pid_tuning .advancedSlider').hide(); + $('.tab-pid-tuning .baseSlider').hide(); + $('.tab-pid_tuning .sliderMode').hide(); } - allPidTuningSliders.on('input', function() { + allPidTuningSliders.on('input mouseup', function() { const slider = $(this); - // adjust step for more smoothness above 1x - if (slider.val() >= 1) { - slider.attr('step', SLIDER_STEP_LOWER); - } else { - slider.attr('step', SLIDER_STEP_UPPER); - } - if (!TuningSliders.expertMode && semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - if (slider.val() > NON_EXPERT_SLIDER_MAX) { - slider.val(NON_EXPERT_SLIDER_MAX); - } else if (slider.val() < NON_EXPERT_SLIDER_MIN) { - slider.val(NON_EXPERT_SLIDER_MIN); + + if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + if (slider.val() >= 1) { + slider.attr('step', SLIDER_STEP_LOWER); + } else { + slider.attr('step', SLIDER_STEP_UPPER); } } - const scaledValue = TuningSliders.scaleSliderValue(slider.val()); - if (slider.is('#sliderMasterMultiplier')) { - TuningSliders.sliderMasterMultiplier = scaledValue; - } else if (slider.is('#sliderRollPitchRatio')) { - TuningSliders.sliderRollPitchRatio = scaledValue; - } else if (slider.is('#sliderIGain')) { - TuningSliders.sliderIGain = scaledValue; - } else if (slider.is('#sliderPDRatio')) { - TuningSliders.sliderPDRatio = scaledValue; - } else if (slider.is('#sliderPDGain')) { - TuningSliders.sliderPDGain = scaledValue; - } else if (slider.is('#sliderDMinRatio')) { - TuningSliders.sliderDMinRatio = scaledValue; - } else if (slider.is('#sliderFeedforwardGain')) { - TuningSliders.sliderFeedforwardGain = scaledValue; + + if (!TuningSliders.expertMode) { + if (slider.val() > NON_EXPERT_SLIDER_MAX) { + slider.val(slider.is('#sliderFeedforwardGain') ? NON_EXPERT_SLIDER_MAX_FF : NON_EXPERT_SLIDER_MAX); + } else if (slider.val() < NON_EXPERT_SLIDER_MIN) { + slider.val(slider.is('#sliderFeedforwardGain') ? NON_EXPERT_SLIDER_MIN_FF : NON_EXPERT_SLIDER_MIN); + } + } + + const sliderValue = isInt(slider.val()) ? parseInt(slider.val()) : parseFloat(slider.val()); + const scaledValue = TuningSliders.scaleSliderValue(sliderValue); + + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + if (slider.is('#sliderDGain')) { + TuningSliders.sliderDGain = scaledValue; + } else if (slider.is('#sliderPIGain')) { + TuningSliders.sliderPIGain = scaledValue; + } else if (slider.is('#sliderFeedforwardGain')) { + TuningSliders.sliderFeedforwardGain = sliderValue; + } else if (slider.is('#sliderDMaxGain')) { + TuningSliders.sliderDMaxGain = sliderValue; + } else if (slider.is('#sliderIGain')) { + TuningSliders.sliderIGain = scaledValue; + } else if (slider.is('#sliderRollPitchRatio')) { + TuningSliders.sliderRollPitchRatio = scaledValue; + } else if (slider.is('#sliderPitchPIGain')) { + TuningSliders.sliderPitchPIGain = scaledValue; + } else if (slider.is('#sliderMasterMultiplier')) { + TuningSliders.sliderMasterMultiplier = scaledValue; + } + } else { + if (slider.is('#sliderMasterMultiplierLegacy')) { + TuningSliders.sliderMasterMultiplierLegacy = sliderValue; + } else if (slider.is('#sliderPDRatio')) { + TuningSliders.sliderPDRatio = sliderValue; + } else if (slider.is('#sliderPDGain')) { + TuningSliders.sliderPDGain = sliderValue; + } else if (slider.is('#sliderFeedforwardGainLegacy')) { + TuningSliders.sliderFeedforwardGainLegacy = sliderValue; + } } TuningSliders.calculateNewPids(); self.analyticsChanges['PidTuningSliders'] = "On"; }); - allPidTuningSliders.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(); + if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + allPidTuningSliders.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(); + }); + } else { TuningSliders.updatePidSlidersDisplay(); - }); + TuningSliders.updateSlidersWarning(); + } // reset to middle with double click allPidTuningSliders.dblclick(function() { const slider = $(this); - slider.val(1); - if (slider.is('#sliderMasterMultiplier')) { - TuningSliders.sliderMasterMultiplier = 1; - } else if (slider.is('#sliderRollPitchRatio')) { - TuningSliders.sliderRollPitchRatio = 1; - } else if (slider.is('#sliderIGain')) { - TuningSliders.sliderIGain = 1; - } else if (slider.is('#sliderPDRatio')) { - TuningSliders.sliderPDRatio = 1; - } else if (slider.is('#sliderPDGain')) { - TuningSliders.sliderPDGain = 1; - } else if (slider.is('#sliderDMinRatio')) { - TuningSliders.sliderDMinRatio = 1; - } else if (slider.is('#sliderFeedforwardGain')) { - TuningSliders.sliderFeedforwardGain = 1; + let value; + + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + if (slider.is('#sliderDGain')) { + value = FC.DEFAULT_TUNING_SLIDERS.slider_d_gain / 100; + TuningSliders.sliderDGain = value; + } else if (slider.is('#sliderPIGain')) { + value = FC.DEFAULT_TUNING_SLIDERS.slider_pi_gain / 100; + TuningSliders.sliderPIGain = value; + } else if (slider.is('#sliderFeedforwardGain')) { + value = FC.DEFAULT_TUNING_SLIDERS.slider_feedforward_gain / 100; + TuningSliders.sliderFeedforwardGain = value; + } else if (slider.is('#sliderDMaxGain')) { + value = FC.DEFAULT_TUNING_SLIDERS.slider_dmax_gain / 100; + TuningSliders.sliderDMaxGain = value; + } else if (slider.is('#sliderIGain')) { + value = FC.DEFAULT_TUNING_SLIDERS.slider_i_gain / 100; + TuningSliders.sliderIGain = value; + } else if (slider.is('#sliderRollPitchRatio')) { + value = FC.DEFAULT_TUNING_SLIDERS.slider_roll_pitch_ratio / 100; + TuningSliders.sliderRollPitchRatio = value; + } else if (slider.is('#sliderPitchPIGain')) { + value = FC.DEFAULT_TUNING_SLIDERS.slider_pitch_pi_gain / 100; + TuningSliders.sliderPitchPIGain = value; + } else if (slider.is('#sliderMasterMultiplier')) { + value = FC.DEFAULT_TUNING_SLIDERS.slider_master_multiplier / 100; + TuningSliders.sliderMasterMultiplier = value; + } + slider.val(TuningSliders.downscaleSliderValue(value)); + } else { + if (slider.is('#sliderMasterMultiplierLegacy')) { + TuningSliders.sliderMasterMultiplierLegacy = 1; + } else if (slider.is('#sliderPDRatio')) { + TuningSliders.sliderPDRatio = 1; + } else if (slider.is('#sliderPDGain')) { + TuningSliders.sliderPDGain = 1; + } else if (slider.is('#sliderFeedforwardGainLegacy')) { + TuningSliders.sliderFeedforwardGainLegacy = 1; + } } + TuningSliders.calculateNewPids(); TuningSliders.updatePidSlidersDisplay(); }); @@ -1953,8 +2128,8 @@ TABS.pid_tuning.initialize = function (callback) { $('a.buttonPidTuningSliders').click(function() { //set Slider PID mode to RPY when re-enabling Sliders if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { - FC.TUNING_SLIDERS.slider_pids_mode = 2; - $('#sliderPidsModeSelect').val(FC.TUNING_SLIDERS.slider_pids_mode); + $('#sliderPidsModeSelect').val(2).trigger('change'); + self.sliderModeHasChanged = true; } // if values were previously changed manually and then sliders are reactivated, reset pids to previous valid values if available, else default TuningSliders.resetPidSliders(); @@ -1966,30 +2141,40 @@ TABS.pid_tuning.initialize = function (callback) { self.analyticsChanges['PidTuningSliders'] = "On"; }); - // filter slider inputs + // enable filter sliders inputs const allFilterTuningSliders = $('#sliderGyroFilterMultiplier, #sliderDTermFilterMultiplier'); - allFilterTuningSliders.on('input', function() { + allFilterTuningSliders.on('input mouseup', function() { const slider = $(this); - // adjust step for more smoothness above 1x - if (slider.val() >= 1) { - slider.attr('step', SLIDER_STEP_LOWER); + + if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + if (slider.is('#sliderGyroFilterMultiplier')) { + slider.attr('step', SLIDER_STEP_UPPER * 2); + } else { + slider.attr('step', SLIDER_STEP_UPPER); + } } else { - slider.attr('step', SLIDER_STEP_UPPER); + // adjust step for more smoothness above 1x + if (slider.val() >= 1) { + slider.attr('step', SLIDER_STEP_LOWER); + } else { + slider.attr('step', SLIDER_STEP_UPPER); + } } - if (!TuningSliders.expertMode && semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_44)) { + if (!TuningSliders.expertMode) { if (slider.val() > NON_EXPERT_SLIDER_MAX) { slider.val(NON_EXPERT_SLIDER_MAX); } else if (slider.val() < NON_EXPERT_SLIDER_MIN) { slider.val(NON_EXPERT_SLIDER_MIN); } } - const scaledValue = TuningSliders.scaleSliderValue(slider.val()); + const sliderValue = isInt(slider.val()) ? parseInt(slider.val()) : parseFloat(slider.val()); + const scaledValue = TuningSliders.scaleSliderValue(sliderValue); if (slider.is('#sliderGyroFilterMultiplier')) { TuningSliders.sliderGyroFilterMultiplier = scaledValue; TuningSliders.calculateNewGyroFilters(); self.analyticsChanges['GyroFilterTuningSlider'] = "On"; } else if (slider.is('#sliderDTermFilterMultiplier')) { - TuningSliders.sliderDTermFilterMultiplier = scaledValue; + TuningSliders.sliderDTermFilterMultiplier = sliderValue; TuningSliders.calculateNewDTermFilters(); self.analyticsChanges['DTermFilterTuningSlider'] = "On"; } @@ -2008,6 +2193,7 @@ TABS.pid_tuning.initialize = function (callback) { }); // enable Filter sliders button $('a.buttonFilterTuningSliders').click(function() { + self.sliderModeHasChanged = true; if (TuningSliders.GyroSliderUnavailable) { //set Slider mode to ON when re-enabling Sliders if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_44)) { @@ -2079,8 +2265,8 @@ TABS.pid_tuning.initialize = function (callback) { // update == save. $('a.update').click(function () { form_to_pid_and_rc(); - self.updating = true; + Promise.resolve(true) .then(function () { let promise; @@ -2113,6 +2299,9 @@ TABS.pid_tuning.initialize = function (callback) { return MSP.promise(MSPCodes.MSP_EEPROM_WRITE); }).then(function () { self.updating = false; + self.sliderPositionHasChanged = false; + self.sliderModeHasChanged = false; + self.sliderChanges = {}; self.setDirty(false); GUI.log(i18n.getMessage('pidTuningEepromSaved')); @@ -2174,7 +2363,7 @@ TABS.pid_tuning.renderModel = function () { this.currentRates.rc_expo, this.currentRates.superexpo, this.currentRates.deadband, - this.currentRates.roll_rate_limit + this.currentRates.roll_rate_limit, ); const pitch = delta * this.rateCurve.rcCommandRawToDegreesPerSecond( FC.RC.channels[1], @@ -2183,7 +2372,7 @@ TABS.pid_tuning.renderModel = function () { this.currentRates.rc_pitch_expo, this.currentRates.superexpo, this.currentRates.deadband, - this.currentRates.pitch_rate_limit + this.currentRates.pitch_rate_limit, ); const yaw = delta * this.rateCurve.rcCommandRawToDegreesPerSecond( FC.RC.channels[2], @@ -2192,7 +2381,7 @@ TABS.pid_tuning.renderModel = function () { this.currentRates.rc_yaw_expo, this.currentRates.superexpo, this.currentRates.yawDeadband, - this.currentRates.yaw_rate_limit + this.currentRates.yaw_rate_limit, ); this.model.rotateBy(-degToRad(pitch), -degToRad(yaw), -degToRad(roll)); @@ -2222,6 +2411,10 @@ TABS.pid_tuning.cleanup = function (callback) { TABS.pid_tuning.refresh = function (callback) { const self = this; + if ((self.sliderPositionHasChanged || self.sliderModeHasChanged) && !self.updating) { + TuningSliders.restoreInitialSettings(); + } + GUI.tab_switch_cleanup(function () { self.initialize(); @@ -2280,7 +2473,9 @@ TABS.pid_tuning.checkUpdateProfile = function (updateRateProfile) { } if (changedProfile || changedRateProfile) { + self.updating = true; self.refresh(function () { + self.updating = false; if (changedProfile) { GUI.log(i18n.getMessage('pidTuningReceivedProfile', [FC.CONFIG.profile + 1])); FC.CONFIG.profile = self.currentProfile; @@ -2502,9 +2697,9 @@ TABS.pid_tuning.updateRatesLabels = function() { balloonsDirty = []; // reset the dirty balloon draw area (for overlap detection) // create an array of balloons to draw const balloons = [ - {value: parseInt(maxAngularVelRoll), balloon: function() {drawBalloonLabel(stickContext, maxAngularVelRoll, curveWidth, rateScale * (maxAngularVel - parseInt(maxAngularVelRoll)), 'right', BALLOON_COLORS.roll, balloonsDirty);}}, + {value: parseInt(maxAngularVelRoll), balloon: function() {drawBalloonLabel(stickContext, maxAngularVelRoll, curveWidth, rateScale * (maxAngularVel - parseInt(maxAngularVelRoll)), 'right', BALLOON_COLORS.roll, balloonsDirty);}}, {value: parseInt(maxAngularVelPitch), balloon: function() {drawBalloonLabel(stickContext, maxAngularVelPitch, curveWidth, rateScale * (maxAngularVel - parseInt(maxAngularVelPitch)), 'right', BALLOON_COLORS.pitch, balloonsDirty);}}, - {value: parseInt(maxAngularVelYaw), balloon: function() {drawBalloonLabel(stickContext, maxAngularVelYaw, curveWidth, rateScale * (maxAngularVel - parseInt(maxAngularVelYaw)), 'right', BALLOON_COLORS.yaw, balloonsDirty);}} + {value: parseInt(maxAngularVelYaw), balloon: function() {drawBalloonLabel(stickContext, maxAngularVelYaw, curveWidth, rateScale * (maxAngularVel - parseInt(maxAngularVelYaw)), 'right', BALLOON_COLORS.yaw, balloonsDirty);}}, ]; // show warning message if any axis angular velocity exceeds 1800d/s const MAX_RATE_WARNING = 1800; @@ -2520,7 +2715,7 @@ TABS.pid_tuning.updateRatesLabels = function() { balloons.push( {value: parseInt(currentValues[0]), balloon: function() {drawBalloonLabel(stickContext, currentValues[0], 10, 150, 'none', BALLOON_COLORS.roll, balloonsDirty);}}, {value: parseInt(currentValues[1]), balloon: function() {drawBalloonLabel(stickContext, currentValues[1], 10, 250, 'none', BALLOON_COLORS.pitch, balloonsDirty);}}, - {value: parseInt(currentValues[2]), balloon: function() {drawBalloonLabel(stickContext, currentValues[2], 10, 350, 'none', BALLOON_COLORS.yaw, balloonsDirty);}} + {value: parseInt(currentValues[2]), balloon: function() {drawBalloonLabel(stickContext, currentValues[2], 10, 350, 'none', BALLOON_COLORS.yaw, balloonsDirty);}}, ); } // then display them on the chart @@ -2585,6 +2780,23 @@ TABS.pid_tuning.updatePIDColors = function(clear = false) { setTuningElementColor($('.pid_tuning .YAW input[name="f"]'), FC.ADVANCED_TUNING_ACTIVE.feedforwardYaw, FC.ADVANCED_TUNING.feedforwardYaw); }; +TABS.pid_tuning.updateGuiElements = function() { + const rollF = parseInt($('.pid_tuning .ROLL input[name="f"]').val()); + const pitchF = parseInt($('.pid_tuning .PITCH input[name="f"]').val()); + const yawF = parseInt($('.pid_tuning .YAW input[name="f"]').val()); + const FF_SWITCH = rollF || pitchF || yawF; + $('input[id="feedforwardGroup"]').prop('checked', FF_SWITCH).trigger('change'); + + const dRoll = parseInt($('.pid_tuning .ROLL input[name="d"]').val()); + const dPitch = parseInt($('.pid_tuning .PITCH input[name="d"]').val()); + const dYaw = parseInt($('.pid_tuning .YAW input[name="d"]').val()); + const dMinRoll = parseInt($('.pid_tuning input[name="dMinRoll"]').val()); + const dMinPitch = parseInt($('.pid_tuning input[name="dMinPitch"]').val()); + const dMinYaw = parseInt($('.pid_tuning input[name="dMinYaw"]').val()); + const DMAX_GAIN_SWITCH = dRoll !== dMinRoll || dPitch !== dMinPitch || dYaw !== dMinYaw; + $('#dMinSwitch').prop('checked', DMAX_GAIN_SWITCH).trigger('change'); +}; + TABS.pid_tuning.changeRatesType = function(rateTypeID) { const self = this; const dialogRatesType = $('.dialogRatesType')[0]; diff --git a/src/js/utils/common.js b/src/js/utils/common.js index 2e2e108a..bf3b5017 100644 --- a/src/js/utils/common.js +++ b/src/js/utils/common.js @@ -26,6 +26,10 @@ export function bytesToSize(bytes) { return outputBytes; } +export function isInt(n) { + return n % 1 === 0; +} + /* * checkChromeRuntimeError() has to be called after each chrome API call */ @@ -107,6 +111,7 @@ export function sortElement(element, keepDown = "DISABLED") { // TODO: these are temp binding while transition to module happens window.degToRad = degToRad; window.bytesToSize = bytesToSize; +window.isInt = isInt; window.checkChromeRuntimeError = checkChromeRuntimeError; window.generateVirtualApiVersions = generateVirtualApiVersions; window.getMixerImageSrc = getMixerImageSrc; diff --git a/src/tabs/pid_tuning.html b/src/tabs/pid_tuning.html index 1c988321..27e4c0ee 100644 --- a/src/tabs/pid_tuning.html +++ b/src/tabs/pid_tuning.html @@ -39,9 +39,11 @@

-
- -
+ +
+ +
+
@@ -89,7 +91,7 @@
-
+
@@ -117,29 +119,29 @@ - - - - + + + + - - - - + + + + - - - - + + + + @@ -177,7 +179,8 @@ - +
@@ -189,7 +192,165 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -203,89 +364,7 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+

+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+
- - - - - - -
-
- - - - - - -
-
- - - - - - -
-
- - - - - - -
-
- - - - - - -
-
- - - - - - -
-
@@ -344,7 +423,6 @@ - @@ -705,10 +783,10 @@ - +
- + @@ -1086,7 +1164,7 @@ - +
@@ -1108,7 +1186,7 @@
-
+
@@ -1428,7 +1506,7 @@
-
+