1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-13 19:40:31 +03:00

Added roll to yaw cross link control to improve roll rotation on high angle of attack

This commit is contained in:
demvlad 2025-04-19 19:48:24 +03:00
parent ae1ff951df
commit b95e336c0a
5 changed files with 37 additions and 5 deletions

View file

@ -1425,6 +1425,9 @@ const clivalue_t valueTable[] = {
{ PARAM_NAME_AFCS_LIFT_C_LIMIT, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 5, 20 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_lift_c_limit) }, { PARAM_NAME_AFCS_LIFT_C_LIMIT, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 5, 20 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_lift_c_limit) },
{ PARAM_NAME_AFCS_AOA_LIMITER_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 1000 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_aoa_limiter_gain) }, { PARAM_NAME_AFCS_AOA_LIMITER_GAIN, VAR_UINT16 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 1000 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_aoa_limiter_gain) },
{ PARAM_NAME_AFCS_SERVO_TIME, VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 5, 1000 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_servo_time) }, { PARAM_NAME_AFCS_SERVO_TIME, VAR_UINT16 | MASTER_VALUE, .config.minmaxUnsigned = { 5, 1000 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_servo_time) },
{ PARAM_NAME_AFCS_ROLL_YAW_CLIFT_START, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 20 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_roll_yaw_clift_start) },
{ PARAM_NAME_AFCS_ROLL_YAW_CLIFT_STOP, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 20 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_roll_yaw_clift_stop) },
{ PARAM_NAME_AFCS_ROLL_TO_YAW_LINK, VAR_UINT8 | PROFILE_VALUE, .config.minmaxUnsigned = { 0, 200 }, PG_PID_PROFILE, offsetof(pidProfile_t, afcs_roll_to_yaw_link) },
#endif #endif
// PG_TELEMETRY_CONFIG // PG_TELEMETRY_CONFIG
#ifdef USE_TELEMETRY #ifdef USE_TELEMETRY

View file

@ -296,4 +296,7 @@
#define PARAM_NAME_AFCS_LIFT_C_LIMIT "afcs_lift_c_limit" #define PARAM_NAME_AFCS_LIFT_C_LIMIT "afcs_lift_c_limit"
#define PARAM_NAME_AFCS_AOA_LIMITER_GAIN "afcs_aoa_limiter_gain" #define PARAM_NAME_AFCS_AOA_LIMITER_GAIN "afcs_aoa_limiter_gain"
#define PARAM_NAME_AFCS_SERVO_TIME "afcs_servo_time" #define PARAM_NAME_AFCS_SERVO_TIME "afcs_servo_time"
#define PARAM_NAME_AFCS_ROLL_YAW_CLIFT_START "afcs_roll_yaw_clift_start"
#define PARAM_NAME_AFCS_ROLL_YAW_CLIFT_STOP "afcs_roll_yaw_clift_stop"
#define PARAM_NAME_AFCS_ROLL_TO_YAW_LINK "afcs_roll_to_yaw_link"
#endif #endif

View file

