AC_AttitudeControl: ensure plane always gets the latest gyro

This commit is contained in:
Andy Piper 2024-09-21 12:22:13 +01:00 committed by Peter Barker
parent a647b3914c
commit 02a2c788da
3 changed files with 34 additions and 4 deletions

View File

@ -9,10 +9,12 @@ extern const AP_HAL::HAL& hal;
// default gains for Plane // default gains for Plane
# define AC_ATTITUDE_CONTROL_INPUT_TC_DEFAULT 0.2f // Soft # define AC_ATTITUDE_CONTROL_INPUT_TC_DEFAULT 0.2f // Soft
#define AC_ATTITUDE_CONTROL_ANGLE_LIMIT_MIN 5.0 // Min lean angle so that vehicle can maintain limited control #define AC_ATTITUDE_CONTROL_ANGLE_LIMIT_MIN 5.0 // Min lean angle so that vehicle can maintain limited control
#define AC_ATTITUDE_CONTROL_AFTER_RATE_CONTROL 0
#else #else
// default gains for Copter and Sub // default gains for Copter and Sub
# define AC_ATTITUDE_CONTROL_INPUT_TC_DEFAULT 0.15f // Medium # define AC_ATTITUDE_CONTROL_INPUT_TC_DEFAULT 0.15f // Medium
#define AC_ATTITUDE_CONTROL_ANGLE_LIMIT_MIN 10.0 // Min lean angle so that vehicle can maintain limited control #define AC_ATTITUDE_CONTROL_ANGLE_LIMIT_MIN 10.0 // Min lean angle so that vehicle can maintain limited control
#define AC_ATTITUDE_CONTROL_AFTER_RATE_CONTROL 1
#endif #endif
AC_AttitudeControl *AC_AttitudeControl::_singleton; AC_AttitudeControl *AC_AttitudeControl::_singleton;
@ -185,11 +187,37 @@ float AC_AttitudeControl::get_slew_yaw_max_degs() const
return MIN(_ang_vel_yaw_max, _slew_yaw * 0.01); return MIN(_ang_vel_yaw_max, _slew_yaw * 0.01);
} }
// get the latest gyro for the purposes of attitude control
// Counter-inuitively the lowest latency for rate control is achieved by running rate control
// *before* attitude control. This is because you want rate control to run as close as possible
// to the time that a gyro sample was read to minimise jitter and control errors. Running rate
// control after attitude control might makes sense logically, but the overhead of attitude
// control calculations (and other updates) compromises the actual rate control.
//
// In the case of running rate control in a separate thread, the ordering between rate and attitude
// updates is less important, except that gyro sample used should be the latest
//
// Currently quadplane runs rate control after attitude control, necessitating the following code
// to minimise latency.
// However this code can be removed once quadplane updates it's structure to run the rate loops before
// the Attitude controller.
const Vector3f AC_AttitudeControl::get_latest_gyro() const
{
#if AC_ATTITUDE_CONTROL_AFTER_RATE_CONTROL
// rate updates happen before attitude updates so the last gyro value is the last rate gyro value
// this also allows a separate rate thread to be the source of gyro data
return _rate_gyro;
#else
// rate updates happen after attitude updates so the AHRS must be consulted for the last gyro value
return _ahrs.get_gyro_latest();
#endif
}
// Ensure attitude controller have zero errors to relax rate controller output // Ensure attitude controller have zero errors to relax rate controller output
void AC_AttitudeControl::relax_attitude_controllers() void AC_AttitudeControl::relax_attitude_controllers()
{ {
// take a copy of the last gyro used by the rate controller before using it // take a copy of the last gyro used by the rate controller before using it
Vector3f gyro = _rate_gyro; Vector3f gyro = get_latest_gyro();
// Initialize the attitude variables to the current attitude // Initialize the attitude variables to the current attitude
_ahrs.get_quat_body_to_ned(_attitude_target); _ahrs.get_quat_body_to_ned(_attitude_target);
_attitude_target.to_euler(_euler_angle_target); _attitude_target.to_euler(_euler_angle_target);
@ -562,7 +590,7 @@ void AC_AttitudeControl::input_rate_bf_roll_pitch_yaw_3(float roll_rate_bf_cds,
_attitude_ang_error.from_axis_angle(attitude_error); _attitude_ang_error.from_axis_angle(attitude_error);
} }
Vector3f gyro_latest = _rate_gyro; Vector3f gyro_latest = get_latest_gyro();
attitude_ang_error_update_quat.from_axis_angle((_ang_vel_target - gyro_latest) * _dt); attitude_ang_error_update_quat.from_axis_angle((_ang_vel_target - gyro_latest) * _dt);
_attitude_ang_error = attitude_ang_error_update_quat * _attitude_ang_error; _attitude_ang_error = attitude_ang_error_update_quat * _attitude_ang_error;
_attitude_ang_error.normalize(); _attitude_ang_error.normalize();
@ -828,7 +856,7 @@ void AC_AttitudeControl::attitude_controller_run_quat()
// target angle velocity vector in the body frame // target angle velocity vector in the body frame
Vector3f ang_vel_body_feedforward = rotation_target_to_body * _ang_vel_target; Vector3f ang_vel_body_feedforward = rotation_target_to_body * _ang_vel_target;
Vector3f gyro = _rate_gyro; Vector3f gyro = get_latest_gyro();
// Correct the thrust vector and smoothly add feedforward and yaw input // Correct the thrust vector and smoothly add feedforward and yaw input
_feedforward_scalar = 1.0f; _feedforward_scalar = 1.0f;
if (_thrust_error_angle > AC_ATTITUDE_THRUST_ERROR_ANGLE * 2.0f) { if (_thrust_error_angle > AC_ATTITUDE_THRUST_ERROR_ANGLE * 2.0f) {

View File

@ -474,6 +474,9 @@ protected:
// Return the yaw slew rate limit in radians/s // Return the yaw slew rate limit in radians/s
float get_slew_yaw_max_rads() const { return radians(get_slew_yaw_max_degs()); } float get_slew_yaw_max_rads() const { return radians(get_slew_yaw_max_degs()); }
// get the latest gyro for the purposes of attitude control
const Vector3f get_latest_gyro() const;
// Maximum rate the yaw target can be updated in Loiter, RTL, Auto flight modes // Maximum rate the yaw target can be updated in Loiter, RTL, Auto flight modes
AP_Float _slew_yaw; AP_Float _slew_yaw;

View File

@ -441,7 +441,6 @@ void AC_AttitudeControl_Multi::update_throttle_rpy_mix()
void AC_AttitudeControl_Multi::rate_controller_run_dt(float dt, const Vector3f& gyro) void AC_AttitudeControl_Multi::rate_controller_run_dt(float dt, const Vector3f& gyro)
{ {
_rate_gyro = gyro;
// take a copy of the target so that it can't be changed from under us. // take a copy of the target so that it can't be changed from under us.
Vector3f ang_vel_body = _ang_vel_body; Vector3f ang_vel_body = _ang_vel_body;