@@ -875,7 +875,7 @@ void QuadPlane::run_esc_calibration(void)
875
875
*/
876
876
void QuadPlane::multicopter_attitude_rate_update (float yaw_rate_cds)
877
877
{
878
- bool use_multicopter_control = in_vtol_mode () && !tailsitter.in_vtol_transition ();
878
+ bool use_multicopter_control = in_vtol_mode () && !tailsitter.in_vtol_transition () && !force_fw_control_recovery ;
879
879
bool use_yaw_target = false ;
880
880
881
881
float yaw_target_cd = 0.0 ;
@@ -1937,7 +1937,40 @@ void QuadPlane::motors_output(bool run_rate_controller)
1937
1937
if (now - last_att_control_ms > 100 ) {
1938
1938
// relax if have been inactive
1939
1939
relax_attitude_control ();
1940
+ /*
1941
+ when starting the VTOL motors force use of the fixed
1942
+ wing controller for attitude control if we are outside
1943
+ of the Q_ANGLE_MAX limit. We keep it forced until we
1944
+ have recovered to within the limit
1945
+
1946
+ This avoids an issue with the attitude controller
1947
+ limiting the rate of recovery and also an issue with the
1948
+ quaternion controller trying to fix the attitude in a
1949
+ way that is bad for fixed wing aircraft (eg. putting
1950
+ nose down when inverted, leading to rapid loss of
1951
+ height)
1952
+
1953
+ we don't do this in QACRO or tailsitter modes, as this
1954
+ type of attitude is expected
1955
+ */
1956
+ if (!tailsitter.enabled () &&
1957
+ plane.control_mode != &plane.mode_qacro &&
1958
+ (abs (ahrs.roll_sensor ) > aparm.angle_max ||
1959
+ abs (ahrs.pitch_sensor ) > aparm.angle_max )) {
1960
+ force_fw_control_recovery = true ;
1961
+ }
1940
1962
}
1963
+ if (force_fw_control_recovery) {
1964
+ // see if we have recovered attitude
1965
+ if (abs (ahrs.roll_sensor ) <= aparm.angle_max &&
1966
+ abs (ahrs.pitch_sensor ) <= aparm.angle_max ) {
1967
+ force_fw_control_recovery = false ;
1968
+ // reset the attitude target to the new attitude so
1969
+ // the VTOL controller doesn't pull us back
1970
+ attitude_control->reset_target_and_rate (false );
1971
+ }
1972
+ }
1973
+
1941
1974
// run low level rate controllers that only require IMU data and set loop time
1942
1975
const float last_loop_time_s = AP::scheduler ().get_last_loop_time_s ();
1943
1976
motors->set_dt (last_loop_time_s);
@@ -3597,6 +3630,7 @@ void QuadPlane::Log_Write_QControl_Tuning()
3597
3630
speed = 1U <<2 , // true if assistance due to low airspeed
3598
3631
alt = 1U <<3 , // true if assistance due to low altitude
3599
3632
angle = 1U <<4 , // true if assistance due to attitude error
3633
+ fw_force = 1U <<5 , // true if forcing use of fixed wing controllers
3600
3634
};
3601
3635
3602
3636
uint8_t assist_flags = 0 ;
@@ -3615,6 +3649,9 @@ void QuadPlane::Log_Write_QControl_Tuning()
3615
3649
if (assist.in_angle_assist ()) {
3616
3650
assist_flags |= (uint8_t )log_assistance_flags::angle;
3617
3651
}
3652
+ if (force_fw_control_recovery) {
3653
+ assist_flags |= (uint8_t )log_assistance_flags::fw_force;
3654
+ }
3618
3655
3619
3656
struct log_QControl_Tuning pkt = {
3620
3657
LOG_PACKET_HEADER_INIT (LOG_QTUN_MSG),
@@ -4192,7 +4229,8 @@ bool QuadPlane::use_fw_attitude_controllers(void) const
4192
4229
motors->get_desired_spool_state () >= AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED &&
4193
4230
in_vtol_mode () &&
4194
4231
!tailsitter.enabled () &&
4195
- poscontrol.get_state () != QPOS_AIRBRAKE) {
4232
+ poscontrol.get_state () != QPOS_AIRBRAKE &&
4233
+ !force_fw_control_recovery) {
4196
4234
// we want the desired rates for fixed wing slaved to the
4197
4235
// multicopter rates
4198
4236
return false ;
0 commit comments