1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-16 12:55:19 +03:00

Implement tuning sliders, add to CMS, MSP

This commit is contained in:
IvoFPV 2019-10-11 18:43:10 +02:00 committed by Michael Keller
parent 3f116fd103
commit cff19dc113
14 changed files with 443 additions and 35 deletions

View file

@ -320,6 +320,7 @@ SIZE_OPTIMISED_SRC := $(SIZE_OPTIMISED_SRC) \
config/config_eeprom.c \ config/config_eeprom.c \
config/feature.c \ config/feature.c \
config/config_streamer.c \ config/config_streamer.c \
config/tuning_sliders.c \
i2c_bst.c \ i2c_bst.c \
io/dashboard.c \ io/dashboard.c \
io/serial.c \ io/serial.c \

View file

@ -57,6 +57,7 @@ bool cliMode = false;
#include "config/config.h" #include "config/config.h"
#include "config/config_eeprom.h" #include "config/config_eeprom.h"
#include "config/feature.h" #include "config/feature.h"
#include "config/tuning_sliders.h"
#include "drivers/accgyro/accgyro.h" #include "drivers/accgyro/accgyro.h"
#include "drivers/adc.h" #include "drivers/adc.h"
@ -3093,6 +3094,17 @@ static void cliVtxInfo(const char *cmdName, char *cmdline)
} }
#endif // USE_VTX_TABLE #endif // USE_VTX_TABLE
#ifdef USE_TUNING_SLIDERS
static void cliTuningSliders(const char *cmdName, char *cmdline)
{
UNUSED(cmdName);
UNUSED(cmdline);
applyTuningSliders(currentPidProfile);
cliPrintLine("Applied tuning slider calculation");
}
#endif
static void printName(dumpFlags_t dumpMask, const pilotConfig_t *pilotConfig) static void printName(dumpFlags_t dumpMask, const pilotConfig_t *pilotConfig)
{ {
const bool equalsDefault = strlen(pilotConfig->name) == 0; const bool equalsDefault = strlen(pilotConfig->name) == 0;
@ -6391,6 +6403,9 @@ static void cliHelp(const char *cmdName, char *cmdline);
// should be sorted a..z for bsearch() // should be sorted a..z for bsearch()
const clicmd_t cmdTable[] = { const clicmd_t cmdTable[] = {
CLI_COMMAND_DEF("adjrange", "configure adjustment ranges", "<index> <unused> <range channel> <start> <end> <function> <select channel> [<center> <scale>]", cliAdjustmentRange), CLI_COMMAND_DEF("adjrange", "configure adjustment ranges", "<index> <unused> <range channel> <start> <end> <function> <select channel> [<center> <scale>]", cliAdjustmentRange),
#ifdef USE_TUNING_SLIDERS
CLI_COMMAND_DEF("apply_tuning_sliders", "applies tuning sliders calculation based on slider positions", NULL, cliTuningSliders),
#endif
CLI_COMMAND_DEF("aux", "configure modes", "<index> <mode> <aux> <start> <end> <logic>", cliAux), CLI_COMMAND_DEF("aux", "configure modes", "<index> <mode> <aux> <start> <end> <logic>", cliAux),
#ifdef USE_CLI_BATCH #ifdef USE_CLI_BATCH
CLI_COMMAND_DEF("batch", "start or end a batch of commands", "start | end", cliBatch), CLI_COMMAND_DEF("batch", "start or end a batch of commands", "start | end", cliBatch),

View file

@ -33,6 +33,8 @@
#include "common/utils.h" #include "common/utils.h"
#include "common/time.h" #include "common/time.h"
#include "config/tuning_sliders.h"
#include "drivers/adc.h" #include "drivers/adc.h"
#include "drivers/bus_i2c.h" #include "drivers/bus_i2c.h"
#include "drivers/bus_spi.h" #include "drivers/bus_spi.h"
@ -158,7 +160,7 @@ const char * const lookupTableRangefinderHardware[] = {
}; };
#endif #endif
static const char * const lookupTableOffOn[] = { const char * const lookupTableOffOn[] = {
"OFF", "ON" "OFF", "ON"
}; };
@ -500,6 +502,9 @@ static const char * const lookupTableOsdLogoOnArming[] = {
"OFF", "ON", "FIRST_ARMING", "OFF", "ON", "FIRST_ARMING",
}; };
#endif #endif
const char * const lookupTableSliderPidsMode[] = {
"OFF", "RP", "RPY",
};
static const char* const lookupTableMixerType[] = { static const char* const lookupTableMixerType[] = {
"LEGACY", "LINEAR", "DYNAMIC", "LEGACY", "LINEAR", "DYNAMIC",
@ -627,6 +632,7 @@ const lookupTableEntry_t lookupTables[] = {
LOOKUP_TABLE_ENTRY(lookupTableOsdLogoOnArming), LOOKUP_TABLE_ENTRY(lookupTableOsdLogoOnArming),
#endif #endif
LOOKUP_TABLE_ENTRY(lookupTableMixerType), LOOKUP_TABLE_ENTRY(lookupTableMixerType),
LOOKUP_TABLE_ENTRY(lookupTableSliderPidsMode),
}; };
#undef LOOKUP_TABLE_ENTRY #undef LOOKUP_TABLE_ENTRY
@ -670,8 +676,8 @@ const clivalue_t valueTable[] = {
{ "dyn_notch_max_hz", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 200, 1000 }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, dyn_notch_max_hz) }, { "dyn_notch_max_hz", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 200, 1000 }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, dyn_notch_max_hz) },
#endif #endif
#ifdef USE_DYN_LPF #ifdef USE_DYN_LPF
{ "dyn_lpf_gyro_min_hz", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 1000 }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, dyn_lpf_gyro_min_hz) }, { "dyn_lpf_gyro_min_hz", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, DYN_LPF_FILTER_FREQUENCY_MAX }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, dyn_lpf_gyro_min_hz) },
{ "dyn_lpf_gyro_max_hz", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 1000 }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, dyn_lpf_gyro_max_hz) }, { "dyn_lpf_gyro_max_hz", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, DYN_LPF_FILTER_FREQUENCY_MAX }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, dyn_lpf_gyro_max_hz) },
{ "dyn_lpf_gyro_curve_expo", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 10 }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, dyn_lpf_curve_expo) }, { "dyn_lpf_gyro_curve_expo", VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 10 }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, dyn_lpf_curve_expo) },
#endif #endif
{ "gyro_filter_debug_axis", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_GYRO_FILTER_DEBUG }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, gyro_filter_debug_axis) }, { "gyro_filter_debug_axis", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_GYRO_FILTER_DEBUG }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, gyro_filter_debug_axis) },
@ -1038,8 +1044,8 @@ const clivalue_t valueTable[] = {
{ "profile_name", VAR_UINT8 | PROFILE_VALUE | MODE_STRING, .config.string = { 1, MAX_PROFILE_NAME_LENGTH, STRING_FLAGS_NONE }, PG_PID_PROFILE, offsetof(pidProfile_t, profileName) }, { "profile_name", VAR_UINT8 | PROFILE_VALUE | MODE_STRING, .config.string = { 1, MAX_PROFILE_NAME_LENGTH, STRING_FLAGS_NONE }, PG_PID_PROFILE, offsetof(pidProfile_t, profileName) },
#endif #endif
#ifdef USE_DYN_LPF #ifdef USE_DYN_LPF
{ "dyn_lpf_dterm_min_hz", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 1000 }, PG_PID_PROFILE, offsetof(pidProfile_t, dyn_lpf_dterm_min_hz) }, { "dyn_lpf_dterm_min_hz", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, DYN_LPF_FILTER_FREQUENCY_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, dyn_lpf_dterm_min_hz) },
{ "dyn_lpf_dterm_max_hz", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 1000 }, PG_PID_PROFILE, offsetof(pidProfile_t, dyn_lpf_dterm_max_hz) }, { "dyn_lpf_dterm_max_hz", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, DYN_LPF_FILTER_FREQUENCY_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, dyn_lpf_dterm_max_hz) },
{ "dyn_lpf_dterm_curve_expo", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 10 }, PG_PID_PROFILE, offsetof(pidProfile_t, dyn_lpf_curve_expo) }, { "dyn_lpf_dterm_curve_expo", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 10 }, PG_PID_PROFILE, offsetof(pidProfile_t, dyn_lpf_curve_expo) },
#endif #endif
{ "dterm_lowpass_type", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_DTERM_LOWPASS_TYPE }, PG_PID_PROFILE, offsetof(pidProfile_t, dterm_filter_type) }, { "dterm_lowpass_type", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_DTERM_LOWPASS_TYPE }, PG_PID_PROFILE, offsetof(pidProfile_t, dterm_filter_type) },
@ -1092,18 +1098,18 @@ const clivalue_t valueTable[] = {
{ "acro_trainer_gain", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 25, 255 }, PG_PID_PROFILE, offsetof(pidProfile_t, acro_trainer_gain) }, { "acro_trainer_gain", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 25, 255 }, PG_PID_PROFILE, offsetof(pidProfile_t, acro_trainer_gain) },
#endif // USE_ACRO_TRAINER #endif // USE_ACRO_TRAINER
{ "p_pitch", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_PITCH].P) }, { "p_pitch", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_PITCH].P) },
{ "i_pitch", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_PITCH].I) }, { "i_pitch", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_PITCH].I) },
{ "d_pitch", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_PITCH].D) }, { "d_pitch", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_PITCH].D) },
{ "f_pitch", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 2000 },PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_PITCH].F) }, { "f_pitch", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, F_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_PITCH].F) },
{ "p_roll", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_ROLL].P) }, { "p_roll", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_ROLL].P) },
{ "i_roll", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_ROLL].I) }, { "i_roll", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_ROLL].I) },
{ "d_roll", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_ROLL].D) }, { "d_roll", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_ROLL].D) },
{ "f_roll", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 2000 },PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_ROLL].F) }, { "f_roll", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, F_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_ROLL].F) },
{ "p_yaw", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_YAW].P) }, { "p_yaw", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_YAW].P) },
{ "i_yaw", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_YAW].I) }, { "i_yaw", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_YAW].I) },
{ "d_yaw", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_YAW].D) }, { "d_yaw", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, PID_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_YAW].D) },
{ "f_yaw", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 2000 },PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_YAW].F) }, { "f_yaw", VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, F_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_YAW].F) },
{ "angle_level_strength", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_LEVEL].P) }, { "angle_level_strength", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_LEVEL].P) },
{ "horizon_level_strength", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_LEVEL].I) }, { "horizon_level_strength", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, pid[PID_LEVEL].I) },
@ -1127,9 +1133,9 @@ const clivalue_t valueTable[] = {
#endif #endif
#ifdef USE_D_MIN #ifdef USE_D_MIN
{ "d_min_roll", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 100 }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min[FD_ROLL]) }, { "d_min_roll", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, D_MIN_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min[FD_ROLL]) },
{ "d_min_pitch", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 100 }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min[FD_PITCH]) }, { "d_min_pitch", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, D_MIN_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min[FD_PITCH]) },
{ "d_min_yaw", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 100 }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min[FD_YAW]) }, { "d_min_yaw", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, D_MIN_GAIN_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min[FD_YAW]) },
{ "d_min_boost_gain", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 100 }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min_gain) }, { "d_min_boost_gain", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 100 }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min_gain) },
{ "d_min_advance", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min_advance) }, { "d_min_advance", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, d_min_advance) },
#endif #endif
@ -1169,6 +1175,23 @@ const clivalue_t valueTable[] = {
#endif #endif
{ "level_race_mode", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_PID_PROFILE, offsetof(pidProfile_t, level_race_mode) }, { "level_race_mode", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_PID_PROFILE, offsetof(pidProfile_t, level_race_mode) },
#ifdef USE_TUNING_SLIDERS
{ "slider_pids_mode", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_SLIDER_PIDS_MODE }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_pids_mode) },
{ "slider_master_multiplier", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_master_multiplier) },
{ "slider_roll_pitch_ratio", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_roll_pitch_ratio) },
{ "slider_i_gain", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_i_gain) },
{ "slider_pd_ratio", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_pd_ratio) },
{ "slider_pd_gain", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_pd_gain) },
{ "slider_dmin_ratio", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_dmin_ratio) },
{ "slider_ff_gain", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_ff_gain) },
{ "slider_dterm_filter", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_dterm_filter) },
{ "slider_dterm_filter_multiplier", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, slider_dterm_filter_multiplier) },
{ "slider_gyro_filter", VAR_UINT8 | PROFILE_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, slider_gyro_filter) },
{ "slider_gyro_filter_multiplier", VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { SLIDER_MIN, SLIDER_MAX }, PG_GYRO_CONFIG, offsetof(gyroConfig_t, slider_gyro_filter_multiplier) },
#endif
// PG_TELEMETRY_CONFIG // PG_TELEMETRY_CONFIG
#ifdef USE_TELEMETRY #ifdef USE_TELEMETRY
{ "tlm_inverted", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, telemetry_inverted) }, { "tlm_inverted", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, telemetry_inverted) },
@ -1183,7 +1206,7 @@ const clivalue_t valueTable[] = {
{ "frsky_vfas_precision", VAR_UINT8 | MASTER_VALUE, .config.minmaxUnsigned = { FRSKY_VFAS_PRECISION_LOW, FRSKY_VFAS_PRECISION_HIGH }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, frsky_vfas_precision) }, { "frsky_vfas_precision", VAR_UINT8 | MASTER_VALUE, .config.minmaxUnsigned = { FRSKY_VFAS_PRECISION_LOW, FRSKY_VFAS_PRECISION_HIGH }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, frsky_vfas_precision) },
#endif // USE_TELEMETRY_FRSKY_HUB #endif // USE_TELEMETRY_FRSKY_HUB
{ "hott_alarm_int", VAR_UINT8 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 120 }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, hottAlarmSoundInterval) }, { "hott_alarm_int", VAR_UINT8 | MASTER_VALUE, .config.minmaxUnsigned = { 0, 120 }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, hottAlarmSoundInterval) },
{ "pid_in_tlm", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = {TABLE_OFF_ON }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, pidValuesAsTelemetry) }, { "pid_in_tlm", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, pidValuesAsTelemetry) },
{ "report_cell_voltage", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, report_cell_voltage) }, { "report_cell_voltage", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, report_cell_voltage) },
#if defined(USE_TELEMETRY_IBUS) #if defined(USE_TELEMETRY_IBUS)
{ "ibus_sensor", VAR_UINT8 | MASTER_VALUE | MODE_ARRAY, .config.array.length = IBUS_SENSOR_COUNT, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, flysky_sensors)}, { "ibus_sensor", VAR_UINT8 | MASTER_VALUE | MODE_ARRAY, .config.array.length = IBUS_SENSOR_COUNT, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, flysky_sensors)},

