mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-24 00:35:39 +03:00
Added non PID airplane flight control system (AFCS) as special flight mode for airplanes
This commit is contained in:
parent
9eb7d1920b
commit
125cb1f4cc
13 changed files with 163 additions and 3 deletions
|
@ -178,6 +178,7 @@ COMMON_SRC = \
|
|||
flight/rpm_filter.c \
|
||||
flight/servos.c \
|
||||
flight/servos_tricopter.c \
|
||||
flight/airplane_fcs.c \
|
||||
io/serial_4way.c \
|
||||
io/serial_4way_avrootloader.c \
|
||||
io/serial_4way_stk500v2.c \
|
||||
|
@ -451,6 +452,7 @@ SPEED_OPTIMISED_SRC += \
|
|||
flight/mixer.c \
|
||||
flight/pid.c \
|
||||
flight/rpm_filter.c \
|
||||
flight/airplane_fcs.c \
|
||||
rx/ibus.c \
|
||||
rx/rc_stats.c \
|
||||
rx/rx.c \
|
||||
|
|
|
@ -1403,6 +1403,20 @@ const clivalue_t valueTable[] = {
|
|||
{ PARAM_NAME_ANGLE_PITCH_OFFSET, VAR_INT16 | PROFILE_VALUE, .config.minmaxUnsigned = { -ANGLE_PITCH_OFFSET_MAX, ANGLE_PITCH_OFFSET_MAX }, PG_PID_PROFILE, offsetof(pidProfile_t, angle_pitch_offset) },
|
||||
#endif
|
||||
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
{ PARAM_NAME_AFCS_PITCH_STICK_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_pitch_stick_gain) },
|
||||
{ PARAM_NAME_AFCS_PITCH_DAMPING_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 1000 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_pitch_damping_gain) },
|
||||
{ PARAM_NAME_AFCS_PITCH_DAMPING_FILTER_TIME, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 3000 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_pitch_damping_filter_time) },
|
||||
{ PARAM_NAME_AFCS_PITCH_STABILITY_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 20 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_pitch_stability_gain) },
|
||||
|
||||
{ PARAM_NAME_AFCS_ROLL_STICK_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_roll_stick_gain) },
|
||||
{ PARAM_NAME_AFCS_ROLL_DAMPING_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 250 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_roll_damping_gain) },
|
||||
|
||||
{ PARAM_NAME_AFCS_YAW_STICK_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_yaw_stick_gain) },
|
||||
{ PARAM_NAME_AFCS_YAW_DAMPING_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 1000 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_yaw_damping_gain) },
|
||||
{ PARAM_NAME_AFCS_YAW_DAMPING_FILTER_TIME, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 3000 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_yaw_damping_filter_time) },
|
||||
{ PARAM_NAME_AFCS_YAW_STABILITY_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 20 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_yaw_stability_gain) },
|
||||
#endif
|
||||
// PG_TELEMETRY_CONFIG
|
||||
#ifdef USE_TELEMETRY
|
||||
{ "tlm_inverted", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_TELEMETRY_CONFIG, offsetof(telemetryConfig_t, telemetry_inverted) },
|
||||
|
|
|
@ -1148,6 +1148,13 @@ void processRxModes(timeUs_t currentTimeUs)
|
|||
DISABLE_FLIGHT_MODE(PASSTHRU_MODE);
|
||||
}
|
||||
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
if (IS_RC_MODE_ACTIVE(BOXAIRPLANEFCS)) {
|
||||
ENABLE_FLIGHT_MODE(AIRPLANE_FCS_MODE);
|
||||
} else {
|
||||
DISABLE_FLIGHT_MODE(AIRPLANE_FCS_MODE);
|
||||
}
|
||||
#endif
|
||||
if (mixerConfig()->mixerMode == MIXER_FLYING_WING || mixerConfig()->mixerMode == MIXER_AIRPLANE) {
|
||||
DISABLE_FLIGHT_MODE(HEADFREE_MODE);
|
||||
}
|
||||
|
|
|
@ -276,3 +276,16 @@
|
|||
#ifdef USE_MAG
|
||||
#define PARAM_NAME_IMU_MAG_DECLINATION "mag_declination"
|
||||
#endif
|
||||
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
#define PARAM_NAME_AFCS_PITCH_STICK_GAIN "afcs_pitch_stick_gain"
|
||||
#define PARAM_NAME_AFCS_PITCH_DAMPING_GAIN "afcs_pitch_damping_gain"
|
||||
#define PARAM_NAME_AFCS_PITCH_DAMPING_FILTER_TIME "afcs_pitch_damping_filter_time"
|
||||
#define PARAM_NAME_AFCS_PITCH_STABILITY_GAIN "afcs_pitch_stability_gain"
|
||||
#define PARAM_NAME_AFCS_ROLL_STICK_GAIN "afcs_roll_stick_gain"
|
||||
#define PARAM_NAME_AFCS_ROLL_DAMPING_GAIN "afcs_roll_damping_gain"
|
||||
#define PARAM_NAME_AFCS_YAW_STICK_GAIN "afcs_yaw_stick_gain"
|
||||
#define PARAM_NAME_AFCS_YAW_DAMPING_GAIN "afcs_yaw_damping_gain"
|
||||
#define PARAM_NAME_AFCS_YAW_DAMPING_FILTER_TIME "afcs_yaw_damping_filter_time"
|
||||
#define PARAM_NAME_AFCS_YAW_STABILITY_GAIN "afcs_yaw_stability_gain"
|
||||
#endif
|
|
@ -40,7 +40,8 @@ typedef enum {
|
|||
BOXFAILSAFE,
|
||||
BOXPOSHOLD,
|
||||
BOXGPSRESCUE,
|
||||
BOXID_FLIGHTMODE_LAST = BOXGPSRESCUE,
|
||||
BOXAIRPLANEFCS,
|
||||
BOXID_FLIGHTMODE_LAST = BOXAIRPLANEFCS,
|
||||
|
||||
// When new flight modes are added, the parameter group version for 'modeActivationConditions' in src/main/fc/rc_modes.c has to be incremented to ensure that the RC modes configuration is reset.
|
||||
|
||||
|
|
|
@ -91,7 +91,8 @@ typedef enum {
|
|||
PASSTHRU_MODE = (1 << 8),
|
||||
// RANGEFINDER_MODE= (1 << 9),
|
||||
FAILSAFE_MODE = (1 << 10),
|
||||
GPS_RESCUE_MODE = (1 << 11)
|
||||
GPS_RESCUE_MODE = (1 << 11),
|
||||
AIRPLANE_FCS_MODE = (1 << 12)
|
||||
} flightModeFlags_e;
|
||||
|
||||
extern uint16_t flightModeFlags;
|
||||
|
@ -113,6 +114,7 @@ extern uint16_t flightModeFlags;
|
|||
[BOXPASSTHRU] = LOG2(PASSTHRU_MODE), \
|
||||
[BOXFAILSAFE] = LOG2(FAILSAFE_MODE), \
|
||||
[BOXGPSRESCUE] = LOG2(GPS_RESCUE_MODE), \
|
||||
[BOXAIRPLANEFCS] = LOG2(AIRPLANE_FCS_MODE), \
|
||||
} \
|
||||
/**/
|
||||
|
||||
|
|
64
src/main/flight/airplane_fcs.c
Normal file
64
src/main/flight/airplane_fcs.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifdef USE_AIRPLANE_FCS
|
||||
#include "fc/rc.h"
|
||||
#include "sensors/acceleration.h"
|
||||
#include "sensors/gyro.h"
|
||||
|
||||
void afcsInit(const pidProfile_t *pidProfile)
|
||||
{
|
||||
pt1FilterInit(&pidRuntime.afcsPitchDampingLowpass, pt1FilterGainFromDelay(pidProfile->afcs_pitch_damping_filter_time * 0.001f, pidRuntime.dT));
|
||||
pt1FilterInit(&pidRuntime.afcsYawDampingLowpass, pt1FilterGainFromDelay(pidProfile->afcs_yaw_damping_filter_time * 0.001f, pidRuntime.dT));
|
||||
}
|
||||
|
||||
void FAST_CODE afcsUpdate(const pidProfile_t *pidProfile, timeUs_t currentTimeUs)
|
||||
{
|
||||
UNUSED(currentTimeUs);
|
||||
for (int axis = FD_ROLL; axis <= FD_YAW; ++axis) {
|
||||
pidData[axis].P = 0;
|
||||
pidData[axis].I = 0;
|
||||
pidData[axis].D = 0;
|
||||
pidData[axis].F = 0;
|
||||
pidData[axis].S = 0;
|
||||
pidData[axis].Sum = 0;
|
||||
}
|
||||
|
||||
// Pitch channel
|
||||
float pitchPilotCtrl = getSetpointRate(FD_PITCH) / getMaxRcRate(FD_PITCH) * pidProfile->afcs_pitch_stick_gain;
|
||||
float gyroPitch = gyro.gyroADCf[FD_PITCH];
|
||||
float gyroPitchLow = pt1FilterApply(&pidRuntime.afcsPitchDampingLowpass, gyroPitch);
|
||||
float gyroPitchHigh = gyroPitch - gyroPitchLow;
|
||||
float pitchDampingCtrl = -1.0f * gyroPitchHigh * (pidProfile->afcs_pitch_damping_gain * 0.001f);
|
||||
float pitchStabilityCtrl = (acc.accADC.z - 1.0f) * (pidProfile->afcs_pitch_stability_gain * 0.01f);
|
||||
pidData[FD_PITCH].Sum = pitchPilotCtrl + pitchDampingCtrl + pitchStabilityCtrl;
|
||||
pidData[FD_PITCH].Sum = constrainf(pidData[FD_PITCH].Sum, -100.0f, 100.0f) / 100.0f * 500.0f;
|
||||
|
||||
// Save control components instead of PID to get logging without additional variables
|
||||
pidData[FD_PITCH].F = 10.0f * pitchPilotCtrl;
|
||||
pidData[FD_PITCH].D = 10.0f * pitchDampingCtrl;
|
||||
pidData[FD_PITCH].P = 10.0f * pitchStabilityCtrl;
|
||||
|
||||
// Roll channel
|
||||
float rollPilotCtrl = getSetpointRate(FD_ROLL) / getMaxRcRate(FD_ROLL) * (pidProfile->afcs_roll_stick_gain);
|
||||
float rollDampingCtrl = -1.0f * gyro.gyroADCf[FD_ROLL] * (pidProfile->afcs_roll_damping_gain * 0.001f);
|
||||
pidData[FD_ROLL].Sum = rollPilotCtrl + rollDampingCtrl;
|
||||
pidData[FD_ROLL].Sum = constrainf(pidData[FD_ROLL].Sum, -100.0f, 100.0f) / 100.0f * 500.0f;
|
||||
|
||||
// Save control components instead of PID to get logging without additional variables
|
||||
pidData[FD_ROLL].F = 10.0f * rollPilotCtrl;
|
||||
pidData[FD_ROLL].D = 10.0f * rollDampingCtrl;
|
||||
|
||||
// Yaw channel
|
||||
float yawPilotCtrl = getSetpointRate(FD_YAW) / getMaxRcRate(FD_YAW) * (pidProfile->afcs_yaw_stick_gain);
|
||||
float gyroYaw = gyro.gyroADCf[FD_YAW];
|
||||
float gyroYawLow = pt1FilterApply(&pidRuntime.afcsYawDampingLowpass, gyroYaw);
|
||||
float gyroYawHigh = gyroYaw - gyroYawLow;
|
||||
float yawDampingCtrl = gyroYawHigh * (pidProfile->afcs_yaw_damping_gain * 0.001f);
|
||||
float yawStabilityCtrl = acc.accADC.y * (pidProfile->afcs_yaw_stability_gain * 0.01f);
|
||||
pidData[FD_YAW].Sum = yawPilotCtrl + yawDampingCtrl + yawStabilityCtrl;
|
||||
pidData[FD_YAW].Sum = constrainf(pidData[FD_YAW].Sum, -100.0f, 100.0f) / 100.0f * 500.0f;
|
||||
|
||||
// Save control components instead of PID to get logging without additional variables
|
||||
pidData[FD_YAW].F = 10.0f * yawPilotCtrl;
|
||||
pidData[FD_YAW].D = 10.0f * yawDampingCtrl;
|
||||
pidData[FD_YAW].P = 10.0f * yawStabilityCtrl;
|
||||
}
|
||||
#endif
|
4
src/main/flight/airplane_fcs.h
Normal file
4
src/main/flight/airplane_fcs.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
#include "pid.h"
|
||||
void afcsInit(const pidProfile_t *pidProfile);
|
||||
void FAST_CODE afcsUpdate(const pidProfile_t *pidProfile, timeUs_t currentTimeUs);
|
|
@ -64,6 +64,9 @@
|
|||
|
||||
#include "pid.h"
|
||||
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
#include "airplane_fcs.h"
|
||||
#endif
|
||||
typedef enum {
|
||||
LEVEL_MODE_OFF = 0,
|
||||
LEVEL_MODE_R,
|
||||
|
@ -267,6 +270,18 @@ void resetPidProfile(pidProfile_t *pidProfile)
|
|||
.chirp_frequency_start_deci_hz = 2,
|
||||
.chirp_frequency_end_deci_hz = 6000,
|
||||
.chirp_time_seconds = 20,
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
.afcs_pitch_stick_gain = 100,
|
||||
.afcs_pitch_damping_gain = 20,
|
||||
.afcs_pitch_damping_filter_time = 100,
|
||||
.afcs_pitch_stability_gain = 0,
|
||||
.afcs_roll_stick_gain = 100,
|
||||
.afcs_roll_damping_gain = 25,
|
||||
.afcs_yaw_stick_gain = 100,
|
||||
.afcs_yaw_damping_gain = 500,
|
||||
.afcs_yaw_damping_filter_time = 3000,
|
||||
.afcs_yaw_stability_gain = 0,
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1240,6 +1255,14 @@ void FAST_CODE pidController(const pidProfile_t *pidProfile, timeUs_t currentTim
|
|||
|
||||
#endif // USE_CHIRP
|
||||
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
bool isAFCS = isFixedWing() && FLIGHT_MODE(AIRPLANE_FCS_MODE);
|
||||
if (isAFCS) {
|
||||
afcsUpdate(pidProfile, currentTimeUs);
|
||||
return; // The airplanes FCS do not need PID controller
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------PID controller----------
|
||||
for (int axis = FD_ROLL; axis <= FD_YAW; ++axis) {
|
||||
|
||||
|
|
|
@ -332,6 +332,19 @@ typedef struct pidProfile_s {
|
|||
uint16_t chirp_frequency_start_deci_hz; // start frequency in units of 0.1 hz
|
||||
uint16_t chirp_frequency_end_deci_hz; // end frequency in units of 0.1 hz
|
||||
uint8_t chirp_time_seconds; // excitation time
|
||||
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
uint16_t afcs_pitch_stick_gain;
|
||||
uint16_t afcs_pitch_damping_gain;
|
||||
uint16_t afcs_pitch_damping_filter_time;
|
||||
uint16_t afcs_pitch_stability_gain;
|
||||
uint16_t afcs_roll_stick_gain;
|
||||
uint16_t afcs_roll_damping_gain;
|
||||
uint16_t afcs_yaw_stick_gain;
|
||||
uint16_t afcs_yaw_damping_gain;
|
||||
uint16_t afcs_yaw_damping_filter_time;
|
||||
uint16_t afcs_yaw_stability_gain;
|
||||
#endif
|
||||
} pidProfile_t;
|
||||
|
||||
PG_DECLARE_ARRAY(pidProfile_t, PID_PROFILE_COUNT, pidProfiles);
|
||||
|
@ -550,6 +563,11 @@ typedef struct pidRuntime_s {
|
|||
float chirpFrequencyEndHz;
|
||||
float chirpTimeSeconds;
|
||||
#endif // USE_CHIRP
|
||||
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
pt1Filter_t afcsPitchDampingLowpass;
|
||||
pt1Filter_t afcsYawDampingLowpass;
|
||||
#endif
|
||||
} pidRuntime_t;
|
||||
|
||||
extern pidRuntime_t pidRuntime;
|
||||
|
|
|
@ -47,6 +47,10 @@
|
|||
#include "sensors/gyro.h"
|
||||
#include "sensors/sensors.h"
|
||||
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
#include "airplane_fcs.h"
|
||||
#endif
|
||||
|
||||
#include "pid_init.h"
|
||||
|
||||
#ifdef USE_D_MAX
|
||||
|
@ -387,6 +391,9 @@ void pidInit(const pidProfile_t *pidProfile)
|
|||
#ifdef USE_ADVANCED_TPA
|
||||
tpaCurveInit(pidProfile);
|
||||
#endif
|
||||
#ifdef USE_AIRPLANE_FCS
|
||||
afcsInit(pidProfile);
|
||||
#endif
|
||||
}
|
||||
|
||||
void pidInitConfig(const pidProfile_t *pidProfile)
|
||||
|
|
|
@ -415,6 +415,10 @@ void servoMixer(void)
|
|||
input[INPUT_STABILIZED_ROLL] = rcCommand[ROLL];
|
||||
input[INPUT_STABILIZED_PITCH] = rcCommand[PITCH];
|
||||
input[INPUT_STABILIZED_YAW] = rcCommand[YAW];
|
||||
} else if (FLIGHT_MODE(AIRPLANE_FCS_MODE)) {
|
||||
input[INPUT_STABILIZED_ROLL] = pidData[FD_ROLL].Sum;
|
||||
input[INPUT_STABILIZED_PITCH] = pidData[FD_PITCH].Sum;
|
||||
input[INPUT_STABILIZED_YAW] = pidData[FD_YAW].Sum;
|
||||
} else {
|
||||
// Assisted modes (gyro only or gyro+acc according to AUX configuration in Gui
|
||||
input[INPUT_STABILIZED_ROLL] = pidData[FD_ROLL].Sum * PID_SERVO_MIXER_SCALING;
|
||||
|
|
|
@ -101,7 +101,8 @@ static const box_t boxes[CHECKBOX_ITEM_COUNT] = {
|
|||
{ .boxId = BOXBEEPERMUTE, .boxName = "BEEPER MUTE", .permanentId = 52},
|
||||
{ .boxId = BOXREADY, .boxName = "READY", .permanentId = 53},
|
||||
{ .boxId = BOXLAPTIMERRESET, .boxName = "LAP TIMER RESET", .permanentId = 54},
|
||||
{ .boxId = BOXCHIRP, .boxName = "CHIRP", .permanentId = 55}
|
||||
{ .boxId = BOXCHIRP, .boxName = "CHIRP", .permanentId = 55},
|
||||
{ .boxId = BOXAIRPLANEFCS, .boxName = "AIRPLANE FCS", .permanentId = 56},
|
||||
};
|
||||
|
||||
// mask of enabled IDs, calculated on startup based on enabled features. boxId_e is used as bit index
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue