2015-05-29 23:12:49 -03:00
# include "Copter.h"
2014-02-03 04:57:31 -04:00
/*
2016-07-25 15:45:29 -03:00
* High level calls to set and update flight modes logic for individual
* flight modes is in control_acro . cpp , control_stabilize . cpp , etc
2014-02-03 04:57:31 -04:00
*/
// set_mode - change flight mode and perform any necessary initialisation
// optional force parameter used to force the flight mode change (used only first time mode is set)
2016-05-12 14:24:23 -03:00
// returns true if mode was successfully set
2014-02-03 04:57:31 -04:00
// ACRO, STABILIZE, ALTHOLD, LAND, DRIFT and SPORT can always be set successfully but the return state of other flight modes should be checked and the caller should deal with failures appropriately
2016-01-25 19:40:41 -04:00
bool Copter : : set_mode ( control_mode_t mode , mode_reason_t reason )
2014-02-03 04:57:31 -04:00
{
// boolean to record if flight mode could be set
bool success = false ;
2017-01-09 03:31:26 -04:00
bool ignore_checks = ! motors - > armed ( ) ; // allow switching to any mode if disarmed. We rely on the arming check to perform
2014-02-03 04:57:31 -04:00
// return immediately if we are already in the desired mode
if ( mode = = control_mode ) {
2016-01-26 20:08:45 -04:00
prev_control_mode = control_mode ;
prev_control_mode_reason = control_mode_reason ;
2016-01-25 19:40:41 -04:00
control_mode_reason = reason ;
2014-02-03 04:57:31 -04:00
return true ;
}
2017-09-19 22:18:49 -03:00
# if FRAME_CONFIG == HELI_FRAME
// do not allow helis to enter a non-manual throttle mode if the
// rotor runup is not complete
if ( ! ignore_checks & & ! mode_has_manual_throttle ( mode ) & & ! motors - > rotor_runup_complete ( ) ) {
goto failed ;
}
# endif
2016-03-21 01:33:42 -03:00
// for transition, we assume no flightmode object will be used in
// the new mode, and if the transition fails we reset the
// flightmode to the previous value
Copter : : FlightMode * old_flightmode = flightmode ;
flightmode = nullptr ;
2016-10-10 00:11:14 -03:00
switch ( mode ) {
2014-02-03 04:57:31 -04:00
case ACRO :
2016-03-21 01:20:54 -03:00
success = flightmode_acro . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_acro ;
}
2014-02-03 04:57:31 -04:00
break ;
case STABILIZE :
2017-01-14 01:23:33 -04:00
success = flightmode_stabilize . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_stabilize ;
}
2014-02-03 04:57:31 -04:00
break ;
case ALT_HOLD :
2016-03-21 01:23:41 -03:00
success = flightmode_althold . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_althold ;
}
2014-02-03 04:57:31 -04:00
break ;
case AUTO :
2016-03-21 00:45:50 -03:00
success = flightmode_auto . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_auto ;
}
2014-02-03 04:57:31 -04:00
break ;
case CIRCLE :
2016-03-21 07:41:37 -03:00
success = flightmode_circle . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_circle ;
}
2014-02-03 04:57:31 -04:00
break ;
case LOITER :
2016-03-21 21:42:21 -03:00
success = flightmode_loiter . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_loiter ;
}
2014-02-03 04:57:31 -04:00
break ;
case GUIDED :
2016-03-21 23:13:34 -03:00
success = flightmode_guided . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_guided ;
}
2014-02-03 04:57:31 -04:00
break ;
case LAND :
2016-03-22 00:24:56 -03:00
success = flightmode_land . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_land ;
}
2014-02-03 04:57:31 -04:00
break ;
case RTL :
2016-03-22 03:42:17 -03:00
success = flightmode_rtl . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_rtl ;
}
2014-02-03 04:57:31 -04:00
break ;
case DRIFT :
2016-03-22 03:56:08 -03:00
success = flightmode_drift . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_drift ;
}
2014-02-03 04:57:31 -04:00
break ;
case SPORT :
2016-03-22 05:07:23 -03:00
success = flightmode_sport . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_sport ;
}
2014-02-03 04:57:31 -04:00
break ;
case FLIP :
2016-03-22 07:41:38 -03:00
success = flightmode_flip . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_flip ;
}
2014-02-03 04:57:31 -04:00
break ;
# if AUTOTUNE_ENABLED == ENABLED
case AUTOTUNE :
2016-03-22 20:36:52 -03:00
success = flightmode_autotune . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_autotune ;
}
2014-02-03 04:57:31 -04:00
break ;
# endif
2014-07-11 02:08:09 -03:00
# if POSHOLD_ENABLED == ENABLED
case POSHOLD :
2016-03-22 21:51:39 -03:00
success = flightmode_poshold . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_poshold ;
}
2014-04-04 11:14:30 -03:00
break ;
2014-04-23 03:24:03 -03:00
# endif
2014-04-04 11:14:30 -03:00
2015-05-17 00:22:20 -03:00
case BRAKE :
2016-03-22 22:00:19 -03:00
success = flightmode_brake . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_brake ;
}
2015-04-22 18:10:30 -03:00
break ;
2015-12-18 05:46:56 -04:00
case THROW :
2016-08-02 23:30:27 -03:00
success = flightmode_throw . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_throw ;
}
2015-12-18 05:46:56 -04:00
break ;
2016-07-21 09:44:09 -03:00
case AVOID_ADSB :
2016-08-02 09:40:31 -03:00
success = flightmode_avoid_adsb . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_avoid_adsb ;
}
2016-07-21 09:44:09 -03:00
break ;
2016-08-01 05:44:12 -03:00
case GUIDED_NOGPS :
2016-08-02 23:41:10 -03:00
success = flightmode_guided_nogps . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_guided_nogps ;
}
2016-08-01 05:44:12 -03:00
break ;
2017-09-08 23:45:31 -03:00
case SMART_RTL :
2017-09-10 20:46:51 -03:00
success = flightmode_guided_nogps . init ( ignore_checks ) ;
if ( success ) {
flightmode = & flightmode_smartrtl ;
}
2017-07-26 14:14:40 -03:00
break ;
2014-02-03 04:57:31 -04:00
default :
success = false ;
break ;
}
2017-09-19 22:18:49 -03:00
# if FRAME_CONFIG == HELI_FRAME
failed :
# endif
2014-02-03 04:57:31 -04:00
// update flight mode
if ( success ) {
// perform any cleanup required by previous flight mode
2016-04-14 00:22:33 -03:00
exit_mode ( control_mode , mode ) ;
2016-01-26 20:08:45 -04:00
prev_control_mode = control_mode ;
prev_control_mode_reason = control_mode_reason ;
2016-04-14 00:22:33 -03:00
control_mode = mode ;
2016-01-25 19:40:41 -04:00
control_mode_reason = reason ;
2016-01-25 19:50:12 -04:00
DataFlash . Log_Write_Mode ( control_mode , control_mode_reason ) ;
2014-04-26 23:09:15 -03:00
2016-07-21 02:43:46 -03:00
adsb . set_is_auto_mode ( ( mode = = AUTO ) | | ( mode = = RTL ) | | ( mode = = GUIDED ) ) ;
2014-04-26 23:09:15 -03:00
# if AC_FENCE == ENABLED
// pilot requested flight mode change during a fence breach indicates pilot is attempting to manually recover
// this flight mode change could be automatic (i.e. fence, battery, GPS or GCS failsafe)
// but it should be harmless to disable the fence temporarily in these situations as well
fence . manual_recovery_start ( ) ;
# endif
2016-08-09 19:27:47 -03:00
# if FRSKY_TELEM_ENABLED == ENABLED
frsky_telemetry . update_control_mode ( control_mode ) ;
# endif
2017-10-24 07:44:57 -03:00
# if CAMERA == ENABLED
camera . set_is_auto_mode ( control_mode = = AUTO ) ;
# endif
2016-08-09 19:27:47 -03:00
2016-10-10 00:11:14 -03:00
} else {
2016-03-21 01:33:42 -03:00
flightmode = old_flightmode ;
2014-02-03 04:57:31 -04:00
// Log error that we failed to enter desired flight mode
Log_Write_Error ( ERROR_SUBSYSTEM_FLIGHT_MODE , mode ) ;
2017-07-08 21:56:49 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_WARNING , " Flight mode change failed " ) ;
2014-02-03 04:57:31 -04:00
}
2015-03-06 02:33:25 -04:00
// update notify object
if ( success ) {
2016-03-20 22:19:11 -03:00
notify_flight_mode ( ) ;
2015-03-06 02:33:25 -04:00
}
2014-02-03 04:57:31 -04:00
// return success or failure
return success ;
}
// update_flight_mode - calls the appropriate attitude controllers based on flight mode
// called at 100hz or more
2015-05-29 23:12:49 -03:00
void Copter : : update_flight_mode ( )
2014-02-03 04:57:31 -04:00
{
2014-11-15 20:51:46 -04:00
// Update EKF speed limit - used to limit speed when we are using optical flow
2014-11-15 21:42:56 -04:00
ahrs . getEkfControlLimits ( ekfGndSpdLimit , ekfNavVelGainScaler ) ;
2015-06-10 00:14:13 -03:00
2016-03-21 01:33:42 -03:00
if ( flightmode ! = nullptr ) {
flightmode - > run ( ) ;
}
2014-02-03 04:57:31 -04:00
switch ( control_mode ) {
2016-01-26 21:30:13 -04:00
default :
break ;
2014-02-03 04:57:31 -04:00
}
}
// exit_mode - high level call to organise cleanup as a flight mode is exited
2016-01-25 17:26:20 -04:00
void Copter : : exit_mode ( control_mode_t old_control_mode , control_mode_t new_control_mode )
2014-02-03 04:57:31 -04:00
{
# if AUTOTUNE_ENABLED == ENABLED
if ( old_control_mode = = AUTOTUNE ) {
2016-03-22 20:36:52 -03:00
flightmode_autotune . autotune_stop ( ) ;
2014-02-03 04:57:31 -04:00
}
# endif
2014-02-11 09:32:44 -04:00
2014-05-03 15:26:58 -03:00
// stop mission when we leave auto mode
if ( old_control_mode = = AUTO ) {
2014-05-15 04:11:17 -03:00
if ( mission . state ( ) = = AP_Mission : : MISSION_RUNNING ) {
mission . stop ( ) ;
}
2014-06-09 16:02:28 -03:00
# if MOUNT == ENABLED
camera_mount . set_mode_to_default ( ) ;
# endif // MOUNT == ENABLED
2014-05-03 15:26:58 -03:00
}
2014-02-11 09:32:44 -04:00
// smooth throttle transition when switching from manual to automatic flight modes
2017-01-09 03:31:26 -04:00
if ( mode_has_manual_throttle ( old_control_mode ) & & ! mode_has_manual_throttle ( new_control_mode ) & & motors - > armed ( ) & & ! ap . land_complete ) {
2014-02-11 09:32:44 -04:00
// this assumes all manual flight modes use get_pilot_desired_throttle to translate pilot input to output throttle
2016-10-14 03:34:24 -03:00
set_accel_throttle_I_from_pilot_throttle ( ) ;
2014-02-11 09:32:44 -04:00
}
2015-04-30 03:52:32 -03:00
// cancel any takeoffs in progress
takeoff_stop ( ) ;
2017-09-08 23:45:31 -03:00
// call smart_rtl cleanup
if ( old_control_mode = = SMART_RTL ) {
2017-09-10 20:46:51 -03:00
flightmode_smartrtl . exit ( ) ;
2017-07-26 14:14:40 -03:00
}
2014-07-03 18:07:04 -03:00
# if FRAME_CONFIG == HELI_FRAME
// firmly reset the flybar passthrough to false when exiting acro mode.
if ( old_control_mode = = ACRO ) {
2017-01-09 03:31:26 -04:00
attitude_control - > use_flybar_passthrough ( false , false ) ;
motors - > set_acro_tail ( false ) ;
2014-07-03 18:07:04 -03:00
}
2015-05-23 19:57:17 -03:00
2015-10-12 22:05:49 -03:00
// if we are changing from a mode that did not use manual throttle,
// stab col ramp value should be pre-loaded to the correct value to avoid a twitch
// heli_stab_col_ramp should really only be active switching between Stabilize and Acro modes
if ( ! mode_has_manual_throttle ( old_control_mode ) ) {
if ( new_control_mode = = STABILIZE ) {
input_manager . set_stab_col_ramp ( 1.0 ) ;
} else if ( new_control_mode = = ACRO ) {
input_manager . set_stab_col_ramp ( 0.0 ) ;
}
}
2014-07-03 18:07:04 -03:00
# endif //HELI_FRAME
2014-02-03 04:57:31 -04:00
}
2016-03-20 22:19:11 -03:00
// returns true or false whether current control mode requires GPS
bool Copter : : mode_requires_GPS ( )
2016-10-10 00:11:14 -03:00
{
2016-03-21 01:33:42 -03:00
if ( flightmode ! = nullptr ) {
return flightmode - > requires_GPS ( ) ;
}
2016-03-20 22:19:11 -03:00
switch ( control_mode ) {
2014-02-03 04:57:31 -04:00
default :
return false ;
}
}
2015-01-21 06:57:02 -04:00
// mode_has_manual_throttle - returns true if the flight mode has a manual throttle (i.e. pilot directly controls throttle)
2016-10-10 00:11:14 -03:00
bool Copter : : mode_has_manual_throttle ( control_mode_t mode )
{
switch ( mode ) {
2014-02-03 04:57:31 -04:00
case ACRO :
case STABILIZE :
return true ;
default :
return false ;
}
}
2016-03-20 22:19:11 -03:00
// mode_allows_arming - returns true if vehicle can be armed in the current mode
2014-10-11 04:05:32 -03:00
// arming_from_gcs should be set to true if the arming request comes from the ground station
2016-03-20 22:19:11 -03:00
bool Copter : : mode_allows_arming ( bool arming_from_gcs )
2016-10-10 00:11:14 -03:00
{
2016-03-21 01:33:42 -03:00
if ( flightmode ! = nullptr ) {
return flightmode - > allows_arming ( arming_from_gcs ) ;
}
2016-03-20 22:19:11 -03:00
control_mode_t mode = control_mode ;
2016-08-01 05:44:12 -03:00
if ( mode_has_manual_throttle ( mode ) | | mode = = LOITER | | mode = = ALT_HOLD | | mode = = POSHOLD | | mode = = DRIFT | | mode = = SPORT | | mode = = THROW | | ( arming_from_gcs & & ( mode = = GUIDED | | mode = = GUIDED_NOGPS ) ) ) {
2014-10-10 06:26:43 -03:00
return true ;
}
return false ;
}
2016-03-20 22:19:11 -03:00
// notify_flight_mode - sets notify object based on current flight mode. Only used for OreoLED notify device
void Copter : : notify_flight_mode ( )
2016-10-10 00:11:14 -03:00
{
2016-03-20 22:19:11 -03:00
AP_Notify : : flags . flight_mode = control_mode ;
2016-11-19 20:20:46 -04:00
2016-03-21 01:33:42 -03:00
if ( flightmode ! = nullptr ) {
AP_Notify : : flags . autopilot_mode = flightmode - > is_autopilot ( ) ;
notify . set_flight_mode_str ( flightmode - > name4 ( ) ) ;
return ;
}
2016-03-20 22:19:11 -03:00
switch ( control_mode ) {
2015-03-06 02:33:25 -04:00
break ;
2016-03-22 00:24:56 -03:00
default :
2015-03-06 02:33:25 -04:00
// all other are manual flight modes
AP_Notify : : flags . autopilot_mode = false ;
break ;
}
2017-01-20 06:15:20 -04:00
// set flight mode string
2016-03-20 22:19:11 -03:00
switch ( control_mode ) {
2017-01-20 06:15:20 -04:00
default :
notify . set_flight_mode_str ( " ---- " ) ;
break ;
}
2015-03-06 02:33:25 -04:00
}