mirror of
https://github.com/iNavFlight/inav.git
synced 2025-07-25 17:25:18 +03:00
Merge branch 'master' into avs-fw-autotune
# Conflicts: # docs/Settings.md # src/main/build/debug.h # src/main/fc/settings.yaml
This commit is contained in:
commit
261f0a63c0
22 changed files with 1088 additions and 816 deletions
1081
docs/Settings.md
1081
docs/Settings.md
File diff suppressed because it is too large
Load diff
|
@ -320,6 +320,8 @@ main_sources(COMMON_SRC
|
|||
flight/imu.h
|
||||
flight/kalman.c
|
||||
flight/kalman.h
|
||||
flight/smith_predictor.c
|
||||
flight/smith_predictor.h
|
||||
flight/mixer.c
|
||||
flight/mixer.h
|
||||
flight/pid.c
|
||||
|
|
|
@ -83,6 +83,7 @@ typedef enum {
|
|||
DEBUG_FW_D,
|
||||
DEBUG_IMU2,
|
||||
DEBUG_ALTITUDE,
|
||||
DEBUG_SMITH_COMPENSATOR,
|
||||
DEBUG_AUTOTUNE,
|
||||
DEBUG_COUNT
|
||||
} debugType_e;
|
||||
|
|
|
@ -10,12 +10,11 @@ typedef struct displayFontMetadata_s {
|
|||
uint16_t charCount;
|
||||
} displayFontMetadata_t;
|
||||
|
||||
// 'I', 'N', 'A', 'V', 1
|
||||
// 'I', 'N', 'A', 'V'
|
||||
#define FONT_CHR_IS_METADATA(chr) ((chr)->data[0] == 'I' && \
|
||||
(chr)->data[1] == 'N' && \
|
||||
(chr)->data[2] == 'A' && \
|
||||
(chr)->data[3] == 'V' && \
|
||||
(chr)->data[4] == 1)
|
||||
(chr)->data[3] == 'V')
|
||||
|
||||
#define FONT_METADATA_CHR_INDEX 255
|
||||
// Used for runtime detection of display drivers that might
|
||||
|
|
|
@ -119,8 +119,9 @@
|
|||
#define SYM_RPM 0x8B // 139 RPM
|
||||
#define SYM_WAYPOINT 0x8C // 140 Waypoint
|
||||
#define SYM_AZIMUTH 0x8D // 141 Azimuth
|
||||
// 0x8E // 142 -
|
||||
// 0x8F // 143 -
|
||||
|
||||
#define SYM_TELEMETRY_0 0x8E // 142 Antenna tracking telemetry
|
||||
#define SYM_TELEMETRY_1 0x8F // 143 Antenna tracking telemetry
|
||||
|
||||
#define SYM_BATT_FULL 0x90 // 144 Battery full
|
||||
#define SYM_BATT_5 0x91 // 145 Battery
|
||||
|
@ -153,8 +154,8 @@
|
|||
#define SYM_HEADING 0xA9 // 169 Compass Heading symbol
|
||||
#define SYM_ALT 0xAA // 170 ALT
|
||||
#define SYM_WH 0xAB // 171 WH
|
||||
#define SYM_WH_KM_0 0xAC // 172 WH/KM left
|
||||
#define SYM_WH_KM_1 0xAD // 173 WH/KM right
|
||||
#define SYM_WH_KM 0xAC // 172 WH/KM
|
||||
#define SYM_WH_MI 0xAD // 173 WH/MI
|
||||
#define SYM_WATT 0xAE // 174 W
|
||||
#define SYM_SCALE 0xAF // 175 Map scale
|
||||
#define SYM_MPH 0xB0 // 176 MPH
|
||||
|
|
|
@ -22,21 +22,6 @@
|
|||
#include "config/parameter_group.h"
|
||||
|
||||
#define MAX_CONTROL_RATE_PROFILE_COUNT 3
|
||||
/*
|
||||
Max and min available values for rates are now stored as absolute
|
||||
tenths of degrees-per-second [dsp/10]
|
||||
That means, max. rotation rate 180 equals 1800dps
|
||||
|
||||
New defaults of 200dps for pitch,roll and yaw are more less
|
||||
equivalent of rates 0 from previous versions of iNav, Cleanflight, Baseflight
|
||||
and so on.
|
||||
*/
|
||||
#define CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX 180
|
||||
#define CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN 6
|
||||
#define CONTROL_RATE_CONFIG_YAW_RATE_MAX 180
|
||||
#define CONTROL_RATE_CONFIG_YAW_RATE_MIN 2
|
||||
|
||||
#define CONTROL_RATE_CONFIG_TPA_MAX 100
|
||||
|
||||
typedef struct controlRateConfig_s {
|
||||
|
||||
|
|
|
@ -1799,14 +1799,14 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
|
|||
for (int i = 0; i < 3; i++) {
|
||||
tmp_u8 = sbufReadU8(src);
|
||||
if (i == FD_YAW) {
|
||||
((controlRateConfig_t*)currentControlRateProfile)->stabilized.rates[i] = constrain(tmp_u8, CONTROL_RATE_CONFIG_YAW_RATE_MIN, CONTROL_RATE_CONFIG_YAW_RATE_MAX);
|
||||
((controlRateConfig_t*)currentControlRateProfile)->stabilized.rates[i] = constrain(tmp_u8, SETTING_YAW_RATE_MIN, SETTING_YAW_RATE_MAX);
|
||||
}
|
||||
else {
|
||||
((controlRateConfig_t*)currentControlRateProfile)->stabilized.rates[i] = constrain(tmp_u8, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX);
|
||||
((controlRateConfig_t*)currentControlRateProfile)->stabilized.rates[i] = constrain(tmp_u8, SETTING_CONSTANT_ROLL_PITCH_RATE_MIN, SETTING_CONSTANT_ROLL_PITCH_RATE_MAX);
|
||||
}
|
||||
}
|
||||
tmp_u8 = sbufReadU8(src);
|
||||
((controlRateConfig_t*)currentControlRateProfile)->throttle.dynPID = MIN(tmp_u8, CONTROL_RATE_CONFIG_TPA_MAX);
|
||||
((controlRateConfig_t*)currentControlRateProfile)->throttle.dynPID = MIN(tmp_u8, SETTING_TPA_RATE_MAX);
|
||||
((controlRateConfig_t*)currentControlRateProfile)->throttle.rcMid8 = sbufReadU8(src);
|
||||
((controlRateConfig_t*)currentControlRateProfile)->throttle.rcExpo8 = sbufReadU8(src);
|
||||
((controlRateConfig_t*)currentControlRateProfile)->throttle.pa_breakpoint = sbufReadU16(src);
|
||||
|
@ -1836,9 +1836,9 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
|
|||
for (uint8_t i = 0; i < 3; ++i) {
|
||||
tmp_u8 = sbufReadU8(src);
|
||||
if (i == FD_YAW) {
|
||||
currentControlRateProfile_p->stabilized.rates[i] = constrain(tmp_u8, CONTROL_RATE_CONFIG_YAW_RATE_MIN, CONTROL_RATE_CONFIG_YAW_RATE_MAX);
|
||||
currentControlRateProfile_p->stabilized.rates[i] = constrain(tmp_u8, SETTING_YAW_RATE_MIN, SETTING_YAW_RATE_MAX);
|
||||
} else {
|
||||
currentControlRateProfile_p->stabilized.rates[i] = constrain(tmp_u8, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX);
|
||||
currentControlRateProfile_p->stabilized.rates[i] = constrain(tmp_u8, SETTING_CONSTANT_ROLL_PITCH_RATE_MIN, SETTING_CONSTANT_ROLL_PITCH_RATE_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1848,9 +1848,9 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
|
|||
for (uint8_t i = 0; i < 3; ++i) {
|
||||
tmp_u8 = sbufReadU8(src);
|
||||
if (i == FD_YAW) {
|
||||
currentControlRateProfile_p->manual.rates[i] = constrain(tmp_u8, CONTROL_RATE_CONFIG_YAW_RATE_MIN, CONTROL_RATE_CONFIG_YAW_RATE_MAX);
|
||||
currentControlRateProfile_p->manual.rates[i] = constrain(tmp_u8, SETTING_YAW_RATE_MIN, SETTING_YAW_RATE_MAX);
|
||||
} else {
|
||||
currentControlRateProfile_p->manual.rates[i] = constrain(tmp_u8, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX);
|
||||
currentControlRateProfile_p->manual.rates[i] = constrain(tmp_u8, SETTING_CONSTANT_ROLL_PITCH_RATE_MIN, SETTING_CONSTANT_ROLL_PITCH_RATE_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "fc/controlrate_profile.h"
|
||||
#include "fc/rc_adjustments.h"
|
||||
#include "fc/rc_curves.h"
|
||||
#include "fc/settings.h"
|
||||
|
||||
#include "navigation/navigation.h"
|
||||
|
||||
|
@ -61,15 +62,6 @@ static uint8_t adjustmentStateMask = 0;
|
|||
|
||||
#define IS_ADJUSTMENT_FUNCTION_BUSY(adjustmentIndex) (adjustmentStateMask & (1 << adjustmentIndex))
|
||||
|
||||
#define RC_ADJUSTMENT_EXPO_MIN 0
|
||||
#define RC_ADJUSTMENT_EXPO_MAX 100
|
||||
|
||||
#define RC_ADJUSTMENT_MANUAL_RATE_MIN 0
|
||||
#define RC_ADJUSTMENT_MANUAL_RATE_MAX 100
|
||||
|
||||
#define RC_ADJUSTMENT_PID_MIN 0
|
||||
#define RC_ADJUSTMENT_PID_MAX 200
|
||||
|
||||
// sync with adjustmentFunction_e
|
||||
static const adjustmentConfig_t defaultAdjustmentConfigs[ADJUSTMENT_FUNCTION_COUNT - 1] = {
|
||||
{
|
||||
|
@ -368,17 +360,17 @@ static void applyAdjustmentU16(adjustmentFunction_e adjustmentFunction, uint16_t
|
|||
|
||||
static void applyAdjustmentExpo(adjustmentFunction_e adjustmentFunction, uint8_t *val, int delta)
|
||||
{
|
||||
applyAdjustmentU8(adjustmentFunction, val, delta, RC_ADJUSTMENT_EXPO_MIN, RC_ADJUSTMENT_EXPO_MAX);
|
||||
applyAdjustmentU8(adjustmentFunction, val, delta, SETTING_RC_EXPO_MIN, SETTING_RC_EXPO_MAX);
|
||||
}
|
||||
|
||||
static void applyAdjustmentManualRate(adjustmentFunction_e adjustmentFunction, uint8_t *val, int delta)
|
||||
{
|
||||
return applyAdjustmentU8(adjustmentFunction, val, delta, RC_ADJUSTMENT_MANUAL_RATE_MIN, RC_ADJUSTMENT_MANUAL_RATE_MAX);
|
||||
return applyAdjustmentU8(adjustmentFunction, val, delta, SETTING_CONSTANT_MANUAL_RATE_MIN, SETTING_CONSTANT_MANUAL_RATE_MAX);
|
||||
}
|
||||
|
||||
static void applyAdjustmentPID(adjustmentFunction_e adjustmentFunction, uint16_t *val, int delta)
|
||||
{
|
||||
applyAdjustmentU16(adjustmentFunction, val, delta, RC_ADJUSTMENT_PID_MIN, RC_ADJUSTMENT_PID_MAX);
|
||||
applyAdjustmentU16(adjustmentFunction, val, delta, SETTING_CONSTANT_RPYL_PID_MIN, SETTING_CONSTANT_RPYL_PID_MAX);
|
||||
}
|
||||
|
||||
static void applyStepAdjustment(controlRateConfig_t *controlRateConfig, uint8_t adjustmentFunction, int delta)
|
||||
|
@ -406,7 +398,7 @@ static void applyStepAdjustment(controlRateConfig_t *controlRateConfig, uint8_t
|
|||
break;
|
||||
case ADJUSTMENT_PITCH_ROLL_RATE:
|
||||
case ADJUSTMENT_PITCH_RATE:
|
||||
applyAdjustmentU8(ADJUSTMENT_PITCH_RATE, &controlRateConfig->stabilized.rates[FD_PITCH], delta, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX);
|
||||
applyAdjustmentU8(ADJUSTMENT_PITCH_RATE, &controlRateConfig->stabilized.rates[FD_PITCH], delta, SETTING_PITCH_RATE_MIN, SETTING_PITCH_RATE_MAX);
|
||||
if (adjustmentFunction == ADJUSTMENT_PITCH_RATE) {
|
||||
schedulePidGainsUpdate();
|
||||
break;
|
||||
|
@ -415,7 +407,7 @@ static void applyStepAdjustment(controlRateConfig_t *controlRateConfig, uint8_t
|
|||
FALLTHROUGH;
|
||||
|
||||
case ADJUSTMENT_ROLL_RATE:
|
||||
applyAdjustmentU8(ADJUSTMENT_ROLL_RATE, &controlRateConfig->stabilized.rates[FD_ROLL], delta, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN, CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX);
|
||||
applyAdjustmentU8(ADJUSTMENT_ROLL_RATE, &controlRateConfig->stabilized.rates[FD_ROLL], delta, SETTING_CONSTANT_ROLL_PITCH_RATE_MIN, SETTING_CONSTANT_ROLL_PITCH_RATE_MAX);
|
||||
schedulePidGainsUpdate();
|
||||
break;
|
||||
case ADJUSTMENT_MANUAL_PITCH_ROLL_RATE:
|
||||
|
@ -429,7 +421,7 @@ static void applyStepAdjustment(controlRateConfig_t *controlRateConfig, uint8_t
|
|||
applyAdjustmentManualRate(ADJUSTMENT_MANUAL_PITCH_RATE, &controlRateConfig->manual.rates[FD_PITCH], delta);
|
||||
break;
|
||||
case ADJUSTMENT_YAW_RATE:
|
||||
applyAdjustmentU8(ADJUSTMENT_YAW_RATE, &controlRateConfig->stabilized.rates[FD_YAW], delta, CONTROL_RATE_CONFIG_YAW_RATE_MIN, CONTROL_RATE_CONFIG_YAW_RATE_MAX);
|
||||
applyAdjustmentU8(ADJUSTMENT_YAW_RATE, &controlRateConfig->stabilized.rates[FD_YAW], delta, SETTING_YAW_RATE_MIN, SETTING_YAW_RATE_MAX);
|
||||
schedulePidGainsUpdate();
|
||||
break;
|
||||
case ADJUSTMENT_MANUAL_YAW_RATE:
|
||||
|
@ -508,10 +500,10 @@ static void applyStepAdjustment(controlRateConfig_t *controlRateConfig, uint8_t
|
|||
schedulePidGainsUpdate();
|
||||
break;
|
||||
case ADJUSTMENT_NAV_FW_CRUISE_THR:
|
||||
applyAdjustmentU16(ADJUSTMENT_NAV_FW_CRUISE_THR, &navConfigMutable()->fw.cruise_throttle, delta, 1000, 2000);
|
||||
applyAdjustmentU16(ADJUSTMENT_NAV_FW_CRUISE_THR, &navConfigMutable()->fw.cruise_throttle, delta, SETTING_NAV_FW_CRUISE_THR_MIN, SETTING_NAV_FW_CRUISE_THR_MAX);
|
||||
break;
|
||||
case ADJUSTMENT_NAV_FW_PITCH2THR:
|
||||
applyAdjustmentU8(ADJUSTMENT_NAV_FW_PITCH2THR, &navConfigMutable()->fw.pitch_to_throttle, delta, 0, 100);
|
||||
applyAdjustmentU8(ADJUSTMENT_NAV_FW_PITCH2THR, &navConfigMutable()->fw.pitch_to_throttle, delta, SETTING_NAV_FW_PITCH2THR_MIN, SETTING_NAV_FW_PITCH2THR_MAX);
|
||||
break;
|
||||
case ADJUSTMENT_ROLL_BOARD_ALIGNMENT:
|
||||
updateBoardAlignment(delta, 0);
|
||||
|
@ -586,7 +578,7 @@ static void applyStepAdjustment(controlRateConfig_t *controlRateConfig, uint8_t
|
|||
navigationUsePIDs();
|
||||
break;
|
||||
case ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE:
|
||||
applyAdjustmentU16(ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE, &mixerConfigMutable()->fwMinThrottleDownPitchAngle, delta, 0, FW_MIN_THROTTLE_DOWN_PITCH_ANGLE_MAX);
|
||||
applyAdjustmentU16(ADJUSTMENT_FW_MIN_THROTTLE_DOWN_PITCH_ANGLE, &mixerConfigMutable()->fwMinThrottleDownPitchAngle, delta, SETTING_FW_MIN_THROTTLE_DOWN_PITCH_MIN, SETTING_FW_MIN_THROTTLE_DOWN_PITCH_MAX);
|
||||
break;
|
||||
#if defined(USE_VTX_SMARTAUDIO) || defined(USE_VTX_TRAMP)
|
||||
case ADJUSTMENT_VTX_POWER_LEVEL:
|
||||
|
@ -599,13 +591,13 @@ static void applyStepAdjustment(controlRateConfig_t *controlRateConfig, uint8_t
|
|||
break;
|
||||
#endif
|
||||
case ADJUSTMENT_TPA:
|
||||
applyAdjustmentU8(ADJUSTMENT_TPA, &controlRateConfig->throttle.dynPID, delta, 0, CONTROL_RATE_CONFIG_TPA_MAX);
|
||||
applyAdjustmentU8(ADJUSTMENT_TPA, &controlRateConfig->throttle.dynPID, delta, 0, SETTING_TPA_RATE_MAX);
|
||||
break;
|
||||
case ADJUSTMENT_TPA_BREAKPOINT:
|
||||
applyAdjustmentU16(ADJUSTMENT_TPA_BREAKPOINT, &controlRateConfig->throttle.pa_breakpoint, delta, PWM_RANGE_MIN, PWM_RANGE_MAX);
|
||||
break;
|
||||
case ADJUSTMENT_NAV_FW_CONTROL_SMOOTHNESS:
|
||||
applyAdjustmentU8(ADJUSTMENT_NAV_FW_CONTROL_SMOOTHNESS, &navConfigMutable()->fw.control_smoothness, delta, 0, 9);
|
||||
applyAdjustmentU8(ADJUSTMENT_NAV_FW_CONTROL_SMOOTHNESS, &navConfigMutable()->fw.control_smoothness, delta, SETTING_NAV_FW_CONTROL_SMOOTHNESS_MIN, SETTING_NAV_FW_CONTROL_SMOOTHNESS_MAX);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -69,9 +69,15 @@ tables:
|
|||
- name: osd_stats_energy_unit
|
||||
values: ["MAH", "WH"]
|
||||
enum: osd_stats_energy_unit_e
|
||||
- name: osd_stats_min_voltage_unit
|
||||
values: ["BATTERY", "CELL"]
|
||||
enum: osd_stats_min_voltage_unit_e
|
||||
- name: osd_video_system
|
||||
values: ["AUTO", "PAL", "NTSC"]
|
||||
enum: videoSystem_e
|
||||
- name: osd_telemetry
|
||||
values: ["OFF", "ON","TEST"]
|
||||
enum: osd_telemetry_e
|
||||
- name: osd_alignment
|
||||
values: ["LEFT", "RIGHT"]
|
||||
enum: osd_alignment_e
|
||||
|
@ -87,7 +93,8 @@ tables:
|
|||
"FLOW", "SBUS", "FPORT", "ALWAYS", "SAG_COMP_VOLTAGE",
|
||||
"VIBE", "CRUISE", "REM_FLIGHT_TIME", "SMARTAUDIO", "ACC",
|
||||
"ERPM", "RPM_FILTER", "RPM_FREQ", "NAV_YAW", "DYNAMIC_FILTER", "DYNAMIC_FILTER_FREQUENCY",
|
||||
"IRLOCK", "CD", "KALMAN_GAIN", "PID_MEASUREMENT", "SPM_CELLS", "SPM_VS600", "SPM_VARIO", "PCF8574", "DYN_GYRO_LPF", "FW_D", "IMU2", "ALTITUDE", "AUTOTUNE"]
|
||||
"IRLOCK", "CD", "KALMAN_GAIN", "PID_MEASUREMENT", "SPM_CELLS", "SPM_VS600", "SPM_VARIO", "PCF8574", "DYN_GYRO_LPF", "FW_D", "IMU2", "ALTITUDE",
|
||||
"SMITH_COMPENSATOR", "AUTOTUNE"]
|
||||
- name: async_mode
|
||||
values: ["NONE", "GYRO", "ALL"]
|
||||
- name: aux_operator
|
||||
|
@ -173,6 +180,16 @@ tables:
|
|||
enum: navRTHClimbFirst_e
|
||||
values: ["OFF", "ON", "ON_FW_SPIRAL"]
|
||||
|
||||
constants:
|
||||
RPYL_PID_MIN: 0
|
||||
RPYL_PID_MAX: 200
|
||||
|
||||
MANUAL_RATE_MIN: 0
|
||||
MANUAL_RATE_MAX: 100
|
||||
|
||||
ROLL_PITCH_RATE_MIN: 6
|
||||
ROLL_PITCH_RATE_MAX: 180
|
||||
|
||||
groups:
|
||||
- name: PG_GYRO_CONFIG
|
||||
type: gyroConfig_t
|
||||
|
@ -1203,7 +1220,7 @@ groups:
|
|||
default_value: 0
|
||||
field: throttle.dynPID
|
||||
min: 0
|
||||
max: CONTROL_RATE_CONFIG_TPA_MAX
|
||||
max: 100
|
||||
- name: tpa_breakpoint
|
||||
description: "See tpa_rate."
|
||||
default_value: 1500
|
||||
|
@ -1234,20 +1251,20 @@ groups:
|
|||
description: "Defines rotation rate on ROLL axis that UAV will try to archive on max. stick deflection. Rates are defined in tens of degrees (deca-degrees) per second [rate = dps/10]. That means, rate 20 represents 200dps rotation speed. Default 20 (200dps) is more less equivalent of old Cleanflight/Baseflight rate 0. Max. 180 (1800dps) is what gyro can measure."
|
||||
default_value: 20
|
||||
field: stabilized.rates[FD_ROLL]
|
||||
min: CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN
|
||||
max: CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX
|
||||
min: ROLL_PITCH_RATE_MIN
|
||||
max: ROLL_PITCH_RATE_MAX
|
||||
- name: pitch_rate
|
||||
description: "Defines rotation rate on PITCH axis that UAV will try to archive on max. stick deflection. Rates are defined in tens of degrees (deca-degrees) per second [rate = dps/10]. That means, rate 20 represents 200dps rotation speed. Default 20 (200dps) is more less equivalent of old Cleanflight/Baseflight rate 0. Max. 180 (1800dps) is what gyro can measure."
|
||||
default_value: 20
|
||||
field: stabilized.rates[FD_PITCH]
|
||||
min: CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MIN
|
||||
max: CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX
|
||||
min: ROLL_PITCH_RATE_MIN
|
||||
max: ROLL_PITCH_RATE_MAX
|
||||
- name: yaw_rate
|
||||
description: "Defines rotation rate on YAW axis that UAV will try to archive on max. stick deflection. Rates are defined in tens of degrees (deca-degrees) per second [rate = dps/10]. That means, rate 20 represents 200dps rotation speed. Default 20 (200dps) is more less equivalent of old Cleanflight/Baseflight rate 0. Max. 180 (1800dps) is what gyro can measure."
|
||||
default_value: 20
|
||||
field: stabilized.rates[FD_YAW]
|
||||
min: CONTROL_RATE_CONFIG_YAW_RATE_MIN
|
||||
max: CONTROL_RATE_CONFIG_YAW_RATE_MAX
|
||||
min: 2
|
||||
max: 180
|
||||
- name: manual_rc_expo
|
||||
description: "Exposition value used for the PITCH/ROLL axes by the `MANUAL` flight mode [0-100]"
|
||||
default_value: 70
|
||||
|
@ -1264,20 +1281,20 @@ groups:
|
|||
description: "Servo travel multiplier for the ROLL axis in `MANUAL` flight mode [0-100]%"
|
||||
default_value: 100
|
||||
field: manual.rates[FD_ROLL]
|
||||
min: 0
|
||||
max: 100
|
||||
min: MANUAL_RATE_MIN
|
||||
max: MANUAL_RATE_MAX
|
||||
- name: manual_pitch_rate
|
||||
description: "Servo travel multiplier for the PITCH axis in `MANUAL` flight mode [0-100]%"
|
||||
default_value: 100
|
||||
field: manual.rates[FD_PITCH]
|
||||
min: 0
|
||||
max: 100
|
||||
min: MANUAL_RATE_MIN
|
||||
max: MANUAL_RATE_MAX
|
||||
- name: manual_yaw_rate
|
||||
description: "Servo travel multiplier for the YAW axis in `MANUAL` flight mode [0-100]%"
|
||||
default_value: 100
|
||||
field: manual.rates[FD_YAW]
|
||||
min: 0
|
||||
max: 100
|
||||
min: MANUAL_RATE_MIN
|
||||
max: MANUAL_RATE_MAX
|
||||
- name: fpv_mix_degrees
|
||||
field: misc.fpvCamAngleDegrees
|
||||
min: 0
|
||||
|
@ -1498,182 +1515,182 @@ groups:
|
|||
description: "Multicopter rate stabilisation P-gain for PITCH"
|
||||
default_value: 40
|
||||
field: bank_mc.pid[PID_PITCH].P
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_i_pitch
|
||||
description: "Multicopter rate stabilisation I-gain for PITCH"
|
||||
default_value: 30
|
||||
field: bank_mc.pid[PID_PITCH].I
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_d_pitch
|
||||
description: "Multicopter rate stabilisation D-gain for PITCH"
|
||||
default_value: 23
|
||||
field: bank_mc.pid[PID_PITCH].D
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_cd_pitch
|
||||
description: "Multicopter Control Derivative gain for PITCH"
|
||||
default_value: 60
|
||||
field: bank_mc.pid[PID_PITCH].FF
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_p_roll
|
||||
description: "Multicopter rate stabilisation P-gain for ROLL"
|
||||
default_value: 40
|
||||
field: bank_mc.pid[PID_ROLL].P
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_i_roll
|
||||
description: "Multicopter rate stabilisation I-gain for ROLL"
|
||||
default_value: 30
|
||||
field: bank_mc.pid[PID_ROLL].I
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_d_roll
|
||||
description: "Multicopter rate stabilisation D-gain for ROLL"
|
||||
default_value: 23
|
||||
field: bank_mc.pid[PID_ROLL].D
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_cd_roll
|
||||
description: "Multicopter Control Derivative gain for ROLL"
|
||||
default_value: 60
|
||||
field: bank_mc.pid[PID_ROLL].FF
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_p_yaw
|
||||
description: "Multicopter rate stabilisation P-gain for YAW"
|
||||
default_value: 85
|
||||
field: bank_mc.pid[PID_YAW].P
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_i_yaw
|
||||
description: "Multicopter rate stabilisation I-gain for YAW"
|
||||
default_value: 45
|
||||
field: bank_mc.pid[PID_YAW].I
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_d_yaw
|
||||
description: "Multicopter rate stabilisation D-gain for YAW"
|
||||
default_value: 0
|
||||
field: bank_mc.pid[PID_YAW].D
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_cd_yaw
|
||||
description: "Multicopter Control Derivative gain for YAW"
|
||||
default_value: 60
|
||||
field: bank_mc.pid[PID_YAW].FF
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_p_level
|
||||
description: "Multicopter attitude stabilisation P-gain"
|
||||
default_value: 20
|
||||
field: bank_mc.pid[PID_LEVEL].P
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_i_level
|
||||
description: "Multicopter attitude stabilisation low-pass filter cutoff"
|
||||
default_value: 15
|
||||
field: bank_mc.pid[PID_LEVEL].I
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: mc_d_level
|
||||
description: "Multicopter attitude stabilisation HORIZON transition point"
|
||||
default_value: 75
|
||||
field: bank_mc.pid[PID_LEVEL].D
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_p_pitch
|
||||
description: "Fixed-wing rate stabilisation P-gain for PITCH"
|
||||
default_value: 5
|
||||
field: bank_fw.pid[PID_PITCH].P
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_i_pitch
|
||||
description: "Fixed-wing rate stabilisation I-gain for PITCH"
|
||||
default_value: 7
|
||||
field: bank_fw.pid[PID_PITCH].I
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_d_pitch
|
||||
description: "Fixed wing rate stabilisation D-gain for PITCH"
|
||||
default_value: 0
|
||||
field: bank_fw.pid[PID_PITCH].D
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_ff_pitch
|
||||
description: "Fixed-wing rate stabilisation FF-gain for PITCH"
|
||||
default_value: 50
|
||||
field: bank_fw.pid[PID_PITCH].FF
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_p_roll
|
||||
description: "Fixed-wing rate stabilisation P-gain for ROLL"
|
||||
default_value: 5
|
||||
field: bank_fw.pid[PID_ROLL].P
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_i_roll
|
||||
description: "Fixed-wing rate stabilisation I-gain for ROLL"
|
||||
default_value: 7
|
||||
field: bank_fw.pid[PID_ROLL].I
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_d_roll
|
||||
description: "Fixed wing rate stabilisation D-gain for ROLL"
|
||||
default_value: 0
|
||||
field: bank_fw.pid[PID_ROLL].D
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_ff_roll
|
||||
description: "Fixed-wing rate stabilisation FF-gain for ROLL"
|
||||
default_value: 50
|
||||
field: bank_fw.pid[PID_ROLL].FF
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_p_yaw
|
||||
description: "Fixed-wing rate stabilisation P-gain for YAW"
|
||||
default_value: 6
|
||||
field: bank_fw.pid[PID_YAW].P
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_i_yaw
|
||||
description: "Fixed-wing rate stabilisation I-gain for YAW"
|
||||
default_value: 10
|
||||
field: bank_fw.pid[PID_YAW].I
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_d_yaw
|
||||
description: "Fixed wing rate stabilisation D-gain for YAW"
|
||||
default_value: 0
|
||||
field: bank_fw.pid[PID_YAW].D
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_ff_yaw
|
||||
description: "Fixed-wing rate stabilisation FF-gain for YAW"
|
||||
default_value: 60
|
||||
field: bank_fw.pid[PID_YAW].FF
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_p_level
|
||||
description: "Fixed-wing attitude stabilisation P-gain"
|
||||
default_value: 20
|
||||
field: bank_fw.pid[PID_LEVEL].P
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_i_level
|
||||
description: "Fixed-wing attitude stabilisation low-pass filter cutoff"
|
||||
default_value: 5
|
||||
field: bank_fw.pid[PID_LEVEL].I
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: fw_d_level
|
||||
description: "Fixed-wing attitude stabilisation HORIZON transition point"
|
||||
default_value: 75
|
||||
field: bank_fw.pid[PID_LEVEL].D
|
||||
min: 0
|
||||
max: 200
|
||||
min: RPYL_PID_MIN
|
||||
max: RPYL_PID_MAX
|
||||
- name: max_angle_inclination_rll
|
||||
description: "Maximum inclination in level (angle) mode (ROLL axis). 100=10°"
|
||||
default_value: 300
|
||||
|
@ -2048,6 +2065,27 @@ groups:
|
|||
field: fixedWingLevelTrim
|
||||
min: -10
|
||||
max: 10
|
||||
- name: smith_predictor_strength
|
||||
description: "The strength factor of a Smith Predictor of PID measurement. In percents"
|
||||
default_value: 0.5
|
||||
field: smithPredictorStrength
|
||||
condition: USE_SMITH_PREDICTOR
|
||||
min: 0
|
||||
max: 1
|
||||
- name: smith_predictor_delay
|
||||
description: "Expected delay of the gyro signal. In milliseconds"
|
||||
default_value: 0
|
||||
field: smithPredictorDelay
|
||||
condition: USE_SMITH_PREDICTOR
|
||||
min: 0
|
||||
max: 8
|
||||
- name: smith_predictor_lpf_hz
|
||||
description: "Cutoff frequency for the Smith Predictor Low Pass Filter"
|
||||
default_value: 50
|
||||
field: smithPredictorFilterHz
|
||||
condition: USE_SMITH_PREDICTOR
|
||||
min: 1
|
||||
max: 500
|
||||
|
||||
- name: PG_PID_AUTOTUNE_CONFIG
|
||||
type: pidAutotuneConfig_t
|
||||
|
@ -2902,6 +2940,12 @@ groups:
|
|||
headers: ["io/osd.h", "drivers/osd.h"]
|
||||
condition: USE_OSD
|
||||
members:
|
||||
- name: osd_telemetry
|
||||
description: "To enable OSD telemetry for antenna tracker. Possible values are `OFF`, `ON` and `TEST`"
|
||||
table: osd_telemetry
|
||||
field: telemetry
|
||||
type: uint8_t
|
||||
default_value: "OFF"
|
||||
- name: osd_video_system
|
||||
description: "Video system used. Possible values are `AUTO`, `PAL` and `NTSC`"
|
||||
default_value: "AUTO"
|
||||
|
@ -2926,6 +2970,12 @@ groups:
|
|||
field: stats_energy_unit
|
||||
table: osd_stats_energy_unit
|
||||
type: uint8_t
|
||||
- name: osd_stats_min_voltage_unit
|
||||
description: "Display minimum voltage of the `BATTERY` or the average per `CELL` in the OSD stats."
|
||||
default_value: "BATTERY"
|
||||
field: stats_min_voltage_unit
|
||||
table: osd_stats_min_voltage_unit
|
||||
type: uint8_t
|
||||
|
||||
- name: osd_rssi_alarm
|
||||
description: "Value below which to make the OSD RSSI indicator blink"
|
||||
|
|
|
@ -25,11 +25,6 @@
|
|||
#define MAX_SUPPORTED_MOTORS 12
|
||||
#endif
|
||||
|
||||
#define YAW_JUMP_PREVENTION_LIMIT_LOW 80
|
||||
#define YAW_JUMP_PREVENTION_LIMIT_HIGH 500
|
||||
|
||||
#define FW_MIN_THROTTLE_DOWN_PITCH_ANGLE_MAX 450
|
||||
|
||||
// Digital protocol has fixed values
|
||||
#define DSHOT_DISARM_COMMAND 0
|
||||
#define DSHOT_MIN_THROTTLE 48
|
||||
|
|
|
@ -48,6 +48,7 @@ FILE_COMPILE_FOR_SPEED
|
|||
#include "flight/rpm_filter.h"
|
||||
#include "flight/secondary_imu.h"
|
||||
#include "flight/kalman.h"
|
||||
#include "flight/smith_predictor.h"
|
||||
|
||||
#include "io/gps.h"
|
||||
|
||||
|
@ -109,6 +110,8 @@ typedef struct {
|
|||
bool itermFreezeActive;
|
||||
|
||||
biquadFilter_t rateTargetFilter;
|
||||
|
||||
smithPredictor_t smithPredictor;
|
||||
} pidState_t;
|
||||
|
||||
STATIC_FASTRAM bool pidFiltersConfigured = false;
|
||||
|
@ -159,7 +162,7 @@ static EXTENDED_FASTRAM filterApplyFnPtr dTermLpf2FilterApplyFn;
|
|||
static EXTENDED_FASTRAM bool levelingEnabled = false;
|
||||
static EXTENDED_FASTRAM float fixedWingLevelTrim;
|
||||
|
||||
PG_REGISTER_PROFILE_WITH_RESET_TEMPLATE(pidProfile_t, pidProfile, PG_PID_PROFILE, 1);
|
||||
PG_REGISTER_PROFILE_WITH_RESET_TEMPLATE(pidProfile_t, pidProfile, PG_PID_PROFILE, 2);
|
||||
|
||||
PG_RESET_TEMPLATE(pidProfile_t, pidProfile,
|
||||
.bank_mc = {
|
||||
|
@ -297,6 +300,12 @@ PG_RESET_TEMPLATE(pidProfile_t, pidProfile,
|
|||
#endif
|
||||
|
||||
.fixedWingLevelTrim = SETTING_FW_LEVEL_PITCH_TRIM_DEFAULT,
|
||||
|
||||
#ifdef USE_SMITH_PREDICTOR
|
||||
.smithPredictorStrength = SETTING_SMITH_PREDICTOR_STRENGTH_DEFAULT,
|
||||
.smithPredictorDelay = SETTING_SMITH_PREDICTOR_DELAY_DEFAULT,
|
||||
.smithPredictorFilterHz = SETTING_SMITH_PREDICTOR_LPF_HZ_DEFAULT,
|
||||
#endif
|
||||
);
|
||||
|
||||
bool pidInitFilters(void)
|
||||
|
@ -349,6 +358,30 @@ bool pidInitFilters(void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_SMITH_PREDICTOR
|
||||
smithPredictorInit(
|
||||
&pidState[FD_ROLL].smithPredictor,
|
||||
pidProfile()->smithPredictorDelay,
|
||||
pidProfile()->smithPredictorStrength,
|
||||
pidProfile()->smithPredictorFilterHz,
|
||||
getLooptime()
|
||||
);
|
||||
smithPredictorInit(
|
||||
&pidState[FD_PITCH].smithPredictor,
|
||||
pidProfile()->smithPredictorDelay,
|
||||
pidProfile()->smithPredictorStrength,
|
||||
pidProfile()->smithPredictorFilterHz,
|
||||
getLooptime()
|
||||
);
|
||||
smithPredictorInit(
|
||||
&pidState[FD_YAW].smithPredictor,
|
||||
pidProfile()->smithPredictorDelay,
|
||||
pidProfile()->smithPredictorStrength,
|
||||
pidProfile()->smithPredictorFilterHz,
|
||||
getLooptime()
|
||||
);
|
||||
#endif
|
||||
|
||||
pidFiltersConfigured = true;
|
||||
|
||||
return true;
|
||||
|
@ -1052,6 +1085,13 @@ void FAST_CODE pidController(float dT)
|
|||
pidState[axis].gyroRate = gyroKalmanUpdate(axis, pidState[axis].gyroRate, pidState[axis].rateTarget);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SMITH_PREDICTOR
|
||||
DEBUG_SET(DEBUG_SMITH_COMPENSATOR, axis, pidState[axis].gyroRate);
|
||||
pidState[axis].gyroRate = applySmithPredictor(axis, &pidState[axis].smithPredictor, pidState[axis].gyroRate);
|
||||
DEBUG_SET(DEBUG_SMITH_COMPENSATOR, axis + 3, pidState[axis].gyroRate);
|
||||
#endif
|
||||
|
||||
DEBUG_SET(DEBUG_PID_MEASUREMENT, axis, pidState[axis].gyroRate);
|
||||
}
|
||||
|
||||
|
|
|
@ -161,6 +161,11 @@ typedef struct pidProfile_s {
|
|||
#endif
|
||||
|
||||
float fixedWingLevelTrim;
|
||||
#ifdef USE_SMITH_PREDICTOR
|
||||
float smithPredictorStrength;
|
||||
float smithPredictorDelay;
|
||||
uint16_t smithPredictorFilterHz;
|
||||
#endif
|
||||
} pidProfile_t;
|
||||
|
||||
typedef struct pidAutotuneConfig_s {
|
||||
|
|
70
src/main/flight/smith_predictor.c
Normal file
70
src/main/flight/smith_predictor.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* This file is part of INAV Project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU General Public License Version 3, as described below:
|
||||
*
|
||||
* This file is free software: you may copy, redistribute and/or modify
|
||||
* it 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.
|
||||
*
|
||||
* This file is distributed in the hope that it 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 program. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This code is a derivative of work done in EmuFlight Project https://github.com/emuflight/EmuFlight
|
||||
*
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#ifdef USE_SMITH_PREDICTOR
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "common/axis.h"
|
||||
#include "common/utils.h"
|
||||
#include "flight/smith_predictor.h"
|
||||
#include "build/debug.h"
|
||||
|
||||
FUNCTION_COMPILE_FOR_SPEED
|
||||
float applySmithPredictor(uint8_t axis, smithPredictor_t *predictor, float sample) {
|
||||
UNUSED(axis);
|
||||
if (predictor->enabled) {
|
||||
predictor->data[predictor->idx] = sample;
|
||||
|
||||
predictor->idx++;
|
||||
if (predictor->idx > predictor->samples) {
|
||||
predictor->idx = 0;
|
||||
}
|
||||
|
||||
// filter the delayed data to help reduce the overall noise this prediction adds
|
||||
float delayed = pt1FilterApply(&predictor->smithPredictorFilter, predictor->data[predictor->idx]);
|
||||
float delayCompensatedSample = predictor->smithPredictorStrength * (sample - delayed);
|
||||
|
||||
sample += delayCompensatedSample;
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
|
||||
FUNCTION_COMPILE_FOR_SIZE
|
||||
void smithPredictorInit(smithPredictor_t *predictor, float delay, float strength, uint16_t filterLpfHz, uint32_t looptime) {
|
||||
if (delay > 0.1) {
|
||||
predictor->enabled = true;
|
||||
predictor->samples = (delay * 1000) / looptime;
|
||||
predictor->idx = 0;
|
||||
predictor->smithPredictorStrength = strength;
|
||||
pt1FilterInit(&predictor->smithPredictorFilter, filterLpfHz, looptime * 1e-6f);
|
||||
} else {
|
||||
predictor->enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
45
src/main/flight/smith_predictor.h
Normal file
45
src/main/flight/smith_predictor.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This file is part of INAV Project.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU General Public License Version 3, as described below:
|
||||
*
|
||||
* This file is free software: you may copy, redistribute and/or modify
|
||||
* it 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.
|
||||
*
|
||||
* This file is distributed in the hope that it 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 program. If not, see http://www.gnu.org/licenses/.
|
||||
*
|
||||
* This code is a derivative of work done in EmuFlight Project https://github.com/emuflight/EmuFlight
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common/filter.h"
|
||||
|
||||
#define MAX_SMITH_SAMPLES 64
|
||||
|
||||
typedef struct smithPredictor_s {
|
||||
bool enabled;
|
||||
uint8_t samples;
|
||||
uint8_t idx;
|
||||
float data[MAX_SMITH_SAMPLES + 1];
|
||||
pt1Filter_t smithPredictorFilter;
|
||||
float smithPredictorStrength;
|
||||
} smithPredictor_t;
|
||||
|
||||
float applySmithPredictor(uint8_t axis, smithPredictor_t *predictor, float sample);
|
||||
void smithPredictorInit(smithPredictor_t *predictor, float delay, float strength, uint16_t filterLpfHz, uint32_t looptime);
|
|
@ -144,7 +144,7 @@ FILE_COMPILE_FOR_SPEED
|
|||
#define OSD_CENTER_LEN(x) ((osdDisplayPort->cols - x) / 2)
|
||||
#define OSD_CENTER_S(s) OSD_CENTER_LEN(strlen(s))
|
||||
|
||||
#define OSD_MIN_FONT_VERSION 1
|
||||
#define OSD_MIN_FONT_VERSION 2
|
||||
|
||||
static unsigned currentLayout = 0;
|
||||
static int layoutOverride = -1;
|
||||
|
@ -193,7 +193,7 @@ static bool osdDisplayHasCanvas;
|
|||
|
||||
#define AH_MAX_PITCH_DEFAULT 20 // Specify default maximum AHI pitch value displayed (degrees)
|
||||
|
||||
PG_REGISTER_WITH_RESET_TEMPLATE(osdConfig_t, osdConfig, PG_OSD_CONFIG, 15);
|
||||
PG_REGISTER_WITH_RESET_TEMPLATE(osdConfig_t, osdConfig, PG_OSD_CONFIG, 0);
|
||||
PG_REGISTER_WITH_RESET_FN(osdLayoutsConfig_t, osdLayoutsConfig, PG_OSD_LAYOUTS_CONFIG, 0);
|
||||
|
||||
static int digitCount(int32_t value)
|
||||
|
@ -534,7 +534,7 @@ static uint16_t osdConvertRSSI(void)
|
|||
return constrain(getRSSI() * 100 / RSSI_MAX_VALUE, 0, 99);
|
||||
}
|
||||
|
||||
static uint16_t osdGetLQ(void)
|
||||
static uint16_t osdGetCrsfLQ(void)
|
||||
{
|
||||
int16_t statsLQ = rxLinkStatistics.uplinkLQ;
|
||||
int16_t scaledLQ = scaleRange(constrain(statsLQ, 0, 100), 0, 100, 170, 300);
|
||||
|
@ -545,7 +545,7 @@ static uint16_t osdGetLQ(void)
|
|||
}
|
||||
}
|
||||
|
||||
static uint16_t osdGetdBm(void)
|
||||
static int16_t osdGetCrsfdBm(void)
|
||||
{
|
||||
return rxLinkStatistics.uplinkRSSI;
|
||||
}
|
||||
|
@ -1183,6 +1183,67 @@ static void osdDrawRadar(uint16_t *drawn, uint32_t *usedScale)
|
|||
osdDrawMap(reference, 0, SYM_ARROW_UP, GPS_distanceToHome, poiDirection, SYM_HOME, drawn, usedScale);
|
||||
}
|
||||
|
||||
static uint16_t crc_accumulate(uint8_t data, uint16_t crcAccum)
|
||||
{
|
||||
uint8_t tmp;
|
||||
tmp = data ^ (uint8_t)(crcAccum & 0xff);
|
||||
tmp ^= (tmp << 4);
|
||||
crcAccum = (crcAccum >> 8) ^ (tmp << 8) ^ (tmp << 3) ^ (tmp >> 4);
|
||||
return crcAccum;
|
||||
}
|
||||
|
||||
|
||||
static void osdDisplayTelemetry(void)
|
||||
{
|
||||
uint32_t trk_data;
|
||||
uint16_t trk_crc = 0;
|
||||
char trk_buffer[31];
|
||||
static int16_t trk_elevation = 127;
|
||||
static uint16_t trk_bearing = 0;
|
||||
|
||||
if (ARMING_FLAG(ARMED)) {
|
||||
if (STATE(GPS_FIX)){
|
||||
if (GPS_distanceToHome > 5) {
|
||||
trk_bearing = GPS_directionToHome;
|
||||
trk_bearing += 360 + 180;
|
||||
trk_bearing %= 360;
|
||||
int32_t alt = CENTIMETERS_TO_METERS(osdGetAltitude());
|
||||
float at = atan2(alt, GPS_distanceToHome);
|
||||
trk_elevation = (float)at * 57.2957795; // 57.2957795 = 1 rad
|
||||
trk_elevation += 37; // because elevation in telemetry should be from -37 to 90
|
||||
if (trk_elevation < 0) {
|
||||
trk_elevation = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
trk_elevation = 127;
|
||||
trk_bearing = 0;
|
||||
}
|
||||
|
||||
trk_data = 0; // bit 0 - packet type 0 = bearing/elevation, 1 = 2 byte data packet
|
||||
trk_data = trk_data | (uint32_t)(0x7F & trk_elevation) << 1; // bits 1-7 - elevation angle to target. NOTE number is abused. constrained value of -37 to 90 sent as 0 to 127.
|
||||
trk_data = trk_data | (uint32_t)trk_bearing << 8; // bits 8-17 - bearing angle to target. 0 = true north. 0 to 360
|
||||
trk_crc = crc_accumulate(0xFF & trk_data, trk_crc); // CRC First Byte bits 0-7
|
||||
trk_crc = crc_accumulate(0xFF & trk_bearing, trk_crc); // CRC Second Byte bits 8-15
|
||||
trk_crc = crc_accumulate(trk_bearing >> 8, trk_crc); // CRC Third Byte bits 16-17
|
||||
trk_data = trk_data | (uint32_t)trk_crc << 17; // bits 18-29 CRC & 0x3FFFF
|
||||
|
||||
for (uint8_t t_ctr = 0; t_ctr < 30; t_ctr++) { // Prepare screen buffer and write data line.
|
||||
if (trk_data & (uint32_t)1 << t_ctr){
|
||||
trk_buffer[29 - t_ctr] = SYM_TELEMETRY_0;
|
||||
}
|
||||
else{
|
||||
trk_buffer[29 - t_ctr] = SYM_TELEMETRY_1;
|
||||
}
|
||||
}
|
||||
trk_buffer[30] = 0;
|
||||
displayWrite(osdDisplayPort, 0, 0, trk_buffer);
|
||||
if (osdConfig()->telemetry>1){
|
||||
displayWrite(osdDisplayPort, 0, 3, trk_buffer); // Test display because normal telemetry line is not visible
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void osdFormatPidControllerOutput(char *buff, const char *label, const pidController_t *pidController, uint8_t scale, bool showDecimal) {
|
||||
|
@ -1710,7 +1771,7 @@ static bool osdDrawSingleElement(uint8_t item)
|
|||
else if (FLIGHT_MODE(MANUAL_MODE))
|
||||
p = "MANU";
|
||||
else if (FLIGHT_MODE(NAV_RTH_MODE))
|
||||
p = "RTH ";
|
||||
p = isWaypointMissionRTHActive() ? "WRTH" : "RTH ";
|
||||
else if (FLIGHT_MODE(NAV_POSHOLD_MODE))
|
||||
p = "HOLD";
|
||||
else if (FLIGHT_MODE(NAV_COURSE_HOLD_MODE) && FLIGHT_MODE(NAV_ALTHOLD_MODE))
|
||||
|
@ -2304,9 +2365,8 @@ static bool osdDrawSingleElement(uint8_t item)
|
|||
} else {
|
||||
buff[0] = buff[1] = buff[2] = '-';
|
||||
}
|
||||
buff[3] = SYM_WH_KM_0;
|
||||
buff[4] = SYM_WH_KM_1;
|
||||
buff[5] = '\0';
|
||||
buff[3] = SYM_WH_KM;
|
||||
buff[4] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2692,8 +2752,11 @@ void osdDrawNextElement(void)
|
|||
elementIndex = osdIncElementIndex(elementIndex);
|
||||
} while(!osdDrawSingleElement(elementIndex) && index != elementIndex);
|
||||
|
||||
// Draw artificial horizon last
|
||||
// Draw artificial horizon + tracking telemtry last
|
||||
osdDrawSingleElement(OSD_ARTIFICIAL_HORIZON);
|
||||
if (osdConfig()->telemetry>0){
|
||||
osdDisplayTelemetry();
|
||||
}
|
||||
}
|
||||
|
||||
PG_RESET_TEMPLATE(osdConfig_t, osdConfig,
|
||||
|
@ -2774,7 +2837,8 @@ PG_RESET_TEMPLATE(osdConfig_t, osdConfig,
|
|||
|
||||
.force_grid = SETTING_OSD_FORCE_GRID_DEFAULT,
|
||||
|
||||
.stats_energy_unit = SETTING_OSD_STATS_ENERGY_UNIT_DEFAULT
|
||||
.stats_energy_unit = SETTING_OSD_STATS_ENERGY_UNIT_DEFAULT,
|
||||
.stats_min_voltage_unit = SETTING_OSD_STATS_MIN_VOLTAGE_UNIT_DEFAULT
|
||||
);
|
||||
|
||||
void pgResetFn_osdLayoutsConfig(osdLayoutsConfig_t *osdLayoutsConfig)
|
||||
|
@ -3023,9 +3087,8 @@ static void osdCompleteAsyncInitialization(void)
|
|||
osdFormatCentiNumber(string_buffer, avg_efficiency / 10, 0, 2, 0, 3);
|
||||
} else
|
||||
strcpy(string_buffer, "---");
|
||||
string_buffer[3] = SYM_WH_KM_0;
|
||||
string_buffer[4] = SYM_WH_KM_1;
|
||||
string_buffer[5] = '\0';
|
||||
string_buffer[3] = SYM_WH_KM;
|
||||
string_buffer[4] = '\0';
|
||||
displayWrite(osdDisplayPort, STATS_VALUE_X_POS-3, y, string_buffer);
|
||||
}
|
||||
#endif // USE_ADC
|
||||
|
@ -3095,11 +3158,11 @@ static void osdUpdateStats(void)
|
|||
if (stats.min_rssi > value)
|
||||
stats.min_rssi = value;
|
||||
|
||||
value = osdGetLQ();
|
||||
value = osdGetCrsfLQ();
|
||||
if (stats.min_lq > value)
|
||||
stats.min_lq = value;
|
||||
|
||||
value = osdGetdBm();
|
||||
value = osdGetCrsfdBm();
|
||||
if (stats.min_rssi_dbm > value)
|
||||
stats.min_rssi_dbm = value;
|
||||
|
||||
|
@ -3185,8 +3248,13 @@ static void osdShowStatsPage2(void)
|
|||
|
||||
displayWrite(osdDisplayPort, statNameX, top++, "--- STATS --- <- 2/2");
|
||||
|
||||
if (osdConfig()->stats_min_voltage_unit == OSD_STATS_MIN_VOLTAGE_UNIT_BATTERY) {
|
||||
displayWrite(osdDisplayPort, statNameX, top, "MIN BATTERY VOLT :");
|
||||
osdFormatCentiNumber(buff, stats.min_voltage, 0, osdConfig()->main_voltage_decimals, 0, osdConfig()->main_voltage_decimals + 2);
|
||||
} else {
|
||||
displayWrite(osdDisplayPort, statNameX, top, "MIN CELL VOLTAGE :");
|
||||
osdFormatCentiNumber(buff, stats.min_voltage/getBatteryCellCount(), 0, 2, 0, 3);
|
||||
}
|
||||
tfp_sprintf(buff, "%s%c", buff, SYM_VOLT);
|
||||
displayWrite(osdDisplayPort, statValuesX, top++, buff);
|
||||
|
||||
|
@ -3220,9 +3288,8 @@ static void osdShowStatsPage2(void)
|
|||
SYM_MAH_KM_0, SYM_MAH_KM_1);
|
||||
else {
|
||||
osdFormatCentiNumber(buff, getMWhDrawn() * 10000 / totalDistance, 0, 2, 0, 3);
|
||||
buff[3] = SYM_WH_KM_0;
|
||||
buff[4] = SYM_WH_KM_1;
|
||||
buff[5] = '\0';
|
||||
buff[3] = SYM_WH_KM;
|
||||
buff[4] = '\0';
|
||||
}
|
||||
// If traveled distance is less than 100 meters efficiency numbers are useless and unreliable so display --- instead
|
||||
if (totalDistance < 10000) {
|
||||
|
@ -3232,9 +3299,8 @@ static void osdShowStatsPage2(void)
|
|||
buff[4] = SYM_MAH_KM_1;
|
||||
buff[5] = '\0';
|
||||
} else {
|
||||
buff[3] = SYM_WH_KM_0;
|
||||
buff[4] = SYM_WH_KM_1;
|
||||
buff[5] = '\0';
|
||||
buff[3] = SYM_WH_KM;
|
||||
buff[4] = '\0';
|
||||
}
|
||||
}
|
||||
displayWrite(osdDisplayPort, statValuesX, top++, buff);
|
||||
|
@ -3610,6 +3676,11 @@ textAttributes_t osdGetSystemMessage(char *buff, size_t buff_size, bool isCenter
|
|||
}
|
||||
} else {
|
||||
if (FLIGHT_MODE(NAV_RTH_MODE) || FLIGHT_MODE(NAV_WP_MODE) || navigationIsExecutingAnEmergencyLanding()) {
|
||||
if (isWaypointMissionRTHActive()) {
|
||||
// if RTH activated whilst WP mode selected, remind pilot to cancel WP mode to exit RTH
|
||||
messages[messageCount++] = OSD_MESSAGE_STR(OSD_MSG_WP_RTH_CANCEL);
|
||||
}
|
||||
|
||||
if (NAV_Status.state == MW_NAV_STATE_WP_ENROUTE) {
|
||||
// Countdown display for remaining Waypoints
|
||||
tfp_sprintf(messageBuf, "TO WP %u/%u", posControl.activeWaypointIndex + 1, posControl.waypointCount);
|
||||
|
|
8
src/main/io/osd.h
Executable file → Normal file
8
src/main/io/osd.h
Executable file → Normal file
|
@ -87,6 +87,7 @@
|
|||
#define OSD_MSG_HOLDING_WAYPOINT "HOLDING WAYPOINT"
|
||||
#define OSD_MSG_TO_WP "TO WP"
|
||||
#define OSD_MSG_PREPARE_NEXT_WP "PREPARING FOR NEXT WAYPOINT"
|
||||
#define OSD_MSG_WP_RTH_CANCEL "CANCEL WP MODE TO EXIT RTH"
|
||||
#define OSD_MSG_EMERG_LANDING "EMERGENCY LANDING"
|
||||
#define OSD_MSG_LANDING "LANDING"
|
||||
#define OSD_MSG_LOITERING_HOME "LOITERING AROUND HOME"
|
||||
|
@ -243,6 +244,11 @@ typedef enum {
|
|||
OSD_STATS_ENERGY_UNIT_WH,
|
||||
} osd_stats_energy_unit_e;
|
||||
|
||||
typedef enum {
|
||||
OSD_STATS_MIN_VOLTAGE_UNIT_BATTERY,
|
||||
OSD_STATS_MIN_VOLTAGE_UNIT_CELL,
|
||||
} osd_stats_min_voltage_unit_e;
|
||||
|
||||
typedef enum {
|
||||
OSD_CROSSHAIRS_STYLE_DEFAULT,
|
||||
OSD_CROSSHAIRS_STYLE_AIRCRAFT,
|
||||
|
@ -339,6 +345,7 @@ typedef struct osdConfig_s {
|
|||
|
||||
uint8_t units; // from osd_unit_e
|
||||
uint8_t stats_energy_unit; // from osd_stats_energy_unit_e
|
||||
uint8_t stats_min_voltage_unit; // from osd_stats_min_voltage_unit_e
|
||||
|
||||
#ifdef USE_WIND_ESTIMATOR
|
||||
bool estimations_wind_compensation; // use wind compensation for estimated remaining flight/distance
|
||||
|
@ -362,6 +369,7 @@ typedef struct osdConfig_s {
|
|||
uint8_t pan_servo_index; // Index of the pan servo used for home direction offset
|
||||
int8_t pan_servo_pwm2centideg; // Centidegrees of servo rotation per us pwm
|
||||
uint8_t crsf_lq_format;
|
||||
uint8_t telemetry; // use telemetry on displayed pixel line 0
|
||||
|
||||
} osdConfig_t;
|
||||
|
||||
|
|
89
src/main/navigation/navigation.c
Executable file → Normal file
89
src/main/navigation/navigation.c
Executable file → Normal file
|
@ -238,6 +238,7 @@ void calculateNewCruiseTarget(fpVector3_t * origin, int32_t yaw, int32_t distanc
|
|||
static bool isWaypointPositionReached(const fpVector3_t * pos, const bool isWaypointHome);
|
||||
static void mapWaypointToLocalPosition(fpVector3_t * localPos, const navWaypoint_t * waypoint);
|
||||
static navigationFSMEvent_t nextForNonGeoStates(void);
|
||||
static bool isWaypointMissionValid(void);
|
||||
|
||||
void initializeRTHSanityChecker(const fpVector3_t * pos);
|
||||
bool validateRTHSanityChecker(void);
|
||||
|
@ -273,7 +274,6 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_HOLD_TIME(navi
|
|||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_NEXT(navigationFSMState_t previousState);
|
||||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_FINISHED(navigationFSMState_t previousState);
|
||||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_RTH_LAND(navigationFSMState_t previousState);
|
||||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_HOVER_ABOVE_HOME(navigationFSMState_t previousState);
|
||||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_INITIALIZE(navigationFSMState_t previousState);
|
||||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_IN_PROGRESS(navigationFSMState_t previousState);
|
||||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_FINISHED(navigationFSMState_t previousState);
|
||||
|
@ -669,6 +669,7 @@ static const navigationFSMStateDescriptor_t navFSM[NAV_STATE_COUNT] = {
|
|||
[NAV_FSM_EVENT_SUCCESS] = NAV_STATE_WAYPOINT_IN_PROGRESS,
|
||||
[NAV_FSM_EVENT_ERROR] = NAV_STATE_IDLE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_IDLE] = NAV_STATE_IDLE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_RTH] = NAV_STATE_RTH_INITIALIZE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_FINISHED] = NAV_STATE_WAYPOINT_FINISHED,
|
||||
}
|
||||
},
|
||||
|
@ -708,7 +709,6 @@ static const navigationFSMStateDescriptor_t navFSM[NAV_STATE_COUNT] = {
|
|||
[NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_HOLD_TIME] = NAV_STATE_WAYPOINT_HOLD_TIME,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_FINISHED] = NAV_STATE_WAYPOINT_FINISHED,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_RTH_LAND] = NAV_STATE_WAYPOINT_RTH_LAND,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_HOVER_ABOVE_HOME] = NAV_STATE_WAYPOINT_HOVER_ABOVE_HOME,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_IDLE] = NAV_STATE_IDLE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_ALTHOLD] = NAV_STATE_ALTHOLD_INITIALIZE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D] = NAV_STATE_POSHOLD_3D_INITIALIZE,
|
||||
|
@ -794,27 +794,6 @@ static const navigationFSMStateDescriptor_t navFSM[NAV_STATE_COUNT] = {
|
|||
}
|
||||
},
|
||||
|
||||
[NAV_STATE_WAYPOINT_HOVER_ABOVE_HOME] = {
|
||||
.persistentId = NAV_PERSISTENT_ID_WAYPOINT_HOVER_ABOVE_HOME,
|
||||
.onEntry = navOnEnteringState_NAV_STATE_WAYPOINT_HOVER_ABOVE_HOME,
|
||||
.timeoutMs = 10,
|
||||
.stateFlags = NAV_CTL_ALT | NAV_CTL_POS | NAV_CTL_YAW | NAV_CTL_LAND | NAV_REQUIRE_ANGLE | NAV_REQUIRE_MAGHOLD | NAV_REQUIRE_THRTILT | NAV_AUTO_WP,
|
||||
.mapToFlightModes = NAV_WP_MODE | NAV_ALTHOLD_MODE,
|
||||
.mwState = MW_NAV_STATE_HOVER_ABOVE_HOME,
|
||||
.mwError = MW_NAV_ERROR_NONE,
|
||||
.onEvent = {
|
||||
[NAV_FSM_EVENT_TIMEOUT] = NAV_STATE_WAYPOINT_HOVER_ABOVE_HOME, // re-process state
|
||||
[NAV_FSM_EVENT_SUCCESS] = NAV_STATE_WAYPOINT_FINISHED,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_IDLE] = NAV_STATE_IDLE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_ALTHOLD] = NAV_STATE_ALTHOLD_INITIALIZE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_POSHOLD_3D] = NAV_STATE_POSHOLD_3D_INITIALIZE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_RTH] = NAV_STATE_RTH_INITIALIZE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING] = NAV_STATE_EMERGENCY_LANDING_INITIALIZE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_COURSE_HOLD] = NAV_STATE_COURSE_HOLD_INITIALIZE,
|
||||
[NAV_FSM_EVENT_SWITCH_TO_CRUISE] = NAV_STATE_CRUISE_INITIALIZE,
|
||||
}
|
||||
},
|
||||
|
||||
/** EMERGENCY LANDING ************************************************/
|
||||
[NAV_STATE_EMERGENCY_LANDING_INITIALIZE] = {
|
||||
.persistentId = NAV_PERSISTENT_ID_EMERGENCY_LANDING_INITIALIZE,
|
||||
|
@ -1331,18 +1310,11 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_RTH_HOVER_PRIOR_TO_LAND
|
|||
|
||||
// If position ok OR within valid timeout - continue
|
||||
if ((posControl.flags.estPosStatus >= EST_USABLE) || !checkForPositionSensorTimeout()) {
|
||||
|
||||
// Wait until target heading is reached (with 15 deg margin for error)
|
||||
if (STATE(FIXED_WING_LEGACY)) {
|
||||
// Wait until target heading is reached for MR (with 15 deg margin for error), or continue for Fixed Wing
|
||||
if ((ABS(wrap_18000(posControl.rthState.homePosition.yaw - posControl.actualState.yaw)) < DEGREES_TO_CENTIDEGREES(15)) || STATE(FIXED_WING_LEGACY)) {
|
||||
resetLandingDetector();
|
||||
updateClimbRateToAltitudeController(0, ROC_TO_ALT_RESET);
|
||||
return navigationRTHAllowsLanding() ? NAV_FSM_EVENT_SUCCESS : NAV_FSM_EVENT_SWITCH_TO_RTH_HOVER_ABOVE_HOME;
|
||||
}
|
||||
else {
|
||||
if (ABS(wrap_18000(posControl.rthState.homePosition.yaw - posControl.actualState.yaw)) < DEGREES_TO_CENTIDEGREES(15)) {
|
||||
resetLandingDetector();
|
||||
updateClimbRateToAltitudeController(0, ROC_TO_ALT_RESET);
|
||||
return navigationRTHAllowsLanding() ? NAV_FSM_EVENT_SUCCESS : NAV_FSM_EVENT_SWITCH_TO_RTH_HOVER_ABOVE_HOME;
|
||||
return navigationRTHAllowsLanding() ? NAV_FSM_EVENT_SUCCESS : NAV_FSM_EVENT_SWITCH_TO_RTH_HOVER_ABOVE_HOME; // success = land
|
||||
}
|
||||
else if (!validateRTHSanityChecker()) {
|
||||
// Continue to check for RTH sanity during pre-landing hover
|
||||
|
@ -1353,8 +1325,6 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_RTH_HOVER_PRIOR_TO_LAND
|
|||
setDesiredPosition(tmpHomePos, posControl.rthState.homePosition.yaw, NAV_POS_UPDATE_XY | NAV_POS_UPDATE_Z | NAV_POS_UPDATE_HEADING);
|
||||
return NAV_FSM_EVENT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING;
|
||||
}
|
||||
|
@ -1549,10 +1519,7 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_PRE_ACTION(nav
|
|||
return nextForNonGeoStates();
|
||||
|
||||
case NAV_WP_ACTION_RTH:
|
||||
posControl.rthState.rthInitialDistance = posControl.homeDistance;
|
||||
initializeRTHSanityChecker(&navGetCurrentActualPositionAndVelocity()->pos);
|
||||
calculateAndSetActiveWaypointToLocalPosition(rthGetHomeTargetPosition(RTH_HOME_ENROUTE_INITIAL));
|
||||
return NAV_FSM_EVENT_SUCCESS; // will switch to NAV_STATE_WAYPOINT_IN_PROGRESS
|
||||
return NAV_FSM_EVENT_SWITCH_TO_RTH;
|
||||
};
|
||||
|
||||
UNREACHABLE();
|
||||
|
@ -1598,21 +1565,8 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_IN_PROGRESS(na
|
|||
case NAV_WP_ACTION_JUMP:
|
||||
case NAV_WP_ACTION_SET_HEAD:
|
||||
case NAV_WP_ACTION_SET_POI:
|
||||
UNREACHABLE();
|
||||
|
||||
case NAV_WP_ACTION_RTH:
|
||||
if (isWaypointReached(&posControl.activeWaypoint, true) || isWaypointMissed(&posControl.activeWaypoint)) {
|
||||
return NAV_FSM_EVENT_SUCCESS; // will switch to NAV_STATE_WAYPOINT_REACHED
|
||||
}
|
||||
else {
|
||||
if(navConfig()->general.flags.rth_tail_first && !STATE(FIXED_WING_LEGACY))
|
||||
setDesiredPosition(&posControl.activeWaypoint.pos, 0, NAV_POS_UPDATE_XY | NAV_POS_UPDATE_BEARING_TAIL_FIRST);
|
||||
else
|
||||
setDesiredPosition(&posControl.activeWaypoint.pos, 0, NAV_POS_UPDATE_XY | NAV_POS_UPDATE_BEARING);
|
||||
setDesiredPosition(rthGetHomeTargetPosition(RTH_HOME_ENROUTE_PROPORTIONAL), 0, NAV_POS_UPDATE_Z);
|
||||
return NAV_FSM_EVENT_NONE; // will re-process state in >10ms
|
||||
}
|
||||
break;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
/* No pos sensor available for NAV_WAIT_FOR_GPS_TIMEOUT_MS - land */
|
||||
|
@ -1637,15 +1591,8 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_REACHED(naviga
|
|||
case NAV_WP_ACTION_JUMP:
|
||||
case NAV_WP_ACTION_SET_HEAD:
|
||||
case NAV_WP_ACTION_SET_POI:
|
||||
UNREACHABLE();
|
||||
|
||||
case NAV_WP_ACTION_RTH:
|
||||
if (posControl.waypointList[posControl.activeWaypointIndex].p1 != 0) {
|
||||
return NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_RTH_LAND;
|
||||
}
|
||||
else {
|
||||
return NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_HOVER_ABOVE_HOME;
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
||||
case NAV_WP_ACTION_LAND:
|
||||
return NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_RTH_LAND;
|
||||
|
@ -1725,14 +1672,6 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_FINISHED(navig
|
|||
}
|
||||
}
|
||||
|
||||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_HOVER_ABOVE_HOME(navigationFSMState_t previousState)
|
||||
{
|
||||
UNUSED(previousState);
|
||||
|
||||
const navigationFSMEvent_t hoverEvent = navOnEnteringState_NAV_STATE_RTH_HOVER_ABOVE_HOME(previousState);
|
||||
return hoverEvent;
|
||||
}
|
||||
|
||||
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_EMERGENCY_LANDING_INITIALIZE(navigationFSMState_t previousState)
|
||||
{
|
||||
// TODO:
|
||||
|
@ -3656,6 +3595,11 @@ rthState_e getStateOfForcedRTH(void)
|
|||
}
|
||||
}
|
||||
|
||||
bool isWaypointMissionRTHActive(void)
|
||||
{
|
||||
return FLIGHT_MODE(NAV_RTH_MODE) && IS_RC_MODE_ACTIVE(BOXNAVWP) && !(IS_RC_MODE_ACTIVE(BOXNAVRTH) || posControl.flags.forcedRTHActivated);
|
||||
}
|
||||
|
||||
bool navigationIsExecutingAnEmergencyLanding(void)
|
||||
{
|
||||
return navGetCurrentStateFlags() & NAV_CTL_EMERG;
|
||||
|
@ -3681,9 +3625,12 @@ bool navigationIsFlyingAutonomousMode(void)
|
|||
|
||||
bool navigationRTHAllowsLanding(void)
|
||||
{
|
||||
if (posControl.waypointList[posControl.activeWaypointIndex].action == NAV_WP_ACTION_LAND)
|
||||
return true;
|
||||
// WP mission RTH landing setting
|
||||
if (isWaypointMissionRTHActive() && isWaypointMissionValid()) {
|
||||
return posControl.waypointList[posControl.waypointCount - 1].p1 > 0;
|
||||
}
|
||||
|
||||
// normal RTH landing setting
|
||||
navRTHAllowLanding_e allow = navConfig()->general.flags.rth_allow_landing;
|
||||
return allow == NAV_RTH_ALLOW_LANDING_ALWAYS ||
|
||||
(allow == NAV_RTH_ALLOW_LANDING_FS_ONLY && FLIGHT_MODE(FAILSAFE_MODE));
|
||||
|
|
|
@ -520,6 +520,7 @@ bool navigationIsExecutingAnEmergencyLanding(void);
|
|||
* or if it's NAV_RTH_ALLOW_LANDING_FAILSAFE and failsafe mode is active.
|
||||
*/
|
||||
bool navigationRTHAllowsLanding(void);
|
||||
bool isWaypointMissionRTHActive(void);
|
||||
|
||||
bool isNavLaunchEnabled(void);
|
||||
bool isFixedWingLaunchDetected(void);
|
||||
|
|
|
@ -141,7 +141,6 @@ typedef enum {
|
|||
NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_RTH_LAND = NAV_FSM_EVENT_STATE_SPECIFIC_1,
|
||||
NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_FINISHED = NAV_FSM_EVENT_STATE_SPECIFIC_2,
|
||||
NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_HOLD_TIME = NAV_FSM_EVENT_STATE_SPECIFIC_3,
|
||||
NAV_FSM_EVENT_SWITCH_TO_WAYPOINT_HOVER_ABOVE_HOME,
|
||||
|
||||
NAV_FSM_EVENT_SWITCH_TO_COURSE_HOLD,
|
||||
NAV_FSM_EVENT_SWITCH_TO_CRUISE,
|
||||
|
@ -200,7 +199,7 @@ typedef enum {
|
|||
|
||||
NAV_PERSISTENT_ID_WAYPOINT_HOLD_TIME = 35,
|
||||
NAV_PERSISTENT_ID_RTH_HOVER_ABOVE_HOME = 36,
|
||||
NAV_PERSISTENT_ID_WAYPOINT_HOVER_ABOVE_HOME = 37,
|
||||
NAV_PERSISTENT_ID_UNUSED_4 = 37, // was NAV_STATE_WAYPOINT_HOVER_ABOVE_HOME
|
||||
|
||||
} navigationPersistentId_e;
|
||||
|
||||
|
@ -232,7 +231,6 @@ typedef enum {
|
|||
NAV_STATE_WAYPOINT_NEXT,
|
||||
NAV_STATE_WAYPOINT_FINISHED,
|
||||
NAV_STATE_WAYPOINT_RTH_LAND,
|
||||
NAV_STATE_WAYPOINT_HOVER_ABOVE_HOME,
|
||||
|
||||
NAV_STATE_EMERGENCY_LANDING_INITIALIZE,
|
||||
NAV_STATE_EMERGENCY_LANDING_IN_PROGRESS,
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
|
||||
#define USE_DYNAMIC_FILTERS
|
||||
#define USE_GYRO_KALMAN
|
||||
#define USE_SMITH_PREDICTOR
|
||||
#define USE_EXTENDED_CMS_MENUS
|
||||
#define USE_HOTT_TEXTMODE
|
||||
|
||||
|
|
|
@ -301,6 +301,7 @@ class Generator
|
|||
|
||||
check_member_default_values_presence
|
||||
sanitize_fields
|
||||
resolv_min_max_and_default_values_if_possible
|
||||
initialize_name_encoder
|
||||
initialize_value_encoder
|
||||
validate_default_values
|
||||
|
@ -359,6 +360,7 @@ class Generator
|
|||
@data = YAML.load_file(@settings_file)
|
||||
|
||||
initialize_tables
|
||||
initialize_constants
|
||||
check_conditions
|
||||
end
|
||||
|
||||
|
@ -415,6 +417,11 @@ class Generator
|
|||
buf << "extern const char * const #{table_variable_name(name)}[];\n"
|
||||
end
|
||||
|
||||
# Write setting constants from settings file
|
||||
@constants.each do |name, value|
|
||||
buf << "#define SETTING_CONSTANT_#{name.upcase} #{value.inspect}\n"
|
||||
end
|
||||
|
||||
# Write #define'd constants for referencing each setting
|
||||
ii = 0
|
||||
foreach_enabled_member do |group, member|
|
||||
|
@ -715,6 +722,10 @@ class Generator
|
|||
end
|
||||
end
|
||||
|
||||
def initialize_constants
|
||||
@constants = @data["constants"]
|
||||
end
|
||||
|
||||
def ordered_table_names
|
||||
@enabled_tables.to_a().sort()
|
||||
end
|
||||
|
@ -877,6 +888,8 @@ class Generator
|
|||
foreach_enabled_member do |_, member|
|
||||
name = member["name"]
|
||||
type = member["type"]
|
||||
min = member["min"] || 0
|
||||
max = member["max"]
|
||||
default_value = member["default_value"]
|
||||
|
||||
next if %i[ zero target ].include? default_value
|
||||
|
@ -894,13 +907,17 @@ class Generator
|
|||
unsigned = !$~[:unsigned].empty?
|
||||
bitsize = $~[:bitsize].to_i
|
||||
type_range = unsigned ? 0..(2**bitsize-1) : (-2**(bitsize-1)+1)..(2**(bitsize-1)-1)
|
||||
raise "Numeric member #{name} doesn't have maximum value defined" unless member.has_key? 'max'
|
||||
min = type_range.min if min =~ /\AU?INT\d+_MIN\Z/
|
||||
max = type_range.max if max =~ /\AU?INT\d+_MAX\Z/
|
||||
raise "Member #{name} default value has an invalid type, integer or symbol expected" unless default_value.is_a? Integer or default_value.is_a? Symbol
|
||||
raise "Member #{name} default value is outside type's storage range, min #{type_range.min}, max #{type_range.max}" unless default_value.is_a? Symbol or type_range === default_value
|
||||
raise "Numeric member #{name} doesn't have maximum value defined" unless member.has_key? 'max'
|
||||
raise "Member #{name} default value is outside of the allowed range" if default_value.is_a? Numeric and min.is_a? Numeric and max.is_a? Numeric and not (min..max) === default_value
|
||||
|
||||
when type == "float"
|
||||
raise "Numeric member #{name} doesn't have maximum value defined" unless member.has_key? 'max'
|
||||
raise "Member #{name} default value has an invalid type, numeric or symbol expected" unless default_value.is_a? Numeric or default_value.is_a? Symbol
|
||||
raise "Numeric member #{name} doesn't have maximum value defined" unless member.has_key? 'max'
|
||||
raise "Member #{name} default value is outside of the allowed range" if default_value.is_a? Numeric and min.is_a? Numeric and max.is_a? Numeric and not (min..max) === default_value
|
||||
|
||||
when type == "string"
|
||||
max = member["max"].to_i
|
||||
|
@ -1041,6 +1058,18 @@ class Generator
|
|||
raise "Missing default value for #{missing_default_value_names.count} member#{"s" unless missing_default_value_names.one?}: #{missing_default_value_names * ", "}" unless missing_default_value_names.empty?
|
||||
end
|
||||
|
||||
def resolv_min_max_and_default_values_if_possible
|
||||
foreach_member do |_, member|
|
||||
%w[ min max default_value ].each do |value_type|
|
||||
member_value = member[value_type]
|
||||
if member_value.is_a? String
|
||||
constant_value = @constants[member_value]
|
||||
member[value_type] = constant_value unless constant_value.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_constants(constants)
|
||||
return nil unless constants.length > 0
|
||||
s = Set.new
|
||||
|
|
|
@ -22,6 +22,16 @@ DEFAULTS_BLACKLIST = [
|
|||
'serialrx_provider',
|
||||
]
|
||||
|
||||
MIN_MAX_REPLACEMENTS = {
|
||||
'INT16_MIN': -32768,
|
||||
'INT16_MAX': 32767,
|
||||
'INT32_MIN': -2147483648,
|
||||
'INT32_MAX': 2147483647,
|
||||
'UINT8_MAX': 255,
|
||||
'UINT16_MAX': 65535,
|
||||
'UINT32_MAX': 4294967295,
|
||||
}
|
||||
|
||||
def parse_settings_yaml():
|
||||
"""Parse the YAML settings specs"""
|
||||
|
||||
|
@ -32,42 +42,59 @@ def generate_md_table_from_yaml(settings_yaml):
|
|||
"""Generate a sorted markdown table with description & default value for each setting"""
|
||||
params = {}
|
||||
|
||||
# Extract description and default value of each setting from the YAML specs (if present)
|
||||
# Extract description, default/min/max values of each setting from the YAML specs (if present)
|
||||
for group in settings_yaml['groups']:
|
||||
for member in group['members']:
|
||||
if not any(key in member for key in ["description", "default_value"]) and not options.quiet:
|
||||
print("Setting \"{}\" has no description or default value specified".format(member['name']))
|
||||
# Handle edge cases of YAML autogeneration
|
||||
if "default_value" in member:
|
||||
if not any(key in member for key in ["description", "default_value", "min", "max"]) and not options.quiet:
|
||||
print("Setting \"{}\" has an incomplete specification".format(member['name']))
|
||||
|
||||
# Handle default/min/max fields for each setting
|
||||
for key in ["default_value", "min", "max"]:
|
||||
# Basing on the check above, not all fields may be present
|
||||
if key in member:
|
||||
### Fetch actual values from the `constants` block if present
|
||||
if ('constants' in settings_yaml) and (member[key] in settings_yaml['constants']):
|
||||
member[key] = settings_yaml['constants'][member[key]]
|
||||
### Fetch actual values from hardcoded min/max replacements
|
||||
elif member[key] in MIN_MAX_REPLACEMENTS:
|
||||
member[key] = MIN_MAX_REPLACEMENTS[member[key]]
|
||||
|
||||
### Handle edge cases of YAML autogeneration and prettify some values
|
||||
# Replace booleans with "ON"/"OFF"
|
||||
if type(member["default_value"]) == bool:
|
||||
member["default_value"] = "ON" if member["default_value"] else "OFF"
|
||||
if type(member[key]) == bool:
|
||||
member[key] = "ON" if member[key] else "OFF"
|
||||
# Replace zero placeholder with actual zero
|
||||
elif member["default_value"] == ":zero":
|
||||
member["default_value"] = 0
|
||||
elif member[key] == ":zero":
|
||||
member[key] = 0
|
||||
# Replace target-default placeholder with extended definition
|
||||
elif member["default_value"] == ":target":
|
||||
member["default_value"] = "_target default_"
|
||||
elif member[key] == ":target":
|
||||
member[key] = "_target default_"
|
||||
# Replace empty strings with more evident marker
|
||||
elif member["default_value"] == "":
|
||||
member["default_value"] = "_empty_"
|
||||
elif member[key] == "":
|
||||
member[key] = "_empty_"
|
||||
# Reformat direct code references
|
||||
elif str(member["default_value"])[0] == ":":
|
||||
member["default_value"] = f'`{member["default_value"][1:]}`'
|
||||
elif str(member[key])[0] == ":":
|
||||
member[key] = f'`{member[key][1:]}`'
|
||||
|
||||
|
||||
params[member['name']] = {
|
||||
"description": member["description"] if "description" in member else "",
|
||||
"default": member["default_value"] if "default_value" in member else ""
|
||||
"default": member["default_value"] if "default_value" in member else "",
|
||||
"min": member["min"] if "min" in member else "",
|
||||
"max": member["max"] if "max" in member else ""
|
||||
}
|
||||
|
||||
# MD table header
|
||||
md_table_lines = [
|
||||
"| Variable Name | Default Value | Description |\n",
|
||||
"| ------------- | ------------- | ----------- |\n",
|
||||
"| Variable Name | Default Value | Min | Max | Description |\n",
|
||||
"| ------------- | ------------- | --- | --- | ----------- |\n",
|
||||
]
|
||||
|
||||
# Sort the settings by name and build the rows of the table
|
||||
for param in sorted(params.items()):
|
||||
md_table_lines.append("| {} | {} | {} |\n".format(param[0], param[1]['default'], param[1]['description']))
|
||||
md_table_lines.append("| {} | {} | {} | {} | {} |\n".format(
|
||||
param[0], param[1]['default'], param[1]['min'], param[1]['max'], param[1]['description']
|
||||
))
|
||||
|
||||
# Return the assembled table
|
||||
return md_table_lines
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue