2015-05-13 03:09:36 -03:00
# include "Plane.h"
2014-03-13 23:48:58 -03:00
2011-09-08 22:29:39 -03:00
/********************************************************************************/
// Command Event Handlers
/********************************************************************************/
2015-05-13 03:09:36 -03:00
bool Plane : : start_command ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2016-05-11 02:57:41 -03:00
// default to non-VTOL loiter
auto_state . vtol_loiter = false ;
// log when new commands start
2014-03-18 23:42:15 -03:00
if ( should_log ( MASK_LOG_CMD ) ) {
2015-06-23 23:13:16 -03:00
DataFlash . Log_Write_Mission_Cmd ( mission , cmd ) ;
2014-03-03 09:50:45 -04:00
}
// special handling for nav vs non-nav commands
if ( AP_Mission : : is_nav_cmd ( cmd ) ) {
2014-04-23 08:57:51 -03:00
// set land_complete to false to stop us zeroing the throttle
2015-06-13 06:11:49 -03:00
auto_state . sink_rate = 0 ;
2012-08-22 03:17:55 -03:00
2016-03-28 18:21:24 -03:00
// set takeoff_complete to true so we don't add extra elevator
2014-03-03 09:50:45 -04:00
// except in a takeoff
2014-04-23 08:57:51 -03:00
auto_state . takeoff_complete = true ;
2014-10-21 12:26:33 -03:00
2015-06-13 06:12:54 -03:00
// start non-idle
auto_state . idle_mode = false ;
2014-04-23 08:57:51 -03:00
2016-04-18 13:37:30 -03:00
nav_controller - > set_data_is_stale ( ) ;
2015-09-16 06:03:28 -03:00
// reset loiter start time. New command is a new loiter
loiter . start_time_ms = 0 ;
2016-07-21 02:29:31 -03:00
AP_Mission : : Mission_Command next_nav_cmd ;
const uint16_t next_index = mission . get_current_nav_index ( ) + 1 ;
2017-10-29 03:31:09 -03:00
auto_state . wp_is_land_approach = mission . get_next_nav_cmd ( next_index , next_nav_cmd ) & & ( next_nav_cmd . id = = MAV_CMD_NAV_LAND ) & &
! quadplane . is_vtol_land ( next_nav_cmd . id ) ;
2016-07-21 02:29:31 -03:00
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Executing nav command ID #%i " , cmd . id ) ;
2014-04-23 08:57:51 -03:00
} else {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Executing command ID #%i " , cmd . id ) ;
2014-03-03 09:50:45 -04:00
}
switch ( cmd . id ) {
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_TAKEOFF :
2015-08-20 17:44:32 -03:00
crash_state . is_crashed = false ;
2017-10-29 03:31:09 -03:00
if ( quadplane . is_vtol_takeoff ( cmd . id ) ) {
return quadplane . do_vtol_takeoff ( cmd ) ;
}
2014-03-03 09:50:45 -04:00
do_takeoff ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_WAYPOINT : // Navigate to Waypoint
2014-03-03 09:50:45 -04:00
do_nav_wp ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_LAND : // LAND to Waypoint
2017-10-29 03:31:09 -03:00
if ( quadplane . is_vtol_land ( cmd . id ) ) {
crash_state . is_crashed = false ;
return quadplane . do_vtol_land ( cmd ) ;
}
2014-03-03 09:50:45 -04:00
do_land ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_LOITER_UNLIM : // Loiter indefinitely
2014-03-03 09:50:45 -04:00
do_loiter_unlimited ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_LOITER_TURNS : // Loiter N Times
2014-03-03 09:50:45 -04:00
do_loiter_turns ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_LOITER_TIME :
2014-03-03 09:50:45 -04:00
do_loiter_time ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2015-03-13 18:48:21 -03:00
case MAV_CMD_NAV_LOITER_TO_ALT :
do_loiter_to_alt ( cmd ) ;
break ;
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_RETURN_TO_LAUNCH :
2016-08-13 04:54:37 -03:00
set_mode ( RTL , MODE_REASON_UNKNOWN ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2014-10-21 17:46:01 -03:00
case MAV_CMD_NAV_CONTINUE_AND_CHANGE_ALT :
do_continue_and_change_alt ( cmd ) ;
2014-11-24 22:15:25 -04:00
break ;
2014-10-21 17:46:01 -03:00
2015-06-13 06:12:54 -03:00
case MAV_CMD_NAV_ALTITUDE_WAIT :
do_altitude_wait ( cmd ) ;
break ;
2016-01-01 05:42:10 -04:00
case MAV_CMD_NAV_VTOL_TAKEOFF :
crash_state . is_crashed = false ;
return quadplane . do_vtol_takeoff ( cmd ) ;
case MAV_CMD_NAV_VTOL_LAND :
crash_state . is_crashed = false ;
return quadplane . do_vtol_land ( cmd ) ;
2014-03-03 09:50:45 -04:00
// Conditional commands
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_CONDITION_DELAY :
2014-03-03 09:50:45 -04:00
do_wait_delay ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_CONDITION_DISTANCE :
2014-03-03 09:50:45 -04:00
do_within_distance ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2014-03-03 09:50:45 -04:00
// Do commands
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_CHANGE_SPEED :
2014-03-03 09:50:45 -04:00
do_change_speed ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_SET_HOME :
2014-03-03 09:50:45 -04:00
do_set_home ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_SET_SERVO :
2014-03-17 02:16:45 -03:00
ServoRelayEvents . do_set_servo ( cmd . content . servo . channel , cmd . content . servo . pwm ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_SET_RELAY :
2014-03-17 02:16:45 -03:00
ServoRelayEvents . do_set_relay ( cmd . content . relay . num , cmd . content . relay . state ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_REPEAT_SERVO :
2014-03-18 23:13:47 -03:00
ServoRelayEvents . do_repeat_servo ( cmd . content . repeat_servo . channel , cmd . content . repeat_servo . pwm ,
cmd . content . repeat_servo . repeat_count , cmd . content . repeat_servo . cycle_time * 1000.0f ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_REPEAT_RELAY :
2014-03-18 23:13:47 -03:00
ServoRelayEvents . do_repeat_relay ( cmd . content . repeat_relay . num , cmd . content . repeat_relay . repeat_count ,
cmd . content . repeat_relay . cycle_time * 1000.0f ) ;
2012-08-16 21:50:15 -03:00
break ;
2011-10-31 18:55:58 -03:00
2014-06-05 03:12:10 -03:00
case MAV_CMD_DO_INVERTED_FLIGHT :
if ( cmd . p1 = = 0 | | cmd . p1 = = 1 ) {
auto_state . inverted_flight = ( bool ) cmd . p1 ;
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Set inverted %u " , cmd . p1 ) ;
2014-06-05 03:12:10 -03:00
}
break ;
2014-10-17 22:40:31 -03:00
case MAV_CMD_DO_LAND_START :
break ;
2014-10-25 18:20:04 -03:00
case MAV_CMD_DO_FENCE_ENABLE :
# if GEOFENCE_ENABLED == ENABLED
2015-04-09 13:02:38 -03:00
if ( cmd . p1 ! = 2 ) {
if ( ! geofence_set_enabled ( ( bool ) cmd . p1 , AUTO_TOGGLED ) ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_WARNING , " Unable to set fence. Enabled state to %u " , cmd . p1 ) ;
2015-04-09 13:02:38 -03:00
} else {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Set fence enabled state to %u " , cmd . p1 ) ;
2015-04-09 13:02:38 -03:00
}
} else { //commanding to only disable floor
if ( ! geofence_set_floor_enabled ( false ) ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_WARNING , " Unable to disable fence floor " ) ;
2015-04-09 13:02:38 -03:00
} else {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_WARNING , " Fence floor disabled " ) ;
2015-04-09 13:02:38 -03:00
}
2014-10-25 18:20:04 -03:00
}
# endif
2015-06-19 23:35:07 -03:00
break ;
2015-06-13 06:16:02 -03:00
case MAV_CMD_DO_AUTOTUNE_ENABLE :
autotune_enable ( cmd . p1 ) ;
2014-10-25 18:20:04 -03:00
break ;
2012-06-13 16:00:20 -03:00
# if CAMERA == ENABLED
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_CONTROL_VIDEO : // Control on-board camera capturing. |Camera ID (-1 for all)| Transmission: 0: disabled, 1: enabled compressed, 2: enabled raw| Transmission mode: 0: video stream, >0: single images every n seconds (decimal)| Recording: 0: disabled, 1: enabled compressed, 2: enabled raw| Empty| Empty| Empty|
break ;
2012-06-13 16:00:20 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_DIGICAM_CONFIGURE : // Mission command to configure an on-board camera controller system. |Modes: P, TV, AV, M, Etc| Shutter speed: Divisor number for one second| Aperture: F stop number| ISO number e.g. 80, 100, 200, Etc| Exposure type enumerator| Command Identity| Main engine cut-off time before camera trigger in seconds/10 (0 means no cut-off)|
2015-03-29 15:49:10 -03:00
do_digicam_configure ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2012-06-13 16:00:20 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_DO_DIGICAM_CONTROL : // Mission command to control an on-board camera controller system. |Session control e.g. show/hide lens| Zoom's absolute position| Zooming step value to offset zoom from the current position| Focus Locking, Unlocking or Re-locking| Shooting Command| Command Identity| Empty|
2015-03-29 15:49:10 -03:00
// do_digicam_control Send Digicam Control message with the camera library
do_digicam_control ( cmd ) ;
2012-08-16 21:50:15 -03:00
break ;
2013-10-11 07:30:01 -03:00
case MAV_CMD_DO_SET_CAM_TRIGG_DIST :
2014-03-17 02:16:45 -03:00
camera . set_trigger_distance ( cmd . content . cam_trigg_dist . meters ) ;
2013-10-11 07:30:01 -03:00
break ;
2012-06-13 16:00:20 -03:00
# endif
2015-06-18 07:45:33 -03:00
# if PARACHUTE == ENABLED
case MAV_CMD_DO_PARACHUTE :
do_parachute ( cmd ) ;
break ;
# endif
2011-10-31 18:55:58 -03:00
# if MOUNT == ENABLED
2012-08-16 21:50:15 -03:00
// Sets the region of interest (ROI) for a sensor set or the
// vehicle itself. This can then be used by the vehicles control
// system to control the vehicle attitude and the attitude of various
// devices such as cameras.
// |Region of interest mode. (see MAV_ROI enum)| Waypoint index/ target ID. (see MAV_ROI enum)| ROI index (allows a vehicle to manage multiple cameras etc.)| Empty| x the location of the fixed ROI (see MAV_FRAME)| y| z|
2014-07-04 03:42:51 -03:00
case MAV_CMD_DO_SET_ROI :
if ( cmd . content . location . alt = = 0 & & cmd . content . location . lat = = 0 & & cmd . content . location . lng = = 0 ) {
// switch off the camera tracking if enabled
if ( camera_mount . get_mode ( ) = = MAV_MOUNT_MODE_GPS_POINT ) {
camera_mount . set_mode_to_default ( ) ;
}
} else {
2015-01-08 16:12:08 -04:00
// set mount's target location
camera_mount . set_roi_target ( cmd . content . location ) ;
2014-07-04 03:42:51 -03:00
}
2012-08-16 21:50:15 -03:00
break ;
2015-05-25 19:30:30 -03:00
case MAV_CMD_DO_MOUNT_CONTROL : // 205
// point the camera to a specified angle
camera_mount . set_angle_targets ( cmd . content . mount_control . roll ,
cmd . content . mount_control . pitch ,
cmd . content . mount_control . yaw ) ;
break ;
2011-10-31 18:55:58 -03:00
# endif
2016-04-22 05:22:31 -03:00
case MAV_CMD_DO_VTOL_TRANSITION :
plane . quadplane . handle_do_vtol_transition ( ( enum MAV_VTOL_STATE ) cmd . content . do_vtol_transition . target_state ) ;
break ;
2016-07-23 04:37:42 -03:00
case MAV_CMD_DO_ENGINE_CONTROL :
2016-07-23 06:02:48 -03:00
plane . g2 . ice_control . engine_control ( cmd . content . do_engine_control . start_control ,
cmd . content . do_engine_control . cold_start ,
cmd . content . do_engine_control . height_delay_cm * 0.01f ) ;
2016-07-23 04:37:42 -03:00
break ;
2018-02-22 05:13:38 -04:00
# if GRIPPER_ENABLED == ENABLED
case MAV_CMD_DO_GRIPPER : // Mission command to control gripper
switch ( cmd . content . gripper . action ) {
case GRIPPER_ACTION_RELEASE :
plane . g2 . gripper . release ( ) ;
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Gripper Released " ) ;
break ;
case GRIPPER_ACTION_GRAB :
plane . g2 . gripper . grab ( ) ;
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Gripper Grabbed " ) ;
break ;
default :
// do nothing
break ;
}
break ;
# endif
2012-08-16 21:50:15 -03:00
}
2014-03-03 09:50:45 -04:00
return true ;
2011-09-08 22:29:39 -03:00
}
2013-04-15 01:41:15 -03:00
/*******************************************************************************
Verify command Handlers
Each type of mission element has a " verify " operation . The verify
operation returns true when the mission element has completed and we
should move onto the next mission element .
2016-08-22 06:05:05 -03:00
Return true if we do not recognize the command so that we move on to the next command
2013-04-15 01:41:15 -03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-09-08 22:29:39 -03:00
2015-05-13 03:09:36 -03:00
bool Plane : : verify_command ( const AP_Mission : : Mission_Command & cmd ) // Returns true if command complete
2011-09-08 22:29:39 -03:00
{
2014-03-03 09:50:45 -04:00
switch ( cmd . id ) {
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_TAKEOFF :
2017-10-29 03:31:09 -03:00
if ( quadplane . is_vtol_takeoff ( cmd . id ) ) {
return quadplane . verify_vtol_takeoff ( cmd ) ;
}
2012-08-16 21:50:15 -03:00
return verify_takeoff ( ) ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_WAYPOINT :
2014-09-02 22:23:29 -03:00
return verify_nav_wp ( cmd ) ;
2011-09-08 22:29:39 -03:00
2016-08-22 06:05:05 -03:00
case MAV_CMD_NAV_LAND :
2017-10-29 03:31:09 -03:00
if ( quadplane . is_vtol_land ( cmd . id ) ) {
return quadplane . verify_vtol_land ( ) ;
}
2017-01-10 03:44:25 -04:00
if ( flight_stage = = AP_Vehicle : : FixedWing : : FlightStage : : FLIGHT_ABORT_LAND ) {
return landing . verify_abort_landing ( prev_WP_loc , next_WP_loc , current_loc , auto_state . takeoff_altitude_rel_cm , throttle_suppressed ) ;
2016-11-23 07:12:34 -04:00
2017-01-10 03:44:25 -04:00
} else {
// use rangefinder to correct if possible
const float height = height_above_target ( ) - rangefinder_correction ( ) ;
return landing . verify_land ( prev_WP_loc , next_WP_loc , current_loc ,
height , auto_state . sink_rate , auto_state . wp_proportion , auto_state . last_flying_ms , arming . is_armed ( ) , is_flying ( ) , rangefinder_state . in_range ) ;
2016-11-23 07:12:34 -04:00
}
2016-08-22 06:05:05 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_LOITER_UNLIM :
return verify_loiter_unlim ( ) ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_LOITER_TURNS :
return verify_loiter_turns ( ) ;
2011-09-08 22:29:39 -03:00
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_LOITER_TIME :
return verify_loiter_time ( ) ;
2011-09-08 22:29:39 -03:00
2015-03-13 18:48:21 -03:00
case MAV_CMD_NAV_LOITER_TO_ALT :
return verify_loiter_to_alt ( ) ;
2012-08-16 21:50:15 -03:00
case MAV_CMD_NAV_RETURN_TO_LAUNCH :
return verify_RTL ( ) ;
2011-09-08 22:29:39 -03:00
2014-10-21 17:46:01 -03:00
case MAV_CMD_NAV_CONTINUE_AND_CHANGE_ALT :
return verify_continue_and_change_alt ( ) ;
2015-06-13 06:12:54 -03:00
case MAV_CMD_NAV_ALTITUDE_WAIT :
return verify_altitude_wait ( cmd ) ;
2016-08-22 06:05:05 -03:00
case MAV_CMD_NAV_VTOL_TAKEOFF :
return quadplane . verify_vtol_takeoff ( cmd ) ;
case MAV_CMD_NAV_VTOL_LAND :
return quadplane . verify_vtol_land ( ) ;
2014-03-03 09:50:45 -04:00
// Conditional commands
2011-09-08 22:29:39 -03:00
case MAV_CMD_CONDITION_DELAY :
return verify_wait_delay ( ) ;
case MAV_CMD_CONDITION_DISTANCE :
return verify_within_distance ( ) ;
2015-06-18 07:45:33 -03:00
# if PARACHUTE == ENABLED
case MAV_CMD_DO_PARACHUTE :
// assume parachute was released successfully
return true ;
# endif
2016-01-01 05:42:10 -04:00
2014-03-03 09:50:45 -04:00
// do commands (always return true)
case MAV_CMD_DO_CHANGE_SPEED :
case MAV_CMD_DO_SET_HOME :
case MAV_CMD_DO_SET_SERVO :
case MAV_CMD_DO_SET_RELAY :
case MAV_CMD_DO_REPEAT_SERVO :
case MAV_CMD_DO_REPEAT_RELAY :
2014-06-05 03:12:10 -03:00
case MAV_CMD_DO_INVERTED_FLIGHT :
2014-10-17 14:35:05 -03:00
case MAV_CMD_DO_LAND_START :
2014-10-25 18:20:04 -03:00
case MAV_CMD_DO_FENCE_ENABLE :
2015-06-13 06:16:02 -03:00
case MAV_CMD_DO_AUTOTUNE_ENABLE :
2016-08-22 06:05:05 -03:00
case MAV_CMD_DO_CONTROL_VIDEO :
case MAV_CMD_DO_DIGICAM_CONFIGURE :
case MAV_CMD_DO_DIGICAM_CONTROL :
case MAV_CMD_DO_SET_CAM_TRIGG_DIST :
case MAV_CMD_DO_SET_ROI :
case MAV_CMD_DO_MOUNT_CONTROL :
2016-07-23 06:02:48 -03:00
case MAV_CMD_DO_VTOL_TRANSITION :
case MAV_CMD_DO_ENGINE_CONTROL :
2018-02-22 05:13:38 -04:00
case MAV_CMD_DO_GRIPPER :
2014-03-03 09:50:45 -04:00
return true ;
2011-09-08 22:29:39 -03:00
default :
2014-03-03 09:50:45 -04:00
// error message
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_WARNING , " Skipping invalid cmd #%i " , cmd . id ) ;
2016-08-22 06:05:05 -03:00
// return true if we do not recognize the command so that we move on to the next command
2014-03-03 09:50:45 -04:00
return true ;
}
2011-09-08 22:29:39 -03:00
}
/********************************************************************************/
// Nav (Must) commands
/********************************************************************************/
2016-04-29 02:31:08 -03:00
void Plane : : do_RTL ( int32_t rtl_altitude )
2011-09-08 22:29:39 -03:00
{
2017-11-21 15:41:45 -04:00
auto_state . next_wp_crosstrack = false ;
auto_state . crosstrack = false ;
2014-03-16 01:53:10 -03:00
prev_WP_loc = current_loc ;
2016-04-29 02:31:08 -03:00
next_WP_loc = rally . calc_best_rally_or_home_location ( current_loc , rtl_altitude ) ;
2014-07-24 04:54:58 -03:00
setup_terrain_target_alt ( next_WP_loc ) ;
2014-08-04 03:55:15 -03:00
set_target_altitude_location ( next_WP_loc ) ;
2013-04-14 09:04:25 -03:00
2017-01-30 13:44:35 -04:00
if ( aparm . loiter_radius < 0 ) {
2013-04-15 08:31:11 -03:00
loiter . direction = - 1 ;
2013-04-14 09:04:25 -03:00
} else {
2013-04-15 08:31:11 -03:00
loiter . direction = 1 ;
2013-04-14 09:04:25 -03:00
}
2011-09-08 22:29:39 -03:00
2013-07-05 01:56:58 -03:00
setup_glide_slope ( ) ;
2014-07-24 03:21:30 -03:00
setup_turn_angle ( ) ;
2013-07-05 01:56:58 -03:00
2017-10-23 21:39:45 -03:00
DataFlash . Log_Write_Mode ( control_mode , control_mode_reason ) ;
2011-09-08 22:29:39 -03:00
}
2017-10-29 03:31:09 -03:00
/*
start a NAV_TAKEOFF command
*/
2015-05-13 03:09:36 -03:00
void Plane : : do_takeoff ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2015-01-02 19:36:14 -04:00
prev_WP_loc = current_loc ;
2014-03-17 04:45:45 -03:00
set_next_WP ( cmd . content . location ) ;
2012-08-16 21:50:15 -03:00
// pitch in deg, airspeed m/s, throttle %, track WP 1 or 0
2014-08-04 06:59:46 -03:00
auto_state . takeoff_pitch_cd = ( int16_t ) cmd . p1 * 100 ;
2015-09-08 20:13:12 -03:00
if ( auto_state . takeoff_pitch_cd < = 0 ) {
// if the mission doesn't specify a pitch use 4 degrees
auto_state . takeoff_pitch_cd = 400 ;
}
2015-02-25 07:54:52 -04:00
auto_state . takeoff_altitude_rel_cm = next_WP_loc . alt - home . alt ;
2014-03-16 01:53:10 -03:00
next_WP_loc . lat = home . lat + 10 ;
next_WP_loc . lng = home . lng + 10 ;
2014-10-06 17:17:33 -03:00
auto_state . takeoff_speed_time_ms = 0 ;
2014-04-23 08:57:51 -03:00
auto_state . takeoff_complete = false ; // set flag to use gps ground course during TO. IMU will be doing yaw drift correction
2016-03-09 18:22:53 -04:00
auto_state . height_below_takeoff_to_level_off_cm = 0 ;
2012-08-16 21:50:15 -03:00
// Flag also used to override "on the ground" throttle disable
2014-10-06 17:17:33 -03:00
// zero locked course
steer_state . locked_course_err = 0 ;
2015-09-08 05:06:19 -03:00
steer_state . hold_course_cd = - 1 ;
2015-09-17 02:35:37 -03:00
auto_state . baro_takeoff_alt = barometer . get_altitude ( ) ;
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : do_nav_wp ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2014-03-17 04:45:45 -03:00
set_next_WP ( cmd . content . location ) ;
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : do_land ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2014-03-17 04:45:45 -03:00
set_next_WP ( cmd . content . location ) ;
2015-05-09 13:36:40 -03:00
// configure abort altitude and pitch
// if NAV_LAND has an abort altitude then use it, else use last takeoff, else use 50m
if ( cmd . p1 > 0 ) {
auto_state . takeoff_altitude_rel_cm = ( int16_t ) cmd . p1 * 100 ;
} else if ( auto_state . takeoff_altitude_rel_cm < = 0 ) {
auto_state . takeoff_altitude_rel_cm = 3000 ;
}
if ( auto_state . takeoff_pitch_cd < = 0 ) {
// If no takeoff command has ever been used, default to a conservative 10deg
auto_state . takeoff_pitch_cd = 1000 ;
}
2015-09-15 22:14:26 -03:00
// zero rangefinder state, start to accumulate good samples now
memset ( & rangefinder_state , 0 , sizeof ( rangefinder_state ) ) ;
2017-01-10 15:47:31 -04:00
2017-01-30 15:48:22 -04:00
landing . do_land ( cmd , relative_altitude ) ;
2017-01-10 15:47:31 -04:00
2017-06-15 23:00:54 -03:00
if ( flight_stage = = AP_Vehicle : : FixedWing : : FLIGHT_ABORT_LAND ) {
// if we were in an abort we need to explicitly move out of the abort state, as it's sticky
set_flight_stage ( AP_Vehicle : : FixedWing : : FLIGHT_LAND ) ;
}
2017-01-10 15:47:31 -04:00
# if GEOFENCE_ENABLED == ENABLED
if ( g . fence_autoenable = = 1 ) {
if ( ! geofence_set_enabled ( false , AUTO_TOGGLED ) ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_NOTICE , " Disable fence failed (autodisable) " ) ;
2017-01-10 15:47:31 -04:00
} else {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_NOTICE , " Fence disabled (autodisable) " ) ;
2017-01-10 15:47:31 -04:00
}
} else if ( g . fence_autoenable = = 2 ) {
if ( ! geofence_set_floor_enabled ( false ) ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_NOTICE , " Disable fence floor failed (autodisable) " ) ;
2017-01-10 15:47:31 -04:00
} else {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_NOTICE , " Fence floor disabled (auto disable) " ) ;
2017-01-10 15:47:31 -04:00
}
}
# endif
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : loiter_set_direction_wp ( const AP_Mission : : Mission_Command & cmd )
2013-01-13 09:29:53 -04:00
{
2014-03-03 09:50:45 -04:00
if ( cmd . content . location . flags . loiter_ccw ) {
2013-04-15 08:31:11 -03:00
loiter . direction = - 1 ;
2013-01-13 09:29:53 -04:00
} else {
2013-04-15 08:31:11 -03:00
loiter . direction = 1 ;
2013-01-13 09:29:53 -04:00
}
}
2015-05-13 03:09:36 -03:00
void Plane : : do_loiter_unlimited ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2016-03-02 12:44:09 -04:00
Location cmdloc = cmd . content . location ;
location_sanitize ( current_loc , cmdloc ) ;
set_next_WP ( cmdloc ) ;
2014-03-03 09:50:45 -04:00
loiter_set_direction_wp ( cmd ) ;
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : do_loiter_turns ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2016-03-02 12:44:09 -04:00
Location cmdloc = cmd . content . location ;
location_sanitize ( current_loc , cmdloc ) ;
set_next_WP ( cmdloc ) ;
2014-03-03 09:50:45 -04:00
loiter_set_direction_wp ( cmd ) ;
2016-03-02 12:44:09 -04:00
loiter . total_cd = ( uint32_t ) ( LOWBYTE ( cmd . p1 ) ) * 36000UL ;
2016-03-02 12:42:27 -04:00
condition_value = 1 ; // used to signify primary turns goal not yet met
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : do_loiter_time ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2016-03-02 12:44:09 -04:00
Location cmdloc = cmd . content . location ;
location_sanitize ( current_loc , cmdloc ) ;
set_next_WP ( cmdloc ) ;
loiter_set_direction_wp ( cmd ) ;
2013-04-15 08:39:14 -03:00
// we set start_time_ms when we reach the waypoint
2016-03-02 12:42:27 -04:00
loiter . time_max_ms = cmd . p1 * ( uint32_t ) 1000 ; // convert sec to ms
condition_value = 1 ; // used to signify primary time goal not yet met
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : do_continue_and_change_alt ( const AP_Mission : : Mission_Command & cmd )
2014-10-21 17:46:01 -03:00
{
2015-08-24 07:06:24 -03:00
// select heading method. Either mission, gps bearing projection or yaw based
// If prev_WP_loc and next_WP_loc are different then an accurate wp based bearing can
// be computed. However, if we had just changed modes before this, such as an aborted landing
// via mode change, the prev and next wps are the same.
float bearing ;
if ( ! locations_are_same ( prev_WP_loc , next_WP_loc ) ) {
// use waypoint based bearing, this is the usual case
steer_state . hold_course_cd = - 1 ;
2017-12-01 19:44:00 -04:00
} else if ( AP : : gps ( ) . status ( ) > = AP_GPS : : GPS_OK_FIX_2D ) {
2015-08-24 07:06:24 -03:00
// use gps ground course based bearing hold
steer_state . hold_course_cd = - 1 ;
2017-12-01 19:44:00 -04:00
bearing = AP : : gps ( ) . ground_course_cd ( ) * 0.01f ;
2015-08-24 07:06:24 -03:00
location_update ( next_WP_loc , bearing , 1000 ) ; // push it out 1km
} else {
// use yaw based bearing hold
steer_state . hold_course_cd = wrap_360_cd ( ahrs . yaw_sensor ) ;
bearing = ahrs . yaw_sensor * 0.01f ;
location_update ( next_WP_loc , bearing , 1000 ) ; // push it out 1km
}
2014-10-21 17:46:01 -03:00
next_WP_loc . alt = cmd . content . location . alt + home . alt ;
2015-08-18 23:48:13 -03:00
condition_value = cmd . p1 ;
2014-12-03 03:31:23 -04:00
reset_offset_altitude ( ) ;
2014-10-21 17:46:01 -03:00
}
2015-06-13 06:12:54 -03:00
void Plane : : do_altitude_wait ( const AP_Mission : : Mission_Command & cmd )
{
// set all servos to trim until we reach altitude or descent speed
auto_state . idle_mode = true ;
}
2015-05-13 03:09:36 -03:00
void Plane : : do_loiter_to_alt ( const AP_Mission : : Mission_Command & cmd )
2015-03-13 18:48:21 -03:00
{
//set target alt
2016-03-02 12:44:09 -04:00
Location loc = cmd . content . location ;
location_sanitize ( current_loc , loc ) ;
set_next_WP ( loc ) ;
loiter_set_direction_wp ( cmd ) ;
2015-03-13 18:48:21 -03:00
2017-02-21 07:56:32 -04:00
// init to 0, set to 1 when altitude is reached
condition_value = 0 ;
2015-03-13 18:48:21 -03:00
}
2011-09-08 22:29:39 -03:00
/********************************************************************************/
// Verify Nav (Must) commands
/********************************************************************************/
2015-05-13 03:09:36 -03:00
bool Plane : : verify_takeoff ( )
2011-09-08 22:29:39 -03:00
{
2014-10-06 17:17:33 -03:00
if ( ahrs . yaw_initialised ( ) & & steer_state . hold_course_cd = = - 1 ) {
const float min_gps_speed = 5 ;
if ( auto_state . takeoff_speed_time_ms = = 0 & &
gps . status ( ) > = AP_GPS : : GPS_OK_FIX_3D & &
2017-03-20 20:54:16 -03:00
gps . ground_speed ( ) > min_gps_speed & &
hal . util - > safety_switch_state ( ) ! = AP_HAL : : Util : : SAFETY_DISARMED ) {
2015-05-13 19:05:32 -03:00
auto_state . takeoff_speed_time_ms = millis ( ) ;
2014-10-06 17:17:33 -03:00
}
if ( auto_state . takeoff_speed_time_ms ! = 0 & &
2015-05-13 19:05:32 -03:00
millis ( ) - auto_state . takeoff_speed_time_ms > = 2000 ) {
2014-10-06 17:17:33 -03:00
// once we reach sufficient speed for good GPS course
// estimation we save our current GPS ground course
// corrected for summed yaw to set the take off
// course. This keeps wings level until we are ready to
2016-05-12 14:10:49 -03:00
// rotate, and also allows us to cope with arbitrary
2014-10-06 17:17:33 -03:00
// compass errors for auto takeoff
2015-04-11 06:43:13 -03:00
float takeoff_course = wrap_PI ( radians ( gps . ground_course_cd ( ) * 0.01f ) ) - steer_state . locked_course_err ;
2014-10-06 17:17:33 -03:00
takeoff_course = wrap_PI ( takeoff_course ) ;
steer_state . hold_course_cd = wrap_360_cd ( degrees ( takeoff_course ) * 100 ) ;
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Holding course %ld at %.1fm/s (%.1f) " ,
2014-10-06 17:17:33 -03:00
steer_state . hold_course_cd ,
2015-05-03 03:00:05 -03:00
( double ) gps . ground_speed ( ) ,
( double ) degrees ( steer_state . locked_course_err ) ) ;
2012-08-16 21:50:15 -03:00
}
}
2011-09-08 22:29:39 -03:00
2013-10-03 09:01:43 -03:00
if ( steer_state . hold_course_cd ! = - 1 ) {
2013-04-11 21:25:46 -03:00
// call navigation controller for heading hold
2013-10-03 09:01:43 -03:00
nav_controller - > update_heading_hold ( steer_state . hold_course_cd ) ;
2013-04-11 21:25:46 -03:00
} else {
nav_controller - > update_level_flight ( ) ;
2012-08-16 21:50:15 -03:00
}
2011-09-08 22:29:39 -03:00
2013-06-26 05:36:53 -03:00
// see if we have reached takeoff altitude
2015-02-25 07:54:52 -04:00
int32_t relative_alt_cm = adjusted_relative_altitude_cm ( ) ;
if ( relative_alt_cm > auto_state . takeoff_altitude_rel_cm ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Takeoff complete at %.2fm " ,
2015-05-03 03:00:05 -03:00
( double ) ( relative_alt_cm * 0.01f ) ) ;
2013-10-03 09:01:43 -03:00
steer_state . hold_course_cd = - 1 ;
2014-04-23 08:57:51 -03:00
auto_state . takeoff_complete = true ;
2014-03-16 01:53:10 -03:00
next_WP_loc = prev_WP_loc = current_loc ;
2014-02-13 18:49:42 -04:00
2016-08-29 05:04:42 -03:00
plane . complete_auto_takeoff ( ) ;
2014-02-13 18:49:42 -04:00
2014-08-04 07:39:15 -03:00
// don't cross-track on completion of takeoff, as otherwise we
// can end up doing too sharp a turn
2017-11-21 15:41:45 -04:00
auto_state . next_wp_crosstrack = false ;
2012-08-16 21:50:15 -03:00
return true ;
} else {
return false ;
}
2011-09-08 22:29:39 -03:00
}
2014-08-04 07:39:15 -03:00
/*
update navigation for normal mission waypoints . Return true when the
waypoint is complete
*/
2015-05-13 03:09:36 -03:00
bool Plane : : verify_nav_wp ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2013-10-03 09:01:43 -03:00
steer_state . hold_course_cd = - 1 ;
2013-04-11 21:25:46 -03:00
2016-12-18 10:39:08 -04:00
// depending on the pass by flag either go to waypoint in regular manner or
// fly past it for set distance along the line of waypoints
Location flex_next_WP_loc = next_WP_loc ;
2017-01-06 21:32:28 -04:00
uint8_t cmd_passby = HIGHBYTE ( cmd . p1 ) ; // distance in meters to pass beyond the wp
uint8_t cmd_acceptance_distance = LOWBYTE ( cmd . p1 ) ; // radius in meters to accept reaching the wp
if ( cmd_passby > 0 ) {
2016-12-18 10:39:08 -04:00
float dist = get_distance ( prev_WP_loc , flex_next_WP_loc ) ;
2017-01-06 21:32:28 -04:00
if ( ! is_zero ( dist ) ) {
float factor = ( dist + cmd_passby ) / dist ;
flex_next_WP_loc . lat = flex_next_WP_loc . lat + ( flex_next_WP_loc . lat - prev_WP_loc . lat ) * ( factor - 1.0f ) ;
flex_next_WP_loc . lng = flex_next_WP_loc . lng + ( flex_next_WP_loc . lng - prev_WP_loc . lng ) * ( factor - 1.0f ) ;
}
2016-12-18 10:39:08 -04:00
}
2017-11-21 15:41:45 -04:00
if ( auto_state . crosstrack ) {
2016-12-18 10:39:08 -04:00
nav_controller - > update_waypoint ( prev_WP_loc , flex_next_WP_loc ) ;
2017-11-21 15:41:45 -04:00
} else {
nav_controller - > update_waypoint ( current_loc , flex_next_WP_loc ) ;
2014-08-04 07:39:15 -03:00
}
2013-09-13 04:43:00 -03:00
// see if the user has specified a maximum distance to waypoint
2016-12-18 10:39:08 -04:00
// If override with p3 - then this is not used as it will overfly badly
if ( g . waypoint_max_radius > 0 & &
2015-01-01 00:17:45 -04:00
auto_state . wp_distance > ( uint16_t ) g . waypoint_max_radius ) {
2016-12-18 10:39:08 -04:00
if ( location_passed_point ( current_loc , prev_WP_loc , flex_next_WP_loc ) ) {
2013-09-13 04:43:00 -03:00
// this is needed to ensure completion of the waypoint
2017-01-06 21:32:28 -04:00
if ( cmd_passby = = 0 ) {
2016-12-18 10:39:08 -04:00
prev_WP_loc = current_loc ;
}
2013-09-13 04:43:00 -03:00
}
return false ;
}
2014-09-02 22:23:29 -03:00
2017-01-06 21:32:28 -04:00
float acceptance_distance_m = 0 ; // default to: if overflown - let it fly up to the point
if ( cmd_acceptance_distance > 0 ) {
2014-09-02 22:23:29 -03:00
// allow user to override acceptance radius
2017-01-06 21:32:28 -04:00
acceptance_distance_m = cmd_acceptance_distance ;
} else if ( cmd_passby = = 0 ) {
acceptance_distance_m = nav_controller - > turn_distance ( g . waypoint_radius , auto_state . next_turn_angle ) ;
2016-12-18 10:39:08 -04:00
} else {
2017-01-06 21:32:28 -04:00
2014-09-02 22:23:29 -03:00
}
2013-04-11 21:25:46 -03:00
2017-01-06 21:32:28 -04:00
if ( auto_state . wp_distance < = acceptance_distance_m ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Reached waypoint #%i dist %um " ,
2014-03-03 09:50:45 -04:00
( unsigned ) mission . get_current_nav_cmd ( ) . index ,
2016-12-18 10:39:08 -04:00
( unsigned ) get_distance ( current_loc , flex_next_WP_loc ) ) ;
2012-08-16 21:50:15 -03:00
return true ;
2013-04-11 21:25:46 -03:00
}
2012-07-03 20:21:34 -03:00
// have we flown past the waypoint?
2016-12-18 10:39:08 -04:00
if ( location_passed_point ( current_loc , prev_WP_loc , flex_next_WP_loc ) ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Passed waypoint #%i dist %um " ,
2014-03-03 09:50:45 -04:00
( unsigned ) mission . get_current_nav_cmd ( ) . index ,
2016-12-18 10:39:08 -04:00
( unsigned ) get_distance ( current_loc , flex_next_WP_loc ) ) ;
2012-07-03 20:21:34 -03:00
return true ;
}
2012-08-16 21:50:15 -03:00
return false ;
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
bool Plane : : verify_loiter_unlim ( )
2011-09-08 22:29:39 -03:00
{
2016-04-24 03:08:03 -03:00
if ( mission . get_current_nav_cmd ( ) . p1 < = 1 & & abs ( g . rtl_radius ) > 1 ) {
2016-02-29 14:11:31 -04:00
// if mission radius is 0,1, and rtl_radius is valid, use rtl_radius.
loiter . direction = ( g . rtl_radius < 0 ) ? - 1 : 1 ;
2016-01-27 15:35:59 -04:00
update_loiter ( abs ( g . rtl_radius ) ) ;
} else {
2016-02-29 14:11:31 -04:00
// else use mission radius
2016-01-27 15:35:59 -04:00
update_loiter ( mission . get_current_nav_cmd ( ) . p1 ) ;
}
2012-08-16 21:50:15 -03:00
return false ;
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
bool Plane : : verify_loiter_time ( )
2011-09-08 22:29:39 -03:00
{
2016-03-02 12:42:27 -04:00
bool result = false ;
2017-01-30 13:44:35 -04:00
// mission radius is always aparm.loiter_radius
2016-01-19 00:04:30 -04:00
update_loiter ( 0 ) ;
2016-03-02 12:42:27 -04:00
2013-04-15 08:39:14 -03:00
if ( loiter . start_time_ms = = 0 ) {
2016-05-07 21:40:42 -03:00
if ( reached_loiter_target ( ) & & loiter . sum_cd > 1 ) {
2013-04-15 08:39:14 -03:00
// we've reached the target, start the timer
2015-05-13 19:05:32 -03:00
loiter . start_time_ms = millis ( ) ;
2013-04-15 08:39:14 -03:00
}
2016-03-02 12:42:27 -04:00
} else if ( condition_value ! = 0 ) {
// primary goal, loiter time
if ( ( millis ( ) - loiter . start_time_ms ) > loiter . time_max_ms ) {
// primary goal completed, initialize secondary heading goal
condition_value = 0 ;
result = verify_loiter_heading ( true ) ;
}
} else {
// secondary goal, loiter to heading
result = verify_loiter_heading ( false ) ;
}
if ( result ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Loiter time complete " ) ;
2016-05-11 02:57:41 -03:00
auto_state . vtol_loiter = false ;
2012-08-16 21:50:15 -03:00
}
2016-03-02 12:42:27 -04:00
return result ;
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
bool Plane : : verify_loiter_turns ( )
2011-09-08 22:29:39 -03:00
{
2016-03-02 12:42:27 -04:00
bool result = false ;
2016-02-29 14:11:31 -04:00
uint16_t radius = HIGHBYTE ( mission . get_current_nav_cmd ( ) . p1 ) ;
update_loiter ( radius ) ;
2016-05-11 02:57:41 -03:00
// LOITER_TURNS makes no sense as VTOL
auto_state . vtol_loiter = false ;
2016-03-02 12:42:27 -04:00
if ( condition_value ! = 0 ) {
// primary goal, loiter time
2016-03-06 10:04:17 -04:00
if ( loiter . sum_cd > loiter . total_cd & & loiter . sum_cd > 1 ) {
2016-03-02 12:42:27 -04:00
// primary goal completed, initialize secondary heading goal
condition_value = 0 ;
result = verify_loiter_heading ( true ) ;
}
} else {
// secondary goal, loiter to heading
result = verify_loiter_heading ( false ) ;
}
if ( result ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Loiter orbits complete " ) ;
2012-08-16 21:50:15 -03:00
}
2016-03-02 12:42:27 -04:00
return result ;
2011-09-08 22:29:39 -03:00
}
2015-04-23 18:39:25 -03:00
/*
verify a LOITER_TO_ALT command . This involves checking we have
reached both the desired altitude and desired heading . The desired
altitude only needs to be reached once .
*/
2015-05-13 03:09:36 -03:00
bool Plane : : verify_loiter_to_alt ( )
2015-04-23 18:39:25 -03:00
{
2016-03-02 12:42:27 -04:00
bool result = false ;
update_loiter ( mission . get_current_nav_cmd ( ) . p1 ) ;
2015-03-13 18:48:21 -03:00
2017-02-21 07:56:32 -04:00
// condition_value == 0 means alt has never been reached
if ( condition_value = = 0 ) {
// primary goal, loiter to alt
if ( labs ( loiter . sum_cd ) > 1 & & ( loiter . reached_target_alt | | loiter . unable_to_acheive_target_alt ) ) {
2016-03-02 12:42:27 -04:00
// primary goal completed, initialize secondary heading goal
2017-02-21 07:56:32 -04:00
if ( loiter . unable_to_acheive_target_alt ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Loiter to alt was stuck at %d " , current_loc . alt / 100 ) ;
2017-02-21 07:56:32 -04:00
}
condition_value = 1 ;
2016-03-02 12:42:27 -04:00
result = verify_loiter_heading ( true ) ;
2015-03-13 18:48:21 -03:00
}
2016-03-02 12:42:27 -04:00
} else {
// secondary goal, loiter to heading
result = verify_loiter_heading ( false ) ;
2015-03-13 18:48:21 -03:00
}
2015-07-20 19:28:25 -03:00
2016-03-02 12:42:27 -04:00
if ( result ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Loiter to alt complete " ) ;
2016-03-02 12:42:27 -04:00
}
return result ;
2015-03-13 18:48:21 -03:00
}
2015-05-13 03:09:36 -03:00
bool Plane : : verify_RTL ( )
2011-09-08 22:29:39 -03:00
{
2016-01-19 00:04:30 -04:00
if ( g . rtl_radius < 0 ) {
loiter . direction = - 1 ;
} else {
loiter . direction = 1 ;
}
update_loiter ( abs ( g . rtl_radius ) ) ;
2015-11-27 13:11:58 -04:00
if ( auto_state . wp_distance < = ( uint32_t ) MAX ( g . waypoint_radius , 0 ) | |
2016-05-07 21:40:42 -03:00
reached_loiter_target ( ) ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Reached RTL location " ) ;
2013-04-11 21:25:46 -03:00
return true ;
} else {
2012-08-16 21:50:15 -03:00
return false ;
2013-04-11 21:25:46 -03:00
}
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
bool Plane : : verify_continue_and_change_alt ( )
2014-10-21 17:46:01 -03:00
{
2015-08-24 07:06:24 -03:00
// is waypoint info not available and heading hold is?
if ( locations_are_same ( prev_WP_loc , next_WP_loc ) & &
steer_state . hold_course_cd ! = - 1 ) {
//keep flying the same course with fixed steering heading computed at start if cmd
nav_controller - > update_heading_hold ( steer_state . hold_course_cd ) ;
}
else {
// Is the next_WP less than 200 m away?
if ( get_distance ( current_loc , next_WP_loc ) < 200.0f ) {
//push another 300 m down the line
int32_t next_wp_bearing_cd = get_bearing_cd ( prev_WP_loc , next_WP_loc ) ;
location_update ( next_WP_loc , next_wp_bearing_cd * 0.01f , 300.0f ) ;
}
//keep flying the same course
nav_controller - > update_waypoint ( prev_WP_loc , next_WP_loc ) ;
}
2015-08-18 23:48:13 -03:00
//climbing?
if ( condition_value = = 1 & & adjusted_altitude_cm ( ) > = next_WP_loc . alt ) {
return true ;
}
//descending?
else if ( condition_value = = 2 & &
adjusted_altitude_cm ( ) < = next_WP_loc . alt ) {
return true ;
}
//don't care if we're climbing or descending
2015-08-27 03:22:44 -03:00
else if ( labs ( adjusted_altitude_cm ( ) - next_WP_loc . alt ) < = 500 ) {
2014-10-21 17:46:01 -03:00
return true ;
}
return false ;
}
2015-06-13 06:12:54 -03:00
/*
see if we have reached altitude or descent speed
*/
bool Plane : : verify_altitude_wait ( const AP_Mission : : Mission_Command & cmd )
{
if ( current_loc . alt > cmd . content . altitude_wait . altitude * 100.0f ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Reached altitude " ) ;
2015-06-13 06:12:54 -03:00
return true ;
}
if ( auto_state . sink_rate > cmd . content . altitude_wait . descent_rate ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Reached descent rate %.1f m/s " , ( double ) auto_state . sink_rate ) ;
2015-06-13 06:12:54 -03:00
return true ;
}
// if requested, wiggle servos
if ( cmd . content . altitude_wait . wiggle_time ! = 0 ) {
static uint32_t last_wiggle_ms ;
if ( auto_state . idle_wiggle_stage = = 0 & &
2015-11-19 23:04:52 -04:00
AP_HAL : : millis ( ) - last_wiggle_ms > cmd . content . altitude_wait . wiggle_time * 1000 ) {
2015-06-13 06:12:54 -03:00
auto_state . idle_wiggle_stage = 1 ;
2015-11-19 23:04:52 -04:00
last_wiggle_ms = AP_HAL : : millis ( ) ;
2015-06-13 06:12:54 -03:00
}
// idle_wiggle_stage is updated in set_servos_idle()
}
return false ;
}
2011-09-08 22:29:39 -03:00
/********************************************************************************/
// Condition (May) commands
/********************************************************************************/
2015-05-13 03:09:36 -03:00
void Plane : : do_wait_delay ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2015-05-13 19:05:32 -03:00
condition_start = millis ( ) ;
2014-03-17 02:16:45 -03:00
condition_value = cmd . content . delay . seconds * 1000 ; // convert seconds to milliseconds
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : do_within_distance ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2014-03-17 02:16:45 -03:00
condition_value = cmd . content . distance . meters ;
2011-09-08 22:29:39 -03:00
}
/********************************************************************************/
// Verify Condition (May) commands
/********************************************************************************/
2015-05-13 03:09:36 -03:00
bool Plane : : verify_wait_delay ( )
2011-09-08 22:29:39 -03:00
{
2015-05-13 19:05:32 -03:00
if ( ( unsigned ) ( millis ( ) - condition_start ) > ( unsigned ) condition_value ) {
2012-08-16 21:50:15 -03:00
condition_value = 0 ;
return true ;
}
return false ;
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
bool Plane : : verify_within_distance ( )
2011-09-08 22:29:39 -03:00
{
2015-11-27 13:11:58 -04:00
if ( auto_state . wp_distance < MAX ( condition_value , 0 ) ) {
2012-08-16 21:50:15 -03:00
condition_value = 0 ;
return true ;
}
return false ;
2011-09-08 22:29:39 -03:00
}
/********************************************************************************/
// Do (Now) commands
/********************************************************************************/
2015-05-13 03:09:36 -03:00
void Plane : : do_loiter_at_location ( )
2011-09-08 22:29:39 -03:00
{
2017-01-30 13:44:35 -04:00
if ( aparm . loiter_radius < 0 ) {
2013-04-15 08:31:11 -03:00
loiter . direction = - 1 ;
2013-04-14 09:04:25 -03:00
} else {
2013-04-15 08:31:11 -03:00
loiter . direction = 1 ;
2013-04-14 09:04:25 -03:00
}
2014-03-16 01:53:10 -03:00
next_WP_loc = current_loc ;
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : do_change_speed ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2014-03-17 02:16:45 -03:00
switch ( cmd . content . speed . speed_type )
2012-08-16 21:50:15 -03:00
{
case 0 : // Airspeed
2014-03-17 02:16:45 -03:00
if ( cmd . content . speed . target_ms > 0 ) {
2016-11-17 21:07:10 -04:00
aparm . airspeed_cruise_cm . set ( cmd . content . speed . target_ms * 100 ) ;
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Set airspeed %u m/s " , ( unsigned ) cmd . content . speed . target_ms ) ;
2012-08-16 21:50:15 -03:00
}
break ;
case 1 : // Ground speed
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Set groundspeed %u " , ( unsigned ) cmd . content . speed . target_ms ) ;
2016-11-17 21:07:10 -04:00
aparm . min_gndspeed_cm . set ( cmd . content . speed . target_ms * 100 ) ;
2012-08-16 21:50:15 -03:00
break ;
}
2011-09-08 22:29:39 -03:00
2014-03-18 23:13:47 -03:00
if ( cmd . content . speed . throttle_pct > 0 & & cmd . content . speed . throttle_pct < = 100 ) {
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Set throttle %u " , ( unsigned ) cmd . content . speed . throttle_pct ) ;
2014-03-17 02:16:45 -03:00
aparm . throttle_cruise . set ( cmd . content . speed . throttle_pct ) ;
2012-09-12 00:09:32 -03:00
}
2011-09-08 22:29:39 -03:00
}
2015-05-13 03:09:36 -03:00
void Plane : : do_set_home ( const AP_Mission : : Mission_Command & cmd )
2011-09-08 22:29:39 -03:00
{
2014-03-28 16:52:48 -03:00
if ( cmd . p1 = = 1 & & gps . status ( ) > = AP_GPS : : GPS_OK_FIX_3D ) {
2012-08-16 21:50:15 -03:00
init_home ( ) ;
} else {
2014-03-28 16:52:48 -03:00
ahrs . set_home ( cmd . content . location ) ;
2015-02-20 19:14:18 -04:00
home_is_set = HOME_SET_NOT_LOCKED ;
2015-07-05 23:01:17 -03:00
Log_Write_Home_And_Origin ( ) ;
2017-07-08 01:46:24 -03:00
gcs ( ) . send_home ( cmd . content . location ) ;
2017-09-18 02:39:00 -03:00
// send ekf origin if set
Location ekf_origin ;
if ( ahrs . get_origin ( ekf_origin ) ) {
gcs ( ) . send_ekf_origin ( ekf_origin ) ;
}
2012-08-16 21:50:15 -03:00
}
2011-09-08 22:29:39 -03:00
}
2015-03-29 15:49:10 -03:00
// do_digicam_configure Send Digicam Configure message with the camera library
2015-05-13 03:09:36 -03:00
void Plane : : do_digicam_configure ( const AP_Mission : : Mission_Command & cmd )
2015-03-29 15:49:10 -03:00
{
# if CAMERA == ENABLED
2015-09-06 17:44:33 -03:00
camera . configure ( cmd . content . digicam_configure . shooting_mode ,
cmd . content . digicam_configure . shutter_speed ,
cmd . content . digicam_configure . aperture ,
cmd . content . digicam_configure . ISO ,
cmd . content . digicam_configure . exposure_type ,
cmd . content . digicam_configure . cmd_id ,
cmd . content . digicam_configure . engine_cutoff_time ) ;
2015-03-29 15:49:10 -03:00
# endif
}
// do_digicam_control Send Digicam Control message with the camera library
2015-05-13 03:09:36 -03:00
void Plane : : do_digicam_control ( const AP_Mission : : Mission_Command & cmd )
2015-03-29 15:49:10 -03:00
{
# if CAMERA == ENABLED
2017-07-26 00:48:21 -03:00
camera . control ( cmd . content . digicam_control . session ,
cmd . content . digicam_control . zoom_pos ,
cmd . content . digicam_control . zoom_step ,
cmd . content . digicam_control . focus_lock ,
cmd . content . digicam_control . shooting_cmd ,
cmd . content . digicam_control . cmd_id ) ;
2015-03-29 15:49:10 -03:00
# endif
}
2015-06-18 07:45:33 -03:00
# if PARACHUTE == ENABLED
// do_parachute - configure or release parachute
void Plane : : do_parachute ( const AP_Mission : : Mission_Command & cmd )
{
switch ( cmd . p1 ) {
case PARACHUTE_DISABLE :
parachute . enabled ( false ) ;
break ;
case PARACHUTE_ENABLE :
parachute . enabled ( true ) ;
break ;
case PARACHUTE_RELEASE :
parachute_release ( ) ;
break ;
default :
// do nothing
break ;
}
}
# endif
2014-03-17 04:09:29 -03:00
// start_command_callback - callback function called from ap-mission when it begins a new mission command
// we double check that the flight mode is AUTO to avoid the possibility of ap-mission triggering actions while we're not in AUTO mode
2015-05-13 03:09:36 -03:00
bool Plane : : start_command_callback ( const AP_Mission : : Mission_Command & cmd )
2014-03-17 04:09:29 -03:00
{
if ( control_mode = = AUTO ) {
return start_command ( cmd ) ;
}
return true ;
}
// verify_command_callback - callback function called from ap-mission at 10hz or higher when a command is being run
// we double check that the flight mode is AUTO to avoid the possibility of ap-mission triggering actions while we're not in AUTO mode
2015-05-13 03:09:36 -03:00
bool Plane : : verify_command_callback ( const AP_Mission : : Mission_Command & cmd )
2014-03-13 23:48:58 -03:00
{
if ( control_mode = = AUTO ) {
2015-07-20 03:11:34 -03:00
bool cmd_complete = verify_command ( cmd ) ;
// send message to GCS
if ( cmd_complete ) {
2017-07-07 22:55:12 -03:00
gcs ( ) . send_mission_item_reached_message ( cmd . index ) ;
2015-07-20 03:11:34 -03:00
}
return cmd_complete ;
2014-03-13 23:48:58 -03:00
}
return false ;
}
2014-03-17 04:09:29 -03:00
// exit_mission_callback - callback function called from ap-mission when the mission has completed
// we double check that the flight mode is AUTO to avoid the possibility of ap-mission triggering actions while we're not in AUTO mode
2015-05-13 03:09:36 -03:00
void Plane : : exit_mission_callback ( )
2014-03-13 23:48:58 -03:00
{
if ( control_mode = = AUTO ) {
2016-08-13 04:54:37 -03:00
set_mode ( RTL , MODE_REASON_MISSION_END ) ;
2017-07-08 22:15:58 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Mission complete, changing mode to RTL " ) ;
2014-03-13 23:48:58 -03:00
}
}
2016-03-02 12:42:27 -04:00
bool Plane : : verify_loiter_heading ( bool init )
{
2016-05-07 21:40:42 -03:00
if ( quadplane . in_vtol_auto ( ) ) {
// skip heading verify if in VTOL auto
return true ;
}
2016-03-02 12:42:27 -04:00
//Get the lat/lon of next Nav waypoint after this one:
AP_Mission : : Mission_Command next_nav_cmd ;
if ( ! mission . get_next_nav_cmd ( mission . get_current_nav_index ( ) + 1 ,
next_nav_cmd ) ) {
//no next waypoint to shoot for -- go ahead and break out of loiter
return true ;
}
2017-01-30 13:48:39 -04:00
if ( get_distance ( next_WP_loc , next_nav_cmd . content . location ) < abs ( aparm . loiter_radius ) ) {
2016-03-02 12:42:27 -04:00
/* Whenever next waypoint is within the loiter radius,
maintaining loiter would prevent us from ever pointing toward the next waypoint .
Hence break out of loiter immediately
*/
return true ;
}
// Bearing in degrees
int32_t bearing_cd = get_bearing_cd ( current_loc , next_nav_cmd . content . location ) ;
// get current heading.
int32_t heading_cd = gps . ground_course_cd ( ) ;
int32_t heading_err_cd = wrap_180_cd ( bearing_cd - heading_cd ) ;
if ( init ) {
loiter . total_cd = wrap_360_cd ( bearing_cd - heading_cd ) ;
loiter . sum_cd = 0 ;
}
/*
Check to see if the the plane is heading toward the land
waypoint . We use 20 degrees ( + / - 10 deg ) of margin so that
we can handle 200 degrees / second of yaw . Allow turn count
to stop it too to ensure we don ' t loop around forever in
case high winds are forcing us beyond 200 deg / sec at this
particular moment .
*/
if ( labs ( heading_err_cd ) < = 1000 | |
loiter . sum_cd > loiter . total_cd ) {
// Want to head in a straight line from _here_ to the next waypoint instead of center of loiter wp
2016-03-14 15:43:13 -03:00
// 0 to xtrack from center of waypoint, 1 to xtrack from tangent exit location
if ( next_WP_loc . flags . loiter_xtrack ) {
next_WP_loc = current_loc ;
}
2016-03-02 12:42:27 -04:00
return true ;
}
return false ;
}