@ -83,7 +83,7 @@ static void updateAstaticAccelZController(const pidProfile_t *pidProfile, float
float servoVelocity = accelDelta * (pidProfile->afcs_pitch_accel_i_gain * 0.1f); float servoVelocity = accelDelta * (pidProfile->afcs_pitch_accel_i_gain * 0.1f);
servoVelocity = constrainf(servoVelocity, -servoVelocityLimit, servoVelocityLimit); servoVelocity = constrainf(servoVelocity, -servoVelocityLimit, servoVelocityLimit);
pidRuntime.afcsElevatorAddition += servoVelocity * pidRuntime.dT; pidRuntime.afcsElevatorAddition += servoVelocity * pidRuntime.dT;
// limit integrator output // limit integrator output
float output = pidData[FD_PITCH].Sum + pidRuntime.afcsElevatorAddition; float output = pidData[FD_PITCH].Sum + pidRuntime.afcsElevatorAddition;
if ( output > 100.0f) { if ( output > 100.0f) {
@ -130,6 +130,21 @@ static bool updateAngleOfAttackLimiter(const pidProfile_t *pidProfile, float lif
return isLimitAoA; return isLimitAoA;
} }
// Roll to yaw control cross link to improve roll rotation at high angle of attack
static float rollToYawCrossLinkControl(const pidProfile_t *pidProfile, float rollPilotControl, float liftCoef)
{
float crossYawControl = 0.0f,
roll_yaw_clift_start = 0.1f * pidProfile->afcs_roll_yaw_clift_start,
roll_yaw_clift_stop = 0.1f * pidProfile->afcs_roll_yaw_clift_stop;
if (pidProfile->afcs_roll_to_yaw_link && liftCoef > roll_yaw_clift_start) {
float k = (liftCoef - roll_yaw_clift_start) / (roll_yaw_clift_stop - roll_yaw_clift_start);
k = constrainf(k, 0.0f, 1.0f);
crossYawControl = k * rollPilotControl * (pidProfile->afcs_roll_to_yaw_link * 0.1f);
}
return crossYawControl;
}
void FAST_CODE afcsUpdate(const pidProfile_t *pidProfile) void FAST_CODE afcsUpdate(const pidProfile_t *pidProfile)
{ {
@ -158,9 +173,9 @@ void FAST_CODE afcsUpdate(const pidProfile_t *pidProfile)
// Hold required accel z value. If it is unpossible due of big angle of attack value, then limit angle of attack // Hold required accel z value. If it is unpossible due of big angle of attack value, then limit angle of attack
float liftCoef; float liftCoef;
bool isValidLiftC = computeLiftCoefficient(pidProfile, accelZ, &liftCoef); bool isValidLiftCoef = computeLiftCoefficient(pidProfile, accelZ, &liftCoef);
bool isLimitAoA = false; bool isLimitAoA = false;
if (isValidLiftC) { if (isValidLiftCoef) {
isLimitAoA = updateAngleOfAttackLimiter(pidProfile, liftCoef); isLimitAoA = updateAngleOfAttackLimiter(pidProfile, liftCoef);
} }
if (isLimitAoA == false) { if (isLimitAoA == false) {
@ -196,13 +211,18 @@ void FAST_CODE afcsUpdate(const pidProfile_t *pidProfile)
} }
float yawDampingCtrl = gyroYaw * (pidProfile->afcs_damping_gain[FD_YAW] * 0.001f); float yawDampingCtrl = gyroYaw * (pidProfile->afcs_damping_gain[FD_YAW] * 0.001f);
float yawStabilityCtrl = acc.accADC.y * acc.dev.acc_1G_rec * (pidProfile->afcs_yaw_stability_gain * 0.01f); float yawStabilityCtrl = acc.accADC.y * acc.dev.acc_1G_rec * (pidProfile->afcs_yaw_stability_gain * 0.01f);
pidData[FD_YAW].Sum = yawPilotCtrl + yawDampingCtrl + yawStabilityCtrl; float rollToYawCrossControl = 0.0f;
if (isValidLiftCoef) {
rollToYawCrossControl = rollToYawCrossLinkControl(pidProfile, rollPilotCtrl, liftCoef);
}
pidData[FD_YAW].Sum = yawPilotCtrl + yawDampingCtrl + yawStabilityCtrl + rollToYawCrossControl;
pidData[FD_YAW].Sum = constrainf(pidData[FD_YAW].Sum, -100.0f, 100.0f) / 100.0f * 500.0f; 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 // Save control components instead of PID to get logging without additional variables
pidData[FD_YAW].F = 10.0f * yawPilotCtrl; pidData[FD_YAW].F = 10.0f * yawPilotCtrl;
pidData[FD_YAW].D = 10.0f * yawDampingCtrl; pidData[FD_YAW].D = 10.0f * yawDampingCtrl;
pidData[FD_YAW].P = 10.0f * yawStabilityCtrl; pidData[FD_YAW].P = 10.0f * yawStabilityCtrl;
pidData[FD_YAW].S = 10.0f * rollToYawCrossControl;
DEBUG_SET(DEBUG_AFCS, 0, lrintf(pitchPilotCtrl * 10.0f)); DEBUG_SET(DEBUG_AFCS, 0, lrintf(pitchPilotCtrl * 10.0f));
DEBUG_SET(DEBUG_AFCS, 1, lrintf(pitchDampingCtrl * 10.0f)); DEBUG_SET(DEBUG_AFCS, 1, lrintf(pitchDampingCtrl * 10.0f));

View file

@ -282,9 +282,12 @@ void resetPidProfile(pidProfile_t *pidProfile)
.afcs_pitch_accel_min = 60, // maximal negative Z accel value *10 .afcs_pitch_accel_min = 60, // maximal negative Z accel value *10
.afcs_wing_load = 560, // wing load (mass / WingArea) g/decimeter^2 * 10. The g/decimeter^2 units is more comfortable for perception, than kg/m^2, i think .afcs_wing_load = 560, // wing load (mass / WingArea) g/decimeter^2 * 10. The g/decimeter^2 units is more comfortable for perception, than kg/m^2, i think
.afcs_air_density = 1225, // The current atmosphere air density [mg/m^3], the MSA 1225 g/m^3 value is default. TODO: Dynamical air density computing by using baro sensors data .afcs_air_density = 1225, // The current atmosphere air density [mg/m^3], the MSA 1225 g/m^3 value is default. TODO: Dynamical air density computing by using baro sensors data
.afcs_lift_c_limit = 12, // Limit aerodinamics lift force coefficient value *10 .afcs_lift_c_limit = 15, // Limit aerodinamics lift force coefficient value *10
.afcs_aoa_limiter_gain = 250, // elevator speed for 0.1 lift force coef difference in %/sec *10 .afcs_aoa_limiter_gain = 250, // elevator speed for 0.1 lift force coef difference in %/sec *10
.afcs_servo_time = 90, // minimal time of servo movement from neutrale to maximum, ms .afcs_servo_time = 90, // minimal time of servo movement from neutrale to maximum, ms
.afcs_roll_yaw_clift_start = 8, // Aerodynamics lift force coef to start yaw control for roll rotation *10
.afcs_roll_yaw_clift_stop = 15, // Aerodynamics lift force coef to maximum yaw control for roll rotation *10
.afcs_roll_to_yaw_link = 0, // The maximal yaw control value to support roll rotation, % *10
#endif #endif
); );
} }

View file

@ -348,6 +348,9 @@ typedef struct pidProfile_s {
uint8_t afcs_lift_c_limit; // Limit aerodinamics lift force coefficient value *10 uint8_t afcs_lift_c_limit; // Limit aerodinamics lift force coefficient value *10
uint16_t afcs_aoa_limiter_gain; // elevator speed for 0.1 lift force coef difference in %/sec *10 uint16_t afcs_aoa_limiter_gain; // elevator speed for 0.1 lift force coef difference in %/sec *10
uint16_t afcs_servo_time; // minimal time of servo movement from neutrale to maximum, ms uint16_t afcs_servo_time; // minimal time of servo movement from neutrale to maximum, ms
uint8_t afcs_roll_yaw_clift_start; // Aerodynamics lift force coef to start yaw control for roll rotation *10
uint8_t afcs_roll_yaw_clift_stop; // Aerodynamics lift force coef to maximum yaw control for roll rotation *10
uint8_t afcs_roll_to_yaw_link; // The maximal yaw control value to support roll rotation, % *10
#endif #endif
} pidProfile_t; } pidProfile_t;