|
|
|
@ -827,52 +827,53 @@ void QuadPlane::multicopter_attitude_rate_update(float yaw_rate_cds)
@@ -827,52 +827,53 @@ void QuadPlane::multicopter_attitude_rate_update(float yaw_rate_cds)
|
|
|
|
|
{ |
|
|
|
|
check_attitude_relax(); |
|
|
|
|
|
|
|
|
|
// tailsitter-only body-frame roll control options
|
|
|
|
|
// Angle mode attitude control for pitch and body-frame roll, rate control for euler yaw.
|
|
|
|
|
if (is_tailsitter() && |
|
|
|
|
(tailsitter.input_type & TAILSITTER_INPUT_BF_ROLL)) { |
|
|
|
|
|
|
|
|
|
if (!(tailsitter.input_type & TAILSITTER_INPUT_PLANE)) { |
|
|
|
|
// In multicopter input mode, the roll and yaw stick axes are independent of pitch
|
|
|
|
|
attitude_control->input_euler_rate_yaw_euler_angle_pitch_bf_roll(false, |
|
|
|
|
plane.nav_roll_cd, |
|
|
|
|
plane.nav_pitch_cd, |
|
|
|
|
yaw_rate_cds); |
|
|
|
|
return; |
|
|
|
|
} else { |
|
|
|
|
// In plane input mode, the roll and yaw sticks are swapped
|
|
|
|
|
// and their effective axes rotate from yaw to roll and vice versa
|
|
|
|
|
// as pitch goes from zero to 90.
|
|
|
|
|
// So it is necessary to also rotate their scaling.
|
|
|
|
|
|
|
|
|
|
// Get the roll angle and yaw rate limits
|
|
|
|
|
int16_t roll_limit = aparm.angle_max; |
|
|
|
|
// separate limit for tailsitter roll, if set
|
|
|
|
|
if (tailsitter.max_roll_angle > 0) { |
|
|
|
|
roll_limit = tailsitter.max_roll_angle * 100.0f; |
|
|
|
|
// normal control modes for VTOL and FW flight
|
|
|
|
|
if (in_vtol_mode()) { |
|
|
|
|
|
|
|
|
|
// tailsitter-only body-frame roll control options
|
|
|
|
|
// Angle mode attitude control for pitch and body-frame roll, rate control for euler yaw.
|
|
|
|
|
if (is_tailsitter() && |
|
|
|
|
(tailsitter.input_type & TAILSITTER_INPUT_BF_ROLL)) { |
|
|
|
|
|
|
|
|
|
if (!(tailsitter.input_type & TAILSITTER_INPUT_PLANE)) { |
|
|
|
|
// In multicopter input mode, the roll and yaw stick axes are independent of pitch
|
|
|
|
|
attitude_control->input_euler_rate_yaw_euler_angle_pitch_bf_roll(false, |
|
|
|
|
plane.nav_roll_cd, |
|
|
|
|
plane.nav_pitch_cd, |
|
|
|
|
yaw_rate_cds); |
|
|
|
|
return; |
|
|
|
|
} else { |
|
|
|
|
// In plane input mode, the roll and yaw sticks are swapped
|
|
|
|
|
// and their effective axes rotate from yaw to roll and vice versa
|
|
|
|
|
// as pitch goes from zero to 90.
|
|
|
|
|
// So it is necessary to also rotate their scaling.
|
|
|
|
|
|
|
|
|
|
// Get the roll angle and yaw rate limits
|
|
|
|
|
int16_t roll_limit = aparm.angle_max; |
|
|
|
|
// separate limit for tailsitter roll, if set
|
|
|
|
|
if (tailsitter.max_roll_angle > 0) { |
|
|
|
|
roll_limit = tailsitter.max_roll_angle * 100.0f; |
|
|
|
|
} |
|
|
|
|
// Prevent a divide by zero
|
|
|
|
|
float yaw_rate_limit = ((yaw_rate_max < 1.0f) ? 1 : yaw_rate_max) * 100.0f; |
|
|
|
|
float yaw2roll_scale = roll_limit / yaw_rate_limit; |
|
|
|
|
|
|
|
|
|
// Rotate as a function of Euler pitch and swap roll/yaw
|
|
|
|
|
float euler_pitch = radians(.01f * plane.nav_pitch_cd); |
|
|
|
|
float spitch = fabsf(sinf(euler_pitch)); |
|
|
|
|
float y2r_scale = linear_interpolate(1, yaw2roll_scale, spitch, 0, 1); |
|
|
|
|
|
|
|
|
|
float p_yaw_rate = plane.nav_roll_cd / y2r_scale; |
|
|
|
|
float p_roll_angle = -y2r_scale * yaw_rate_cds; |
|
|
|
|
|
|
|
|
|
attitude_control->input_euler_rate_yaw_euler_angle_pitch_bf_roll(true, |
|
|
|
|
p_roll_angle, |
|
|
|
|
plane.nav_pitch_cd, |
|
|
|
|
p_yaw_rate); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// Prevent a divide by zero
|
|
|
|
|
float yaw_rate_limit = ((yaw_rate_max < 1.0f) ? 1 : yaw_rate_max) * 100.0f; |
|
|
|
|
float yaw2roll_scale = roll_limit / yaw_rate_limit; |
|
|
|
|
|
|
|
|
|
// Rotate as a function of Euler pitch and swap roll/yaw
|
|
|
|
|
float euler_pitch = radians(.01f * plane.nav_pitch_cd); |
|
|
|
|
float spitch = fabsf(sinf(euler_pitch)); |
|
|
|
|
float y2r_scale = linear_interpolate(1, yaw2roll_scale, spitch, 0, 1); |
|
|
|
|
|
|
|
|
|
float p_yaw_rate = plane.nav_roll_cd / y2r_scale; |
|
|
|
|
float p_roll_angle = -y2r_scale * yaw_rate_cds; |
|
|
|
|
|
|
|
|
|
attitude_control->input_euler_rate_yaw_euler_angle_pitch_bf_roll(true, |
|
|
|
|
p_roll_angle, |
|
|
|
|
plane.nav_pitch_cd, |
|
|
|
|
p_yaw_rate); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// normal control modes for VTOL and FW flight
|
|
|
|
|
if (in_vtol_mode() || is_tailsitter()) { |
|
|
|
|
// use euler angle attitude control
|
|
|
|
|
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(plane.nav_roll_cd, |
|
|
|
|
plane.nav_pitch_cd, |
|
|
|
@ -881,7 +882,12 @@ void QuadPlane::multicopter_attitude_rate_update(float yaw_rate_cds)
@@ -881,7 +882,12 @@ void QuadPlane::multicopter_attitude_rate_update(float yaw_rate_cds)
|
|
|
|
|
// use the fixed wing desired rates
|
|
|
|
|
float roll_rate = plane.rollController.get_pid_info().target; |
|
|
|
|
float pitch_rate = plane.pitchController.get_pid_info().target; |
|
|
|
|
attitude_control->input_rate_bf_roll_pitch_yaw_2(roll_rate*100.0f, pitch_rate*100.0f, yaw_rate_cds); |
|
|
|
|
if (is_tailsitter()) { |
|
|
|
|
// tailsitter roll and yaw swapped due to change in reference frame
|
|
|
|
|
attitude_control->input_rate_bf_roll_pitch_yaw_2(yaw_rate_cds,pitch_rate*100.0f, -roll_rate*100.0f); |
|
|
|
|
} else { |
|
|
|
|
attitude_control->input_rate_bf_roll_pitch_yaw_2(roll_rate*100.0f, pitch_rate*100.0f, yaw_rate_cds); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -900,7 +906,12 @@ void QuadPlane::hold_stabilize(float throttle_in)
@@ -900,7 +906,12 @@ void QuadPlane::hold_stabilize(float throttle_in)
|
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
motors->set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED); |
|
|
|
|
attitude_control->set_throttle_out(throttle_in, true, 0); |
|
|
|
|
bool should_boost = true; |
|
|
|
|
if (is_tailsitter() && assisted_flight) { |
|
|
|
|
// tailsitters in forward flight should not use angle boost
|
|
|
|
|
should_boost = false; |
|
|
|
|
} |
|
|
|
|
attitude_control->set_throttle_out(throttle_in, should_boost, 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1563,12 +1574,12 @@ void QuadPlane::update_transition(void)
@@ -1563,12 +1574,12 @@ void QuadPlane::update_transition(void)
|
|
|
|
|
/*
|
|
|
|
|
see if we should provide some assistance |
|
|
|
|
*/ |
|
|
|
|
bool q_assist_safe = hal.util->get_soft_armed() && ((plane.auto_throttle_mode && !plane.throttle_suppressed) || |
|
|
|
|
plane.get_throttle_input()>0 || |
|
|
|
|
plane.is_flying()); |
|
|
|
|
const bool q_assist_safe = hal.util->get_soft_armed() && ((plane.auto_throttle_mode && !plane.throttle_suppressed) || |
|
|
|
|
plane.get_throttle_input()>0 || |
|
|
|
|
plane.is_flying()); |
|
|
|
|
if (q_assist_safe && |
|
|
|
|
(q_assist_state == Q_ASSIST_STATE_ENUM::Q_ASSIST_FORCE || |
|
|
|
|
(q_assist_state == Q_ASSIST_STATE_ENUM::Q_ASSIST_ENABLED && assistance_needed(aspeed, have_airspeed)))) { |
|
|
|
|
(q_assist_state == Q_ASSIST_STATE_ENUM::Q_ASSIST_ENABLED && assistance_needed(aspeed, have_airspeed) && !is_contol_surface_tailsitter()))) { |
|
|
|
|
// the quad should provide some assistance to the plane
|
|
|
|
|
assisted_flight = true; |
|
|
|
|
if (!is_tailsitter()) { |
|
|
|
|