View file

@ -142,6 +142,7 @@ typedef enum {
TABLE_OSD_LOGO_ON_ARMING, TABLE_OSD_LOGO_ON_ARMING,
#endif #endif
TABLE_MIXER_TYPE, TABLE_MIXER_TYPE,
TABLE_SLIDER_PIDS_MODE,
LOOKUP_TABLE_COUNT LOOKUP_TABLE_COUNT
} lookupTableIndex_e; } lookupTableIndex_e;
@ -260,3 +261,7 @@ extern const char * const lookupTableItermRelaxType[];
extern const char * const lookupTableOsdDisplayPortDevice[]; extern const char * const lookupTableOsdDisplayPortDevice[];
extern const char * const lookupTableInterpolatedSetpoint[]; extern const char * const lookupTableInterpolatedSetpoint[];
extern const char * const lookupTableOffOn[];
extern const char * const lookupTableSliderPidsMode[];

View file

@ -40,6 +40,7 @@
#include "common/utils.h" #include "common/utils.h"
#include "config/feature.h" #include "config/feature.h"
#include "config/tuning_sliders.h"
#include "drivers/pwm_output.h" #include "drivers/pwm_output.h"
@ -228,6 +229,113 @@ static CMS_Menu cmsx_menuPid = {
.entries = cmsx_menuPidEntries .entries = cmsx_menuPidEntries
}; };
#ifdef USE_TUNING_SLIDERS
static uint8_t cmsx_slider_pids_mode;
static uint8_t cmsx_slider_master_multiplier;
static uint8_t cmsx_slider_roll_pitch_ratio;
static uint8_t cmsx_slider_i_gain;
static uint8_t cmsx_slider_pd_ratio;
static uint8_t cmsx_slider_pd_gain;
static uint8_t cmsx_slider_dmin_ratio;
static uint8_t cmsx_slider_ff_gain;
static uint8_t cmsx_slider_dterm_filter;
static uint8_t cmsx_slider_dterm_filter_multiplier;
static uint8_t cmsx_slider_gyro_filter;
static uint8_t cmsx_slider_gyro_filter_multiplier;
static const void *cmsx_slidersOnEnter(displayPort_t *pDisp)
{
UNUSED(pDisp);
const pidProfile_t *pidProfile = pidProfiles(pidProfileIndex);
cmsx_slider_pids_mode = pidProfile->slider_pids_mode;
cmsx_slider_master_multiplier = pidProfile->slider_master_multiplier;
cmsx_slider_roll_pitch_ratio = pidProfile->slider_roll_pitch_ratio;
cmsx_slider_i_gain = pidProfile->slider_i_gain;
cmsx_slider_pd_ratio = pidProfile->slider_pd_ratio;
cmsx_slider_pd_gain = pidProfile->slider_pd_gain;
cmsx_slider_dmin_ratio = pidProfile->slider_dmin_ratio;
cmsx_slider_ff_gain = pidProfile->slider_ff_gain;
cmsx_slider_dterm_filter = pidProfile->slider_dterm_filter;
cmsx_slider_dterm_filter_multiplier = pidProfile->slider_dterm_filter_multiplier;
cmsx_slider_gyro_filter = gyroConfig()->slider_gyro_filter;
cmsx_slider_gyro_filter_multiplier = gyroConfig()->slider_gyro_filter_multiplier;
return 0;
}
static const void *cmsx_slidersOnExit(displayPort_t *pDisp, const OSD_Entry *self)
{
UNUSED(pDisp);
UNUSED(self);
pidProfile_t *pidProfile = currentPidProfile;
pidProfile->slider_pids_mode = cmsx_slider_pids_mode;
pidProfile->slider_master_multiplier = cmsx_slider_master_multiplier;
pidProfile->slider_roll_pitch_ratio = cmsx_slider_roll_pitch_ratio;
pidProfile->slider_i_gain = cmsx_slider_i_gain;
pidProfile->slider_pd_ratio = cmsx_slider_pd_ratio;
pidProfile->slider_pd_gain = cmsx_slider_pd_gain;
pidProfile->slider_dmin_ratio = cmsx_slider_dmin_ratio;
pidProfile->slider_ff_gain = cmsx_slider_ff_gain;
pidProfile->slider_dterm_filter = cmsx_slider_dterm_filter;
pidProfile->slider_dterm_filter_multiplier = cmsx_slider_dterm_filter_multiplier;
gyroConfigMutable()->slider_gyro_filter = cmsx_slider_gyro_filter;
gyroConfigMutable()->slider_gyro_filter_multiplier = cmsx_slider_gyro_filter_multiplier;
return 0;
}
static const void *cmsx_applyTuningSliders(displayPort_t *pDisp, const void *self)
{
UNUSED(pDisp);
UNUSED(self);
applyTuningSliders(currentPidProfile);
return 0;
}
static const OSD_Entry cmsx_menuSlidersEntries[] =
{
{ "-- PID SLIDERS --", OME_Label, NULL, NULL, 0},
{ "PID SLIDERS", OME_TAB, NULL, &(OSD_TAB_t) { &cmsx_slider_pids_mode, PID_TUNING_SLIDERS_MODE_COUNT - 1, lookupTableSliderPidsMode }, 0 },
{ "MASTER MULT", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_master_multiplier, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "R/P RATIO", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_roll_pitch_ratio, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "I GAIN", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_i_gain, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "PD RATIO", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_pd_ratio, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "PD GAIN", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_pd_gain, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "DMIN RATIO", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_dmin_ratio, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "FF GAIN", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_ff_gain, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "-- FILTER SLIDERS --", OME_Label, NULL, NULL, 0},
{ "GYRO SLIDER", OME_TAB, NULL, &(OSD_TAB_t) { &cmsx_slider_gyro_filter, 1, lookupTableOffOn }, 0 },
{ "GYRO MULT", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_gyro_filter_multiplier, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "DTERM SLIDER", OME_TAB, NULL, &(OSD_TAB_t) { &cmsx_slider_dterm_filter, 1, lookupTableOffOn }, 0 },
{ "DTERM MULT", OME_FLOAT, NULL, &(OSD_FLOAT_t) { &cmsx_slider_dterm_filter_multiplier, SLIDER_MIN, SLIDER_MAX, 1, 10 }, 0 },
{ "APPLY SLIDERS", OME_Funcall, cmsx_applyTuningSliders, NULL, 0 },
{ "BACK", OME_Back, NULL, NULL, 0 },
{ NULL, OME_END, NULL, NULL, 0 }
};
static CMS_Menu cmsx_menuSliders = {
#ifdef CMS_MENU_DEBUG
.GUARD_text = "XSLIDER",
.GUARD_type = OME_MENU,
#endif
.onEnter = cmsx_slidersOnEnter,
.onExit = cmsx_slidersOnExit,
.entries = cmsx_menuSlidersEntries,
};
#endif // USE_TUNING_SLIDERS
// //
// Rate & Expo // Rate & Expo
// //
@ -344,7 +452,7 @@ static const OSD_Entry cmsx_menuLaunchControlEntries[] = {
{ "TRIGGER THROTTLE", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_launchControlThrottlePercent, 0, LAUNCH_CONTROL_THROTTLE_TRIGGER_MAX, 1 } , 0 }, { "TRIGGER THROTTLE", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_launchControlThrottlePercent, 0, LAUNCH_CONTROL_THROTTLE_TRIGGER_MAX, 1 } , 0 },
{ "ANGLE LIMIT", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_launchControlAngleLimit, 0, 80, 1 } , 0 }, { "ANGLE LIMIT", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_launchControlAngleLimit, 0, 80, 1 } , 0 },
{ "ITERM GAIN", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_launchControlGain, 0, 200, 1 } , 0 }, { "ITERM GAIN", OME_UINT8, NULL, &(OSD_UINT8_t) { &cmsx_launchControlGain, 0, 200, 1 } , 0 },
{ "BACK", OME_Back, NULL, NULL, 0 }, { "BACK", OME_Back, NULL, NULL, 0 },
{ NULL, OME_END, NULL, NULL, 0 } { NULL, OME_END, NULL, NULL, 0 }
}; };
@ -604,7 +712,7 @@ static const OSD_Entry cmsx_menuFilterGlobalEntries[] =
#ifdef USE_MULTI_GYRO #ifdef USE_MULTI_GYRO
{ "GYRO TO USE", OME_TAB, NULL, &(OSD_TAB_t) { &gyroConfig_gyro_to_use, 2, osdTableGyroToUse}, REBOOT_REQUIRED }, { "GYRO TO USE", OME_TAB, NULL, &(OSD_TAB_t) { &gyroConfig_gyro_to_use, 2, osdTableGyroToUse}, REBOOT_REQUIRED },
#endif #endif
{ "BACK", OME_Back, NULL, NULL, 0 }, { "BACK", OME_Back, NULL, NULL, 0 },
{ NULL, OME_END, NULL, NULL, 0 } { NULL, OME_END, NULL, NULL, 0 }
}; };
@ -767,7 +875,7 @@ static const OSD_Entry cmsx_menuFilterPerProfileEntries[] =
{ "DTERM NF", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_dterm_notch_hz, 0, FILTER_FREQUENCY_MAX, 1 }, 0 }, { "DTERM NF", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_dterm_notch_hz, 0, FILTER_FREQUENCY_MAX, 1 }, 0 },
{ "DTERM NFCO", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_dterm_notch_cutoff, 0, FILTER_FREQUENCY_MAX, 1 }, 0 }, { "DTERM NFCO", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_dterm_notch_cutoff, 0, FILTER_FREQUENCY_MAX, 1 }, 0 },
{ "YAW LPF", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_yaw_lowpass_hz, 0, 500, 1 }, 0 }, { "YAW LPF", OME_UINT16, NULL, &(OSD_UINT16_t){ &cmsx_yaw_lowpass_hz, 0, 500, 1 }, 0 },
{ "BACK", OME_Back, NULL, NULL, 0 }, { "BACK", OME_Back, NULL, NULL, 0 },
{ NULL, OME_END, NULL, NULL, 0 } { NULL, OME_END, NULL, NULL, 0 }
}; };
@ -864,6 +972,9 @@ static const OSD_Entry cmsx_menuImuEntries[] =
{"PID PROF", OME_UINT8, cmsx_profileIndexOnChange, &(OSD_UINT8_t){ &tmpPidProfileIndex, 1, PID_PROFILE_COUNT, 1}, 0}, {"PID PROF", OME_UINT8, cmsx_profileIndexOnChange, &(OSD_UINT8_t){ &tmpPidProfileIndex, 1, PID_PROFILE_COUNT, 1}, 0},
{"PID", OME_Submenu, cmsMenuChange, &cmsx_menuPid, 0}, {"PID", OME_Submenu, cmsMenuChange, &cmsx_menuPid, 0},
#ifdef USE_TUNING_SLIDERS
{"SLIDERS", OME_Submenu, cmsMenuChange, &cmsx_menuSliders, 0},
#endif
{"MISC PP", OME_Submenu, cmsMenuChange, &cmsx_menuProfileOther, 0}, {"MISC PP", OME_Submenu, cmsMenuChange, &cmsx_menuProfileOther, 0},
{"FILT PP", OME_Submenu, cmsMenuChange, &cmsx_menuFilterPerProfile, 0}, {"FILT PP", OME_Submenu, cmsMenuChange, &cmsx_menuFilterPerProfile, 0},

View file

@ -0,0 +1,125 @@
/*
* This file is part of Cleanflight and Betaflight.
*
* Cleanflight and Betaflight are free software. You can redistribute
* this software and/or modify this software under the terms of the
* GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Cleanflight and Betaflight are distributed in the hope that they
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include "platform.h"
#ifdef USE_TUNING_SLIDERS
#include "common/axis.h"
#include "common/maths.h"
#include "config/tuning_sliders.h"
#include "sensors/gyro.h"
static void calculateNewPidValues(pidProfile_t *pidProfile)
{
const pidf_t pidDefaults[FLIGHT_DYNAMICS_INDEX_COUNT] = {
[PID_ROLL] = PID_ROLL_DEFAULT,
[PID_PITCH] = PID_ROLL_DEFAULT, // using the same defaults as roll
[PID_YAW] = PID_YAW_DEFAULT,
};
const int dMinDefaults[FLIGHT_DYNAMICS_INDEX_COUNT] = D_MIN_DEFAULT;
// MASTER MULTIPLIER
for (int axis = FD_ROLL; axis <= pidProfile->slider_pids_mode; ++axis) {
pidProfile->pid[axis].P = constrain(pidDefaults[axis].P * pidProfile->slider_master_multiplier / 100, 0, PID_GAIN_MAX);
pidProfile->pid[axis].I = constrain(pidDefaults[axis].I * pidProfile->slider_master_multiplier / 100, 0, PID_GAIN_MAX);
pidProfile->pid[axis].D = constrain(pidDefaults[axis].D * pidProfile->slider_master_multiplier / 100, 0, PID_GAIN_MAX);
pidProfile->d_min[axis] = constrain(dMinDefaults[axis] * pidProfile->slider_master_multiplier / 100, 0, D_MIN_GAIN_MAX);
pidProfile->pid[axis].F = constrain(pidDefaults[axis].F * pidProfile->slider_master_multiplier / 100, 0, F_GAIN_MAX);
}
// ROLL PITCH RATIO
pidProfile->pid[FD_ROLL].P = constrain(pidProfile->pid[FD_ROLL].P * pidProfile->slider_roll_pitch_ratio / 100, 0, PID_GAIN_MAX);
pidProfile->pid[FD_ROLL].I = constrain(pidProfile->pid[FD_ROLL].I * pidProfile->slider_roll_pitch_ratio / 100, 0, PID_GAIN_MAX);
pidProfile->pid[FD_ROLL].D = constrain(pidProfile->pid[FD_ROLL].D * pidProfile->slider_roll_pitch_ratio / 100, 0, PID_GAIN_MAX);
pidProfile->d_min[FD_ROLL] = constrain(pidProfile->d_min[FD_ROLL] * pidProfile->slider_roll_pitch_ratio / 100, 0, D_MIN_GAIN_MAX);
pidProfile->pid[FD_ROLL].F = constrain(pidProfile->pid[FD_ROLL].F * pidProfile->slider_roll_pitch_ratio / 100, 0, F_GAIN_MAX);
// I GAIN
for (int axis = FD_ROLL; axis <= pidProfile->slider_pids_mode; ++axis) {
pidProfile->pid[axis].I = constrain(pidProfile->pid[axis].I * pidProfile->slider_i_gain / 100, 0, PID_GAIN_MAX);
}
// PD RATIO - applied only on roll and pitch because on yaw default D gain is 0
const float defaultPDRatio = pidDefaults[FD_ROLL].P / (float)pidDefaults[FD_ROLL].D;
for (int axis = FD_ROLL; axis <= FD_PITCH; ++axis) {
pidProfile->pid[axis].P = constrain(pidProfile->pid[axis].D * defaultPDRatio * pidProfile->slider_pd_ratio / 100, 0, PID_GAIN_MAX);
}
// PD GAIN
for (int axis = FD_ROLL; axis <= pidProfile->slider_pids_mode; ++axis) {
pidProfile->pid[axis].P = constrain(pidProfile->pid[axis].P * pidProfile->slider_pd_gain / 100, 0, PID_GAIN_MAX);
pidProfile->pid[axis].D = constrain(pidProfile->pid[axis].D * pidProfile->slider_pd_gain / 100, 0, PID_GAIN_MAX);
pidProfile->d_min[axis] = constrain(pidProfile->d_min[axis] * pidProfile->slider_pd_gain / 100, 0, D_MIN_GAIN_MAX);
}
// D MIN RATIO
const float defaultDMinRatio = dMinDefaults[FD_ROLL] / (float)pidDefaults[FD_ROLL].D;
const float scaledDminRatioSliderValue = scaleRangef(pidProfile->slider_dmin_ratio, SLIDER_MIN, SLIDER_MAX, SLIDER_MIN + SLIDER_MAX - 100 / defaultDMinRatio, 100 / defaultDMinRatio);
for (int axis = FD_ROLL; axis <= pidProfile->slider_pids_mode; ++axis) {
if (pidProfile->slider_dmin_ratio == 200) {
pidProfile->d_min[axis] = 0; // disable d_min if slider maxed out
} else {
pidProfile->d_min[axis] = constrain(constrain(pidProfile->pid[axis].D * defaultDMinRatio * scaledDminRatioSliderValue / 100, 0, pidProfile->pid[axis].D - 1), 0, D_MIN_GAIN_MAX);
}
}
// FF GAIN
for (int axis = FD_ROLL; axis <= pidProfile->slider_pids_mode; ++axis) {
pidProfile->pid[axis].F = constrain(pidProfile->pid[axis].F * pidProfile->slider_ff_gain / 100, 0, F_GAIN_MAX);
}
}
static void calculateNewDTermFilterValues(pidProfile_t *pidProfile)
{
pidProfile->dyn_lpf_dterm_min_hz = constrain(DYN_LPF_DTERM_MIN_HZ_DEFAULT * pidProfile->slider_dterm_filter_multiplier / 100, 0, DYN_LPF_FILTER_FREQUENCY_MAX);
pidProfile->dyn_lpf_dterm_max_hz = constrain(DYN_LPF_DTERM_MAX_HZ_DEFAULT * pidProfile->slider_dterm_filter_multiplier / 100, 0, DYN_LPF_FILTER_FREQUENCY_MAX);
pidProfile->dterm_lowpass2_hz = constrain(DTERM_LOWPASS_2_HZ_DEFAULT * pidProfile->slider_dterm_filter_multiplier / 100, 0, FILTER_FREQUENCY_MAX);
pidProfile->dterm_filter_type = FILTER_PT1;
pidProfile->dterm_filter2_type = FILTER_PT1;
}
static void calculateNewGyroFilterValues()
{
gyroConfigMutable()->dyn_lpf_gyro_min_hz = constrain(DYN_LPF_GYRO_MIN_HZ_DEFAULT * gyroConfig()->slider_gyro_filter_multiplier / 100, 0, DYN_LPF_FILTER_FREQUENCY_MAX);
gyroConfigMutable()->dyn_lpf_gyro_max_hz = constrain(DYN_LPF_GYRO_MAX_HZ_DEFAULT * gyroConfig()->slider_gyro_filter_multiplier / 100, 0, DYN_LPF_FILTER_FREQUENCY_MAX);
gyroConfigMutable()->gyro_lowpass2_hz = constrain(GYRO_LOWPASS_2_HZ_DEFAULT * gyroConfig()->slider_gyro_filter_multiplier / 100, 0, FILTER_FREQUENCY_MAX);
gyroConfigMutable()->gyro_lowpass_type = FILTER_PT1;
gyroConfigMutable()->gyro_lowpass2_type = FILTER_PT1;
}
void applyTuningSliders(pidProfile_t *pidProfile)
{
if (pidProfile->slider_pids_mode != PID_TUNING_SLIDERS_OFF) {
calculateNewPidValues(pidProfile);
}
if (pidProfile->slider_dterm_filter) {
calculateNewDTermFilterValues(pidProfile);
}
if (gyroConfig()->slider_gyro_filter) {
calculateNewGyroFilterValues();
}
}
#endif // USE_TUNING_SLIDERS

View file

@ -0,0 +1,35 @@
/*
* This file is part of Cleanflight and Betaflight.
*
* Cleanflight and Betaflight are free software. You can redistribute
* this software and/or modify this software under the terms of the
* GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Cleanflight and Betaflight are distributed in the hope that they
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "flight/pid.h"
#define SLIDER_MIN 50
#define SLIDER_MAX 200
typedef enum {
PID_TUNING_SLIDERS_OFF = 0,
PID_TUNING_SLIDERS_RP,
PID_TUNING_SLIDERS_RPY,
PID_TUNING_SLIDERS_MODE_COUNT,
} pidTuningSlidersMode_e;
void applyTuningSliders(pidProfile_t *pidProfile);

View file

@ -33,6 +33,7 @@
#include "common/maths.h" #include "common/maths.h"
#include "config/config_reset.h" #include "config/config_reset.h"
#include "config/tuning_sliders.h"
#include "drivers/pwm_output.h" #include "drivers/pwm_output.h"
#include "drivers/sound_beeper.h" #include "drivers/sound_beeper.h"
@ -127,9 +128,9 @@ void resetPidProfile(pidProfile_t *pidProfile)
{ {
RESET_CONFIG(pidProfile_t, pidProfile, RESET_CONFIG(pidProfile_t, pidProfile,
.pid = { .pid = {
[PID_ROLL] = { 42, 85, 35, 90 }, [PID_ROLL] = PID_ROLL_DEFAULT,
[PID_PITCH] = { 46, 90, 38, 95 }, [PID_PITCH] = PID_PITCH_DEFAULT,
[PID_YAW] = { 45, 90, 0, 90 }, [PID_YAW] = PID_YAW_DEFAULT,
[PID_LEVEL] = { 50, 50, 75, 0 }, [PID_LEVEL] = { 50, 50, 75, 0 },
[PID_MAG] = { 40, 0, 0, 0 }, [PID_MAG] = { 40, 0, 0, 0 },
}, },
@ -177,11 +178,11 @@ void resetPidProfile(pidProfile_t *pidProfile)
// overridden and the static lowpass 1 is disabled. We can't set this // overridden and the static lowpass 1 is disabled. We can't set this
// value to 0 otherwise Configurator versions 10.4 and earlier will also // value to 0 otherwise Configurator versions 10.4 and earlier will also
// reset the lowpass filter type to PT1 overriding the desired BIQUAD setting. // reset the lowpass filter type to PT1 overriding the desired BIQUAD setting.
.dterm_lowpass2_hz = 150, // second Dterm LPF ON by default .dterm_lowpass2_hz = DTERM_LOWPASS_2_HZ_DEFAULT, // second Dterm LPF ON by default
.dterm_filter_type = FILTER_PT1, .dterm_filter_type = FILTER_PT1,
.dterm_filter2_type = FILTER_PT1, .dterm_filter2_type = FILTER_PT1,
.dyn_lpf_dterm_min_hz = 70, .dyn_lpf_dterm_min_hz = DYN_LPF_DTERM_MIN_HZ_DEFAULT,
.dyn_lpf_dterm_max_hz = 170, .dyn_lpf_dterm_max_hz = DYN_LPF_DTERM_MAX_HZ_DEFAULT,
.launchControlMode = LAUNCH_CONTROL_MODE_NORMAL, .launchControlMode = LAUNCH_CONTROL_MODE_NORMAL,
.launchControlThrottlePercent = 20, .launchControlThrottlePercent = 20,
.launchControlAngleLimit = 0, .launchControlAngleLimit = 0,
@ -190,7 +191,7 @@ void resetPidProfile(pidProfile_t *pidProfile)
.use_integrated_yaw = false, .use_integrated_yaw = false,
.integrated_yaw_relax = 200, .integrated_yaw_relax = 200,
.thrustLinearization = 0, .thrustLinearization = 0,
.d_min = { 23, 25, 0 }, // roll, pitch, yaw .d_min = D_MIN_DEFAULT,
.d_min_gain = 37, .d_min_gain = 37,
.d_min_advance = 20, .d_min_advance = 20,
.motor_output_limit = 100, .motor_output_limit = 100,
@ -209,6 +210,16 @@ void resetPidProfile(pidProfile_t *pidProfile)
.dyn_lpf_curve_expo = 5, .dyn_lpf_curve_expo = 5,
.level_race_mode = false, .level_race_mode = false,
.vbat_sag_compensation = 0, .vbat_sag_compensation = 0,
.slider_pids_mode = PID_TUNING_SLIDERS_OFF,
.slider_master_multiplier = 100,
.slider_roll_pitch_ratio = 100,
.slider_i_gain = 100,
.slider_pd_ratio = 100,
.slider_pd_gain = 100,
.slider_dmin_ratio = 100,
.slider_ff_gain = 100,
.slider_dterm_filter = true,
.slider_dterm_filter_multiplier = 100,
); );
#ifndef USE_D_MIN #ifndef USE_D_MIN
pidProfile->pid[PID_ROLL].D = 30; pidProfile->pid[PID_ROLL].D = 30;

View file

@ -36,6 +36,10 @@
#define PIDSUM_LIMIT_MIN 100 #define PIDSUM_LIMIT_MIN 100
#define PIDSUM_LIMIT_MAX 1000 #define PIDSUM_LIMIT_MAX 1000
#define PID_GAIN_MAX 200
#define F_GAIN_MAX 2000
#define D_MIN_GAIN_MAX 100
// Scaling factors for Pids for better tunable range in configurator for betaflight pid controller. The scaling is based on legacy pid controller or previous float // Scaling factors for Pids for better tunable range in configurator for betaflight pid controller. The scaling is based on legacy pid controller or previous float
#define PTERM_SCALE 0.032029f #define PTERM_SCALE 0.032029f
#define ITERM_SCALE 0.244381f #define ITERM_SCALE 0.244381f
@ -54,6 +58,15 @@
#define ITERM_ACCELERATOR_GAIN_OFF 0 #define ITERM_ACCELERATOR_GAIN_OFF 0
#define ITERM_ACCELERATOR_GAIN_MAX 30000 #define ITERM_ACCELERATOR_GAIN_MAX 30000
#define PID_ROLL_DEFAULT { 42, 85, 35, 90 }
#define PID_PITCH_DEFAULT { 46, 90, 38, 95 }
#define PID_YAW_DEFAULT { 45, 90, 0, 90 }
#define D_MIN_DEFAULT { 23, 25, 0 }
#define DYN_LPF_DTERM_MIN_HZ_DEFAULT 70
#define DYN_LPF_DTERM_MAX_HZ_DEFAULT 170
#define DTERM_LOWPASS_2_HZ_DEFAULT 150
typedef enum { typedef enum {
PID_ROLL, PID_ROLL,
PID_PITCH, PID_PITCH,
@ -200,6 +213,18 @@ typedef struct pidProfile_s {
uint8_t dyn_lpf_curve_expo; // set the curve for dynamic dterm lowpass filter uint8_t dyn_lpf_curve_expo; // set the curve for dynamic dterm lowpass filter
uint8_t level_race_mode; // NFE race mode - when true pitch setpoint calcualtion is gyro based in level mode uint8_t level_race_mode; // NFE race mode - when true pitch setpoint calcualtion is gyro based in level mode
uint8_t vbat_sag_compensation; // Reduce motor output by this percentage of the maximum compensation amount uint8_t vbat_sag_compensation; // Reduce motor output by this percentage of the maximum compensation amount
uint8_t slider_pids_mode;
uint8_t slider_master_multiplier;
uint8_t slider_roll_pitch_ratio;
uint8_t slider_i_gain;
uint8_t slider_pd_ratio;
uint8_t slider_pd_gain;
uint8_t slider_dmin_ratio;
uint8_t slider_ff_gain;
uint8_t slider_dterm_filter;
uint8_t slider_dterm_filter_multiplier;
} pidProfile_t; } pidProfile_t;
PG_DECLARE_ARRAY(pidProfile_t, PID_PROFILE_COUNT, pidProfiles); PG_DECLARE_ARRAY(pidProfile_t, PID_PROFILE_COUNT, pidProfiles);

View file

@ -47,6 +47,7 @@
#include "config/config.h" #include "config/config.h"
#include "config/config_eeprom.h" #include "config/config_eeprom.h"
#include "config/feature.h" #include "config/feature.h"
#include "config/tuning_sliders.h"
#include "drivers/accgyro/accgyro.h" #include "drivers/accgyro/accgyro.h"
#include "drivers/bus_i2c.h" #include "drivers/bus_i2c.h"
@ -2087,6 +2088,28 @@ static mspResult_e mspFcProcessOutCommandWithArg(mspDescriptor_t srcDesc, int16_
break; break;
#endif // USE_VTX_TABLE #endif // USE_VTX_TABLE
#ifdef USE_TUNING_SLIDERS
// Added in MSP API 1.43
case MSP_TUNING_SLIDERS:
{
sbufWriteU8(dst, currentPidProfile->slider_pids_mode);
sbufWriteU8(dst, currentPidProfile->slider_master_multiplier);
sbufWriteU8(dst, currentPidProfile->slider_roll_pitch_ratio);
sbufWriteU8(dst, currentPidProfile->slider_i_gain);
sbufWriteU8(dst, currentPidProfile->slider_pd_ratio);
sbufWriteU8(dst, currentPidProfile->slider_pd_gain);
sbufWriteU8(dst, currentPidProfile->slider_dmin_ratio);
sbufWriteU8(dst, currentPidProfile->slider_ff_gain);
sbufWriteU8(dst, currentPidProfile->slider_dterm_filter);
sbufWriteU8(dst, currentPidProfile->slider_dterm_filter_multiplier);
sbufWriteU8(dst, gyroConfig()->slider_gyro_filter);
sbufWriteU8(dst, gyroConfig()->slider_gyro_filter_multiplier);
}
break;
#endif
case MSP_RESET_CONF: case MSP_RESET_CONF:
{ {
#if defined(USE_CUSTOM_DEFAULTS) #if defined(USE_CUSTOM_DEFAULTS)
@ -3031,6 +3054,29 @@ static mspResult_e mspProcessInCommand(mspDescriptor_t srcDesc, int16_t cmdMSP,
break; break;
#endif #endif
#ifdef USE_TUNING_SLIDERS
// Added in MSP API 1.43
case MSP_SET_TUNING_SLIDERS:
currentPidProfile->slider_pids_mode = sbufReadU8(src);
currentPidProfile->slider_master_multiplier = sbufReadU8(src);
currentPidProfile->slider_roll_pitch_ratio = sbufReadU8(src);
currentPidProfile->slider_i_gain = sbufReadU8(src);
currentPidProfile->slider_pd_ratio = sbufReadU8(src);
currentPidProfile->slider_pd_gain = sbufReadU8(src);
currentPidProfile->slider_dmin_ratio = sbufReadU8(src);
currentPidProfile->slider_ff_gain = sbufReadU8(src);
currentPidProfile->slider_dterm_filter = sbufReadU8(src);
currentPidProfile->slider_dterm_filter_multiplier = sbufReadU8(src);
gyroConfigMutable()->slider_gyro_filter = sbufReadU8(src);
gyroConfigMutable()->slider_gyro_filter_multiplier = sbufReadU8(src);
applyTuningSliders(currentPidProfile);
break;
#endif
#ifdef USE_CAMERA_CONTROL #ifdef USE_CAMERA_CONTROL
case MSP_CAMERA_CONTROL: case MSP_CAMERA_CONTROL:
{ {

View file

@ -285,6 +285,9 @@
#define MSP_VTXTABLE_POWERLEVEL 138 //out message vtxTable powerLevel data #define MSP_VTXTABLE_POWERLEVEL 138 //out message vtxTable powerLevel data
#define MSP_MOTOR_TELEMETRY 139 //out message Per-motor telemetry data (RPM, packet stats, ESC temp, etc.) #define MSP_MOTOR_TELEMETRY 139 //out message Per-motor telemetry data (RPM, packet stats, ESC temp, etc.)
#define MSP_TUNING_SLIDERS 140 //out message Tuning slider poisitons and enabled state
#define MSP_SET_TUNING_SLIDERS 141 //in message Set tuning slider positions and apply tuning slider calculation
#define MSP_SET_RAW_RC 200 //in message 8 rc chan #define MSP_SET_RAW_RC 200 //in message 8 rc chan
#define MSP_SET_RAW_GPS 201 //in message fix, numsat, lat, lon, alt, speed #define MSP_SET_RAW_GPS 201 //in message fix, numsat, lat, lon, alt, speed
#define MSP_SET_PID 202 //in message P I D coeff (9 are used currently) #define MSP_SET_PID 202 //in message P I D coeff (9 are used currently)

View file

@ -114,7 +114,7 @@ void pgResetFn_gyroConfig(gyroConfig_t *gyroConfig)
// value to 0 otherwise Configurator versions 10.4 and earlier will also // value to 0 otherwise Configurator versions 10.4 and earlier will also
// reset the lowpass filter type to PT1 overriding the desired BIQUAD setting. // reset the lowpass filter type to PT1 overriding the desired BIQUAD setting.
gyroConfig->gyro_lowpass2_type = FILTER_PT1; gyroConfig->gyro_lowpass2_type = FILTER_PT1;
gyroConfig->gyro_lowpass2_hz = 250; gyroConfig->gyro_lowpass2_hz = GYRO_LOWPASS_2_HZ_DEFAULT;
gyroConfig->gyro_high_fsr = false; gyroConfig->gyro_high_fsr = false;
gyroConfig->gyro_to_use = GYRO_CONFIG_USE_GYRO_DEFAULT; gyroConfig->gyro_to_use = GYRO_CONFIG_USE_GYRO_DEFAULT;
gyroConfig->gyro_soft_notch_hz_1 = 0; gyroConfig->gyro_soft_notch_hz_1 = 0;
@ -125,14 +125,14 @@ void pgResetFn_gyroConfig(gyroConfig_t *gyroConfig)
gyroConfig->gyro_offset_yaw = 0; gyroConfig->gyro_offset_yaw = 0;
gyroConfig->yaw_spin_recovery = YAW_SPIN_RECOVERY_AUTO; gyroConfig->yaw_spin_recovery = YAW_SPIN_RECOVERY_AUTO;
gyroConfig->yaw_spin_threshold = 1950; gyroConfig->yaw_spin_threshold = 1950;
gyroConfig->dyn_lpf_gyro_min_hz = 200; gyroConfig->dyn_lpf_gyro_min_hz = DYN_LPF_GYRO_MIN_HZ_DEFAULT;
gyroConfig->dyn_lpf_gyro_max_hz = 500; gyroConfig->dyn_lpf_gyro_max_hz = DYN_LPF_GYRO_MAX_HZ_DEFAULT;
gyroConfig->dyn_notch_max_hz = 600; gyroConfig->dyn_notch_max_hz = 600;
gyroConfig->dyn_notch_width_percent = 8; gyroConfig->dyn_notch_width_percent = 8;
gyroConfig->dyn_notch_q = 120; gyroConfig->dyn_notch_q = 120;
gyroConfig->dyn_notch_min_hz = 150; gyroConfig->dyn_notch_min_hz = 150;
gyroConfig->gyro_filter_debug_axis = FD_ROLL; gyroConfig->gyro_filter_debug_axis = FD_ROLL;
gyroConfig->dyn_lpf_curve_expo = 5; gyroConfig->dyn_lpf_curve_expo = 0;
} }
#ifdef USE_GYRO_DATA_ANALYSE #ifdef USE_GYRO_DATA_ANALYSE

View file

@ -37,6 +37,11 @@
#include "pg/pg.h" #include "pg/pg.h"
#define FILTER_FREQUENCY_MAX 4000 // maximum frequency for filter cutoffs (nyquist limit of 8K max sampling) #define FILTER_FREQUENCY_MAX 4000 // maximum frequency for filter cutoffs (nyquist limit of 8K max sampling)
#define DYN_LPF_FILTER_FREQUENCY_MAX 1000
#define DYN_LPF_GYRO_MIN_HZ_DEFAULT 200
#define DYN_LPF_GYRO_MAX_HZ_DEFAULT 500
#define GYRO_LOWPASS_2_HZ_DEFAULT 250
#ifdef USE_YAW_SPIN_RECOVERY #ifdef USE_YAW_SPIN_RECOVERY
#define YAW_SPIN_RECOVERY_THRESHOLD_MIN 500 #define YAW_SPIN_RECOVERY_THRESHOLD_MIN 500
@ -199,6 +204,8 @@ typedef struct gyroConfig_s {
uint8_t gyrosDetected; // What gyros should detection be attempted for on startup. Automatically set on first startup. uint8_t gyrosDetected; // What gyros should detection be attempted for on startup. Automatically set on first startup.
uint8_t dyn_lpf_curve_expo; // set the curve for dynamic gyro lowpass filter uint8_t dyn_lpf_curve_expo; // set the curve for dynamic gyro lowpass filter
uint8_t slider_gyro_filter;
uint8_t slider_gyro_filter_multiplier;
} gyroConfig_t; } gyroConfig_t;
PG_DECLARE(gyroConfig_t, gyroConfig); PG_DECLARE(gyroConfig_t, gyroConfig);

View file

@ -395,4 +395,5 @@
#define USE_CUSTOM_BOX_NAMES #define USE_CUSTOM_BOX_NAMES
#define USE_BATTERY_VOLTAGE_SAG_COMPENSATION #define USE_BATTERY_VOLTAGE_SAG_COMPENSATION
#define USE_RX_MSP_OVERRIDE #define USE_RX_MSP_OVERRIDE
#define USE_TUNING_SLIDERS
#endif #endif