2014-02-22 20:14:44 -04:00
/// @file AP_Mission.cpp
/// @brief Handles the MAVLINK command mission stack. Reads and writes mission to storage.
# include "AP_Mission.h"
2015-08-11 03:28:44 -03:00
# include <AP_Terrain/AP_Terrain.h>
2016-11-25 20:45:11 -04:00
# include <GCS_MAVLink/GCS.h>
2014-02-22 20:14:44 -04:00
2015-10-25 14:03:46 -03:00
const AP_Param : : GroupInfo AP_Mission : : var_info [ ] = {
2014-02-22 20:14:44 -04:00
// @Param: TOTAL
2014-04-28 18:53:36 -03:00
// @DisplayName: Total mission commands
2014-02-22 20:14:44 -04:00
// @Description: The number of mission mission items that has been loaded by the ground station. Do not change this manually.
2014-03-16 01:53:22 -03:00
// @Range: 0 32766
2014-02-22 20:14:44 -04:00
// @Increment: 1
// @User: Advanced
AP_GROUPINFO ( " TOTAL " , 0 , AP_Mission , _cmd_total , 0 ) ,
2014-05-08 11:06:06 -03:00
// @Param: RESTART
// @DisplayName: Mission Restart when entering Auto mode
// @Description: Controls mission starting point when entering Auto mode (either restart from beginning of mission or resume from last command run)
// @Values: 0:Resume Mission, 1:Restart Mission
2016-07-26 02:35:15 -03:00
// @User: Advanced
2014-05-08 11:06:06 -03:00
AP_GROUPINFO ( " RESTART " , 1 , AP_Mission , _restart , AP_MISSION_RESTART_DEFAULT ) ,
2014-04-15 13:26:45 -03:00
2017-08-27 08:12:45 -03:00
// @Param: OPTIONS
// @DisplayName: Mission options bitmask
// @Description: Bitmask of what options to use in missions.
// @Bitmask: 0:Clear Mission on reboot
// @User: Advanced
AP_GROUPINFO ( " OPTIONS " , 2 , AP_Mission , _options , AP_MISSION_OPTIONS_DEFAULT ) ,
2014-02-22 20:14:44 -04:00
AP_GROUPEND
} ;
extern const AP_HAL : : HAL & hal ;
2014-08-13 01:43:37 -03:00
// storage object
StorageAccess AP_Mission : : _storage ( StorageManager : : StorageMission ) ;
2014-02-24 01:50:24 -04:00
///
/// public mission methods
///
2014-02-22 20:14:44 -04:00
2014-03-11 00:52:23 -03:00
/// init - initialises this library including checks the version in eeprom matches this library
void AP_Mission : : init ( )
{
// check_eeprom_version - checks version of missions stored in eeprom matches this library
// command list will be cleared if they do not match
check_eeprom_version ( ) ;
2014-03-20 02:57:01 -03:00
2017-08-29 03:21:20 -03:00
// changes in Content size break the storage
static_assert ( sizeof ( union Content ) = = 12 , " AP_Mission: Content must be 12 bytes " ) ;
2014-08-06 03:17:11 -03:00
2017-08-27 08:12:45 -03:00
// If Mission Clear bit is set then it should clear the mission, otherwise retain the mission.
if ( AP_MISSION_MASK_MISSION_CLEAR & _options ) {
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Clearing Mission " ) ;
clear ( ) ;
}
2015-11-19 23:12:21 -04:00
_last_change_time_ms = AP_HAL : : millis ( ) ;
2014-03-11 00:52:23 -03:00
}
2014-02-22 20:14:44 -04:00
/// start - resets current commands to point to the beginning of the mission
/// To-Do: should we validate the mission first and return true/false?
void AP_Mission : : start ( )
{
_flags . state = MISSION_RUNNING ;
2014-04-15 13:56:09 -03:00
reset ( ) ; // reset mission to the first command, resets jump tracking
2014-02-23 03:54:53 -04:00
// advance to the first command
2014-02-24 01:50:24 -04:00
if ( ! advance_current_nav_cmd ( ) ) {
// on failure set mission complete
complete ( ) ;
}
2014-02-22 20:14:44 -04:00
}
/// stop - stops mission execution. subsequent calls to update() will have no effect until the mission is started or resumed
void AP_Mission : : stop ( )
{
_flags . state = MISSION_STOPPED ;
}
/// resume - continues the mission execution from where we last left off
2016-03-02 11:16:27 -04:00
/// previous running commands will be re-initialized
2014-02-22 20:14:44 -04:00
void AP_Mission : : resume ( )
{
2014-02-24 01:50:24 -04:00
// if mission had completed then start it from the first command
if ( _flags . state = = MISSION_COMPLETE ) {
start ( ) ;
2014-02-23 03:54:53 -04:00
return ;
}
2014-02-24 01:50:24 -04:00
// if mission had stopped then restart it
if ( _flags . state = = MISSION_STOPPED ) {
_flags . state = MISSION_RUNNING ;
2014-02-23 03:54:53 -04:00
2014-02-24 01:50:24 -04:00
// if no valid nav command index restart from beginning
if ( _nav_cmd . index = = AP_MISSION_CMD_INDEX_NONE ) {
start ( ) ;
2014-02-23 03:54:53 -04:00
return ;
}
2014-03-30 08:29:22 -03:00
}
2014-02-23 03:54:53 -04:00
2015-06-23 15:12:28 -03:00
// ensure cache coherence
2017-05-24 13:24:19 -03:00
if ( ! read_cmd_from_storage ( _nav_cmd . index , _nav_cmd ) ) {
// if we failed to read the command from storage, then the command may have
// been from a previously loaded mission it is illogical to ever resume
// flying to a command that has been excluded from the current mission
start ( ) ;
return ;
}
2015-06-23 15:12:28 -03:00
2014-03-30 08:29:22 -03:00
// restart active navigation command. We run these on resume()
// regardless of whether the mission was stopped, as we may be
// re-entering AUTO mode and the nav_cmd callback needs to be run
// to setup the current target waypoint
2014-02-23 03:54:53 -04:00
2014-03-30 08:29:22 -03:00
// Note: if there is no active command then the mission must have been stopped just after the previous nav command completed
// update will take care of finding and starting the nav command
if ( _flags . nav_cmd_loaded ) {
_cmd_start_fn ( _nav_cmd ) ;
}
// restart active do command
if ( _flags . do_cmd_loaded & & _do_cmd . index ! = AP_MISSION_CMD_INDEX_NONE ) {
_cmd_start_fn ( _do_cmd ) ;
2014-02-23 03:54:53 -04:00
}
2014-02-22 20:14:44 -04:00
}
2016-05-19 07:32:48 -03:00
/// check mission starts with a takeoff command
bool AP_Mission : : starts_with_takeoff_cmd ( )
2016-05-19 07:35:42 -03:00
{
Mission_Command cmd = { } ;
2016-11-23 20:20:18 -04:00
uint16_t cmd_index = _restart ? AP_MISSION_CMD_INDEX_NONE : _nav_cmd . index ;
2016-05-19 07:35:42 -03:00
if ( cmd_index = = AP_MISSION_CMD_INDEX_NONE ) {
cmd_index = AP_MISSION_FIRST_REAL_COMMAND ;
}
2016-11-23 20:20:18 -04:00
if ( ! get_next_nav_cmd ( cmd_index , cmd ) ) {
return false ;
}
2016-05-19 07:35:42 -03:00
if ( cmd . id ! = MAV_CMD_NAV_TAKEOFF ) {
return false ;
}
return true ;
}
2014-04-15 13:56:09 -03:00
/// start_or_resume - if MIS_AUTORESTART=0 this will call resume(), otherwise it will call start()
2014-04-15 13:26:45 -03:00
void AP_Mission : : start_or_resume ( )
{
2014-05-08 11:06:06 -03:00
if ( _restart ) {
2014-04-15 13:26:45 -03:00
start ( ) ;
} else {
resume ( ) ;
}
}
2014-04-15 13:56:09 -03:00
/// reset - reset mission to the first command
void AP_Mission : : reset ( )
{
_flags . nav_cmd_loaded = false ;
_flags . do_cmd_loaded = false ;
_flags . do_cmd_all_done = false ;
_nav_cmd . index = AP_MISSION_CMD_INDEX_NONE ;
_do_cmd . index = AP_MISSION_CMD_INDEX_NONE ;
_prev_nav_cmd_index = AP_MISSION_CMD_INDEX_NONE ;
2015-08-23 22:06:31 -03:00
_prev_nav_cmd_wp_index = AP_MISSION_CMD_INDEX_NONE ;
2016-05-13 20:06:25 -03:00
_prev_nav_cmd_id = AP_MISSION_CMD_ID_NONE ;
2014-04-15 13:56:09 -03:00
init_jump_tracking ( ) ;
}
2014-02-22 20:14:44 -04:00
/// clear - clears out mission
/// returns true if mission was running so it could not be cleared
bool AP_Mission : : clear ( )
{
// do not allow clearing the mission while it is running
if ( _flags . state = = MISSION_RUNNING ) {
return false ;
}
// remove all commands
_cmd_total . set_and_save ( 0 ) ;
// clear index to commands
_nav_cmd . index = AP_MISSION_CMD_INDEX_NONE ;
_do_cmd . index = AP_MISSION_CMD_INDEX_NONE ;
2014-02-23 03:54:53 -04:00
_flags . nav_cmd_loaded = false ;
_flags . do_cmd_loaded = false ;
// return success
return true ;
2014-02-22 20:14:44 -04:00
}
2014-03-13 23:06:00 -03:00
2014-03-16 02:05:22 -03:00
/// trucate - truncate any mission items beyond index
2014-03-13 23:06:00 -03:00
void AP_Mission : : truncate ( uint16_t index )
{
2014-03-23 22:52:27 -03:00
if ( ( unsigned ) _cmd_total > index ) {
2014-03-13 23:06:00 -03:00
_cmd_total . set_and_save ( index ) ;
}
}
2014-02-24 01:50:24 -04:00
/// update - ensures the command queues are loaded with the next command and calls main programs command_init and command_verify functions to progress the mission
/// should be called at 10hz or higher
void AP_Mission : : update ( )
2014-02-22 20:14:44 -04:00
{
2014-02-24 01:50:24 -04:00
// exit immediately if not running or no mission commands
if ( _flags . state ! = MISSION_RUNNING | | _cmd_total = = 0 ) {
return ;
}
// check if we have an active nav command
if ( ! _flags . nav_cmd_loaded | | _nav_cmd . index = = AP_MISSION_CMD_INDEX_NONE ) {
// advance in mission if no active nav command
if ( ! advance_current_nav_cmd ( ) ) {
// failure to advance nav command means mission has completed
complete ( ) ;
return ;
}
} else {
// run the active nav command
if ( _cmd_verify_fn ( _nav_cmd ) ) {
// market _nav_cmd as complete (it will be started on the next iteration)
_flags . nav_cmd_loaded = false ;
2014-08-27 05:04:30 -03:00
// immediately advance to the next mission command
if ( ! advance_current_nav_cmd ( ) ) {
// failure to advance nav command means mission has completed
complete ( ) ;
return ;
}
2014-02-24 01:50:24 -04:00
}
}
// check if we have an active do command
2015-07-17 00:13:28 -03:00
if ( ! _flags . do_cmd_loaded ) {
2014-02-24 01:50:24 -04:00
advance_current_do_cmd ( ) ;
} else {
// run the active do command
if ( _cmd_verify_fn ( _do_cmd ) ) {
// market _nav_cmd as complete (it will be started on the next iteration)
_flags . do_cmd_loaded = false ;
}
}
2014-02-22 20:14:44 -04:00
}
2014-02-24 01:50:24 -04:00
///
/// public command methods
///
2014-02-22 20:14:44 -04:00
/// add_cmd - adds a command to the end of the command list and writes to storage
/// returns true if successfully added, false on failure
/// cmd.index is updated with it's new position in the mission
bool AP_Mission : : add_cmd ( Mission_Command & cmd )
{
// attempt to write the command to storage
bool ret = write_cmd_to_storage ( _cmd_total , cmd ) ;
if ( ret ) {
// update command's index
cmd . index = _cmd_total ;
// increment total number of commands
_cmd_total . set_and_save ( _cmd_total + 1 ) ;
}
return ret ;
}
2014-02-28 22:12:41 -04:00
/// replace_cmd - replaces the command at position 'index' in the command list with the provided cmd
/// replacing the current active command will have no effect until the command is restarted
/// returns true if successfully replaced, false on failure
bool AP_Mission : : replace_cmd ( uint16_t index , Mission_Command & cmd )
{
// sanity check index
2014-03-23 22:52:27 -03:00
if ( index > = ( unsigned ) _cmd_total ) {
2014-02-28 22:12:41 -04:00
return false ;
}
// attempt to write the command to storage
return write_cmd_to_storage ( index , cmd ) ;
}
2014-02-24 01:50:24 -04:00
/// is_nav_cmd - returns true if the command's id is a "navigation" command, false if "do" or "conditional" command
bool AP_Mission : : is_nav_cmd ( const Mission_Command & cmd )
{
2017-08-02 02:25:57 -03:00
// NAV commands all have ids below MAV_CMD_NAV_LAST except NAV_SET_YAW_SPEED
return ( cmd . id < = MAV_CMD_NAV_LAST | | cmd . id = = MAV_CMD_NAV_SET_YAW_SPEED ) ;
2014-02-24 01:50:24 -04:00
}
/// get_next_nav_cmd - gets next "navigation" command found at or after start_index
/// returns true if found, false if not found (i.e. reached end of mission command list)
/// accounts for do_jump commands but never increments the jump's num_times_run (advance_current_nav_cmd is responsible for this)
2014-02-28 08:49:37 -04:00
bool AP_Mission : : get_next_nav_cmd ( uint16_t start_index , Mission_Command & cmd )
2014-02-24 01:50:24 -04:00
{
2014-02-28 08:49:37 -04:00
uint16_t cmd_index = start_index ;
2014-02-24 01:50:24 -04:00
// search until the end of the mission command list
2014-03-23 22:52:27 -03:00
while ( cmd_index < ( unsigned ) _cmd_total ) {
2014-02-24 01:50:24 -04:00
// get next command
2014-04-06 20:29:54 -03:00
if ( ! get_next_cmd ( cmd_index , cmd , false ) ) {
2014-02-24 01:50:24 -04:00
// no more commands so return failure
return false ;
} else {
// if found a "navigation" command then return it
2014-04-06 20:29:54 -03:00
if ( is_nav_cmd ( cmd ) ) {
2014-02-24 01:50:24 -04:00
return true ;
} else {
// move on in list
cmd_index + + ;
}
}
}
// if we got this far we did not find a navigation command
return false ;
}
2014-04-06 20:29:54 -03:00
/// get the ground course of the next navigation leg in centidegrees
/// from 0 36000. Return default_angle if next navigation
/// leg cannot be determined
int32_t AP_Mission : : get_next_ground_course_cd ( int32_t default_angle )
{
Mission_Command cmd ;
if ( ! get_next_nav_cmd ( _nav_cmd . index + 1 , cmd ) ) {
return default_angle ;
}
2017-08-02 02:25:57 -03:00
// special handling for nav commands with no target location
if ( cmd . id = = MAV_CMD_NAV_GUIDED_ENABLE | |
cmd . id = = MAV_CMD_NAV_DELAY ) {
return default_angle ;
}
if ( cmd . id = = MAV_CMD_NAV_SET_YAW_SPEED ) {
return ( _nav_cmd . content . set_yaw_speed . angle_deg * 100 ) ;
}
2014-04-06 20:29:54 -03:00
return get_bearing_cd ( _nav_cmd . content . location , cmd . content . location ) ;
}
2014-02-28 21:19:38 -04:00
// set_current_cmd - jumps to command specified by index
2014-03-04 08:24:49 -04:00
bool AP_Mission : : set_current_cmd ( uint16_t index )
2014-02-28 21:19:38 -04:00
{
Mission_Command cmd ;
2014-03-07 04:01:05 -04:00
// sanity check index and that we have a mission
2014-03-23 22:52:27 -03:00
if ( index > = ( unsigned ) _cmd_total | | _cmd_total = = 1 ) {
2014-02-28 21:19:38 -04:00
return false ;
}
// stop the current running do command
_do_cmd . index = AP_MISSION_CMD_INDEX_NONE ;
_flags . do_cmd_loaded = false ;
_flags . do_cmd_all_done = false ;
// stop current nav cmd
_flags . nav_cmd_loaded = false ;
2014-03-07 04:01:05 -04:00
// if index is zero then the user wants to completely restart the mission
if ( index = = 0 | | _flags . state = = MISSION_COMPLETE ) {
2016-05-13 20:06:25 -03:00
_prev_nav_cmd_id = AP_MISSION_CMD_ID_NONE ;
2014-03-07 04:01:05 -04:00
_prev_nav_cmd_index = AP_MISSION_CMD_INDEX_NONE ;
2015-08-23 22:06:31 -03:00
_prev_nav_cmd_wp_index = AP_MISSION_CMD_INDEX_NONE ;
2014-03-07 04:01:05 -04:00
// reset the jump tracking to zero
init_jump_tracking ( ) ;
2014-03-14 09:37:56 -03:00
if ( index = = 0 ) {
index = 1 ;
}
2014-03-07 04:01:05 -04:00
}
// if the mission is stopped or completed move the nav_cmd index to the specified point and set the state to stopped
// so that if the user resumes the mission it will begin at the specified index
if ( _flags . state ! = MISSION_RUNNING ) {
// search until we find next nav command or reach end of command list
while ( ! _flags . nav_cmd_loaded ) {
// get next command
if ( ! get_next_cmd ( index , cmd , true ) ) {
_nav_cmd . index = AP_MISSION_CMD_INDEX_NONE ;
return false ;
}
// check if navigation or "do" command
if ( is_nav_cmd ( cmd ) ) {
// set current navigation command
_nav_cmd = cmd ;
_flags . nav_cmd_loaded = true ;
} else {
// set current do command
if ( ! _flags . do_cmd_loaded ) {
_do_cmd = cmd ;
_flags . do_cmd_loaded = true ;
}
}
// move onto next command
index = cmd . index + 1 ;
}
2015-07-17 00:13:28 -03:00
// if we have not found a do command then set flag to show there are no do-commands to be run before nav command completes
if ( ! _flags . do_cmd_loaded ) {
_flags . do_cmd_all_done = true ;
}
2014-03-07 04:01:05 -04:00
// if we got this far then the mission can safely be "resumed" from the specified index so we set the state to "stopped"
_flags . state = MISSION_STOPPED ;
return true ;
}
// the state must be MISSION_RUNNING
2014-02-28 21:19:38 -04:00
// search until we find next nav command or reach end of command list
while ( ! _flags . nav_cmd_loaded ) {
// get next command
if ( ! get_next_cmd ( index , cmd , true ) ) {
// if we run out of nav commands mark mission as complete
complete ( ) ;
// return true because we did what was requested
// which was apparently to jump to a command at the end of the mission
return true ;
}
// check if navigation or "do" command
if ( is_nav_cmd ( cmd ) ) {
// save previous nav command index
2016-05-13 20:06:25 -03:00
_prev_nav_cmd_id = _nav_cmd . id ;
2014-02-28 21:19:38 -04:00
_prev_nav_cmd_index = _nav_cmd . index ;
2015-08-23 22:06:31 -03:00
// save separate previous nav command index if it contains lat,long,alt
2015-08-27 02:42:42 -03:00
if ( ! ( cmd . content . location . lat = = 0 & & cmd . content . location . lng = = 0 ) ) {
2015-08-23 22:06:31 -03:00
_prev_nav_cmd_wp_index = _nav_cmd . index ;
}
2014-02-28 21:19:38 -04:00
// set current navigation command and start it
_nav_cmd = cmd ;
_flags . nav_cmd_loaded = true ;
_cmd_start_fn ( _nav_cmd ) ;
} else {
// set current do command and start it (if not already set)
if ( ! _flags . do_cmd_loaded ) {
_do_cmd = cmd ;
_flags . do_cmd_loaded = true ;
_cmd_start_fn ( _do_cmd ) ;
}
}
// move onto next command
index = cmd . index + 1 ;
}
2015-07-17 00:13:28 -03:00
// if we have not found a do command then set flag to show there are no do-commands to be run before nav command completes
if ( ! _flags . do_cmd_loaded ) {
_flags . do_cmd_all_done = true ;
}
2014-02-28 21:19:38 -04:00
// if we got this far we must have successfully advanced the nav command
return true ;
}
2014-02-22 20:14:44 -04:00
/// load_cmd_from_storage - load command from storage
/// true is return if successful
2014-02-28 08:49:37 -04:00
bool AP_Mission : : read_cmd_from_storage ( uint16_t index , Mission_Command & cmd ) const
2014-02-22 20:14:44 -04:00
{
2014-02-28 08:23:38 -04:00
// exit immediately if index is beyond last command but we always let cmd #0 (i.e. home) be read
2017-01-21 00:54:02 -04:00
if ( index > = ( unsigned ) _cmd_total & & index ! = 0 ) {
2014-02-22 20:14:44 -04:00
return false ;
}
2014-02-27 22:58:27 -04:00
// special handling for command #0 which is home
if ( index = = 0 ) {
cmd . index = 0 ;
cmd . id = MAV_CMD_NAV_WAYPOINT ;
2014-03-10 23:23:44 -03:00
cmd . p1 = 0 ;
2014-02-27 22:58:27 -04:00
cmd . content . location = _ahrs . get_home ( ) ;
} else {
// Find out proper location in memory by using the start_byte position + the index
// we can load a command, we don't process it yet
// read WP position
2014-08-13 01:43:37 -03:00
uint16_t pos_in_storage = 4 + ( index * AP_MISSION_EEPROM_COMMAND_SIZE ) ;
2014-02-22 20:14:44 -04:00
2016-04-22 04:58:42 -03:00
uint8_t b1 = _storage . read_byte ( pos_in_storage ) ;
if ( b1 = = 0 ) {
cmd . id = _storage . read_uint16 ( pos_in_storage + 1 ) ;
cmd . p1 = _storage . read_uint16 ( pos_in_storage + 3 ) ;
_storage . read_block ( cmd . content . bytes , pos_in_storage + 5 , 10 ) ;
} else {
cmd . id = b1 ;
cmd . p1 = _storage . read_uint16 ( pos_in_storage + 1 ) ;
_storage . read_block ( cmd . content . bytes , pos_in_storage + 3 , 12 ) ;
}
2014-02-27 09:02:12 -04:00
2014-02-27 22:58:27 -04:00
// set command's index to it's position in eeprom
cmd . index = index ;
}
2014-02-22 20:14:44 -04:00
// return success
return true ;
}
/// write_cmd_to_storage - write a command to storage
/// index is used to calculate the storage location
/// true is returned if successful
2014-02-28 08:49:37 -04:00
bool AP_Mission : : write_cmd_to_storage ( uint16_t index , Mission_Command & cmd )
2014-02-22 20:14:44 -04:00
{
// range check cmd's index
2014-08-13 01:43:37 -03:00
if ( index > = num_commands_max ( ) ) {
2014-02-22 20:14:44 -04:00
return false ;
}
// calculate where in storage the command should be placed
2014-08-13 01:43:37 -03:00
uint16_t pos_in_storage = 4 + ( index * AP_MISSION_EEPROM_COMMAND_SIZE ) ;
2014-02-22 20:14:44 -04:00
2016-04-22 04:58:42 -03:00
if ( cmd . id < 256 ) {
_storage . write_byte ( pos_in_storage , cmd . id ) ;
_storage . write_uint16 ( pos_in_storage + 1 , cmd . p1 ) ;
_storage . write_block ( pos_in_storage + 3 , cmd . content . bytes , 12 ) ;
} else {
// if the command ID is above 256 we store a 0 followed by the 16 bit command ID
_storage . write_byte ( pos_in_storage , 0 ) ;
_storage . write_uint16 ( pos_in_storage + 1 , cmd . id ) ;
_storage . write_uint16 ( pos_in_storage + 3 , cmd . p1 ) ;
_storage . write_block ( pos_in_storage + 5 , cmd . content . bytes , 10 ) ;
}
2014-02-22 20:14:44 -04:00
2014-08-06 03:17:11 -03:00
// remember when the mission last changed
2015-11-19 23:12:21 -04:00
_last_change_time_ms = AP_HAL : : millis ( ) ;
2014-08-06 03:17:11 -03:00
2014-02-22 20:14:44 -04:00
// return success
return true ;
}
2014-03-03 01:36:37 -04:00
/// write_home_to_storage - writes the special purpose cmd 0 (home) to storage
/// home is taken directly from ahrs
void AP_Mission : : write_home_to_storage ( )
{
2014-03-10 23:23:44 -03:00
Mission_Command home_cmd = { } ;
2014-03-03 01:36:37 -04:00
home_cmd . id = MAV_CMD_NAV_WAYPOINT ;
home_cmd . content . location = _ahrs . get_home ( ) ;
write_cmd_to_storage ( 0 , home_cmd ) ;
}
2018-04-26 02:46:46 -03:00
MAV_MISSION_RESULT AP_Mission : : sanity_check_params ( const mavlink_mission_item_int_t & packet ) {
uint8_t nan_mask ;
switch ( packet . command ) {
case MAV_CMD_NAV_WAYPOINT :
nan_mask = ~ ( 1 < < 3 ) ; // param 4 can be nan
break ;
case MAV_CMD_NAV_LAND :
nan_mask = ~ ( 1 < < 3 ) ; // param 4 can be nan
break ;
case MAV_CMD_NAV_TAKEOFF :
nan_mask = ~ ( 1 < < 3 ) ; // param 4 can be nan
break ;
case MAV_CMD_NAV_VTOL_TAKEOFF :
nan_mask = ~ ( 1 < < 3 ) ; // param 4 can be nan
break ;
case MAV_CMD_NAV_VTOL_LAND :
2018-04-26 19:21:18 -03:00
nan_mask = ~ ( ( 1 < < 2 ) | ( 1 < < 3 ) ) ; // param 3 and 4 can be nan
2018-04-26 02:46:46 -03:00
break ;
default :
nan_mask = 0xff ;
break ;
}
if ( ( ( nan_mask & ( 1 < < 0 ) ) & & isnan ( packet . param1 ) ) | |
isinf ( packet . param1 ) ) {
return MAV_MISSION_INVALID_PARAM1 ;
}
if ( ( ( nan_mask & ( 1 < < 1 ) ) & & isnan ( packet . param2 ) ) | |
isinf ( packet . param2 ) ) {
return MAV_MISSION_INVALID_PARAM2 ;
}
if ( ( ( nan_mask & ( 1 < < 2 ) ) & & isnan ( packet . param3 ) ) | |
isinf ( packet . param3 ) ) {
return MAV_MISSION_INVALID_PARAM3 ;
}
if ( ( ( nan_mask & ( 1 < < 3 ) ) & & isnan ( packet . param4 ) ) | |
isinf ( packet . param4 ) ) {
return MAV_MISSION_INVALID_PARAM4 ;
}
return MAV_MISSION_ACCEPTED ;
}
2014-02-28 02:55:02 -04:00
// mavlink_to_mission_cmd - converts mavlink message to an AP_Mission::Mission_Command object which can be stored to eeprom
2015-12-21 01:02:23 -04:00
// return MAV_MISSION_ACCEPTED on success, MAV_MISSION_RESULT error on failure
2016-02-28 02:47:00 -04:00
MAV_MISSION_RESULT AP_Mission : : mavlink_int_to_mission_cmd ( const mavlink_mission_item_int_t & packet , AP_Mission : : Mission_Command & cmd )
2014-02-28 02:55:02 -04:00
{
bool copy_location = false ;
2014-03-03 01:36:37 -04:00
bool copy_alt = false ;
2014-02-28 02:55:02 -04:00
// command's position in mission list and mavlink id
cmd . index = packet . seq ;
cmd . id = packet . command ;
2014-12-03 03:29:43 -04:00
cmd . content . location . options = 0 ;
2014-02-28 02:55:02 -04:00
2018-04-26 02:46:46 -03:00
MAV_MISSION_RESULT param_check = sanity_check_params ( packet ) ;
if ( param_check ! = MAV_MISSION_ACCEPTED ) {
return param_check ;
}
2014-02-28 02:55:02 -04:00
// command specific conversions from mavlink packet to mission command
switch ( cmd . id ) {
2016-04-22 04:58:42 -03:00
case 0 :
// this is reserved for storing 16 bit command IDs
return MAV_MISSION_INVALID ;
2014-02-28 02:55:02 -04:00
case MAV_CMD_NAV_WAYPOINT : // MAV ID: 16
2016-12-18 10:39:44 -04:00
{
2014-02-28 02:55:02 -04:00
copy_location = true ;
2014-09-02 22:23:08 -03:00
/*
the 15 byte limit means we can ' t fit both delay and radius
in the cmd structure . When we expand the mission structure
we can do this properly
*/
2014-09-03 00:28:17 -03:00
# if APM_BUILD_TYPE(APM_BUILD_ArduPlane)
2016-12-18 10:39:44 -04:00
// acceptance radius in meters and pass by distance in meters
uint16_t acp = packet . param2 ; // param 2 is acceptance radius in meters is held in low p1
uint16_t passby = packet . param3 ; // param 3 is pass by distance in meters is held in high p1
2017-01-06 21:29:05 -04:00
// limit to 255 so it does not wrap during the shift or mask operation
passby = MIN ( 0xFF , passby ) ;
acp = MIN ( 0xFF , acp ) ;
2016-12-18 10:39:44 -04:00
cmd . p1 = ( passby < < 8 ) | ( acp & 0x00FF ) ;
2014-09-02 22:23:08 -03:00
# else
2016-12-18 10:39:44 -04:00
// delay at waypoint in seconds (this is for copters???)
cmd . p1 = packet . param1 ;
2014-09-02 22:23:08 -03:00
# endif
2016-12-18 10:39:44 -04:00
}
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_NAV_LOITER_UNLIM : // MAV ID: 17
copy_location = true ;
2016-01-27 15:35:41 -04:00
cmd . p1 = fabsf ( packet . param3 ) ; // store radius as 16bit since no other params are competing for space
2014-03-17 02:14:45 -03:00
cmd . content . location . flags . loiter_ccw = ( packet . param3 < 0 ) ; // -1 = counter clockwise, +1 = clockwise
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_NAV_LOITER_TURNS : // MAV ID: 18
2016-03-02 11:16:27 -04:00
{
2014-02-28 02:55:02 -04:00
copy_location = true ;
2016-03-02 11:16:27 -04:00
uint16_t num_turns = packet . param1 ; // param 1 is number of times to circle is held in low p1
uint16_t radius_m = fabsf ( packet . param3 ) ; // param 3 is radius in meters is held in high p1
cmd . p1 = ( radius_m < < 8 ) | ( num_turns & 0x00FF ) ; // store radius in high byte of p1, num turns in low byte of p1
2014-03-03 01:36:37 -04:00
cmd . content . location . flags . loiter_ccw = ( packet . param3 < 0 ) ;
2016-03-14 15:42:49 -03:00
cmd . content . location . flags . loiter_xtrack = ( packet . param4 > 0 ) ; // 0 to xtrack from center of waypoint, 1 to xtrack from tangent exit location
2016-03-02 11:16:27 -04:00
}
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_NAV_LOITER_TIME : // MAV ID: 19
copy_location = true ;
2016-01-27 15:35:41 -04:00
cmd . p1 = packet . param1 ; // loiter time in seconds uses all 16 bits, 8bit seconds is too small. No room for radius.
2014-03-03 01:36:37 -04:00
cmd . content . location . flags . loiter_ccw = ( packet . param3 < 0 ) ;
2016-03-14 15:42:49 -03:00
cmd . content . location . flags . loiter_xtrack = ( packet . param4 > 0 ) ; // 0 to xtrack from center of waypoint, 1 to xtrack from tangent exit location
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_NAV_RETURN_TO_LAUNCH : // MAV ID: 20
break ;
case MAV_CMD_NAV_LAND : // MAV ID: 21
copy_location = true ;
2015-08-28 22:33:48 -03:00
cmd . p1 = packet . param1 ; // abort target altitude(m) (plane only)
2017-10-03 21:30:41 -03:00
cmd . content . location . flags . loiter_ccw = is_negative ( packet . param4 ) ; // yaw direction, (plane deepstall only)
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_NAV_TAKEOFF : // MAV ID: 22
copy_location = true ; // only altitude is used
2014-03-03 01:36:37 -04:00
cmd . p1 = packet . param1 ; // minimum pitch (plane only)
2014-02-28 02:55:02 -04:00
break ;
2014-10-21 17:45:24 -03:00
case MAV_CMD_NAV_CONTINUE_AND_CHANGE_ALT : // MAV ID: 30
2015-08-24 06:40:49 -03:00
copy_location = true ; // lat/lng used for heading lock
2015-08-18 23:45:48 -03:00
cmd . p1 = packet . param1 ; // Climb/Descend
// 0 = Neutral, cmd complete at +/- 5 of indicated alt.
// 1 = Climb, cmd complete at or above indicated alt.
// 2 = Descend, cmd complete at or below indicated alt.
2014-10-21 17:45:24 -03:00
break ;
2015-03-13 18:47:37 -03:00
case MAV_CMD_NAV_LOITER_TO_ALT : // MAV ID: 31
copy_location = true ;
2016-03-02 11:16:27 -04:00
cmd . p1 = fabsf ( packet . param2 ) ; // param2 is radius in meters
2016-01-27 15:35:41 -04:00
cmd . content . location . flags . loiter_ccw = ( packet . param2 < 0 ) ;
2016-03-14 15:42:49 -03:00
cmd . content . location . flags . loiter_xtrack = ( packet . param4 > 0 ) ; // 0 to xtrack from center of waypoint, 1 to xtrack from tangent exit location
2015-03-13 18:47:37 -03:00
break ;
2014-03-22 00:45:26 -03:00
case MAV_CMD_NAV_SPLINE_WAYPOINT : // MAV ID: 82
copy_location = true ;
cmd . p1 = packet . param1 ; // delay at waypoint in seconds
break ;
2014-10-13 04:03:56 -03:00
case MAV_CMD_NAV_GUIDED_ENABLE : // MAV ID: 92
cmd . p1 = packet . param1 ; // on/off. >0.5 means "on", hand-over control to external controller
2014-06-02 06:02:04 -03:00
break ;
2016-04-18 04:12:40 -03:00
case MAV_CMD_NAV_DELAY : // MAV ID: 94
cmd . content . nav_delay . seconds = packet . param1 ; // delay in seconds
cmd . content . nav_delay . hour_utc = packet . param2 ; // absolute time's hour (utc)
cmd . content . nav_delay . min_utc = packet . param3 ; // absolute time's min (utc)
cmd . content . nav_delay . sec_utc = packet . param4 ; // absolute time's second (utc)
break ;
2014-02-28 02:55:02 -04:00
case MAV_CMD_CONDITION_DELAY : // MAV ID: 112
2014-03-17 02:14:45 -03:00
cmd . content . delay . seconds = packet . param1 ; // delay in seconds
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_CONDITION_DISTANCE : // MAV ID: 114
2014-03-17 02:14:45 -03:00
cmd . content . distance . meters = packet . param1 ; // distance in meters from next waypoint
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_CONDITION_YAW : // MAV ID: 115
2014-03-17 02:14:45 -03:00
cmd . content . yaw . angle_deg = packet . param1 ; // target angle in degrees
cmd . content . yaw . turn_rate_dps = packet . param2 ; // 0 = use default turn rate otherwise specific turn rate in deg/sec
cmd . content . yaw . direction = packet . param3 ; // -1 = ccw, +1 = cw
cmd . content . yaw . relative_angle = packet . param4 ; // lng=0: absolute angle provided, lng=1: relative angle provided
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_DO_SET_MODE : // MAV ID: 176
2014-03-17 02:14:45 -03:00
cmd . p1 = packet . param1 ; // flight mode identifier
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_DO_JUMP : // MAV ID: 177
cmd . content . jump . target = packet . param1 ; // jump-to command number
cmd . content . jump . num_times = packet . param2 ; // repeat count
break ;
case MAV_CMD_DO_CHANGE_SPEED : // MAV ID: 178
2014-03-17 02:14:45 -03:00
cmd . content . speed . speed_type = packet . param1 ; // 0 = airspeed, 1 = ground speed
cmd . content . speed . target_ms = packet . param2 ; // target speed in m/s
cmd . content . speed . throttle_pct = packet . param3 ; // throttle as a percentage from 0 ~ 100%
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_DO_SET_HOME :
copy_location = true ;
2014-03-17 02:14:45 -03:00
cmd . p1 = packet . param1 ; // p1=0 means use current location, p=1 means use provided location
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_DO_SET_RELAY : // MAV ID: 181
2014-03-17 02:14:45 -03:00
cmd . content . relay . num = packet . param1 ; // relay number
cmd . content . relay . state = packet . param2 ; // 0:off, 1:on
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_DO_REPEAT_RELAY : // MAV ID: 182
2014-03-18 23:13:04 -03:00
cmd . content . repeat_relay . num = packet . param1 ; // relay number
cmd . content . repeat_relay . repeat_count = packet . param2 ; // count
cmd . content . repeat_relay . cycle_time = packet . param3 ; // time converted from seconds to milliseconds
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_DO_SET_SERVO : // MAV ID: 183
2014-03-17 02:14:45 -03:00
cmd . content . servo . channel = packet . param1 ; // channel
cmd . content . servo . pwm = packet . param2 ; // PWM
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_DO_REPEAT_SERVO : // MAV ID: 184
2014-03-18 23:13:04 -03:00
cmd . content . repeat_servo . channel = packet . param1 ; // channel
cmd . content . repeat_servo . pwm = packet . param2 ; // PWM
cmd . content . repeat_servo . repeat_count = packet . param3 ; // count
cmd . content . repeat_servo . cycle_time = packet . param4 ; // time in seconds
2014-02-28 02:55:02 -04:00
break ;
2014-10-17 14:34:04 -03:00
case MAV_CMD_DO_LAND_START : // MAV ID: 189
copy_location = true ;
break ;
2014-02-28 02:55:02 -04:00
case MAV_CMD_DO_SET_ROI : // MAV ID: 201
copy_location = true ;
2014-03-17 02:14:45 -03:00
cmd . p1 = packet . param1 ; // 0 = no roi, 1 = next waypoint, 2 = waypoint number, 3 = fixed location, 4 = given target (not supported)
2014-02-28 02:55:02 -04:00
break ;
2015-03-28 22:29:21 -03:00
case MAV_CMD_DO_DIGICAM_CONFIGURE : // MAV ID: 202
cmd . content . digicam_configure . shooting_mode = packet . param1 ;
cmd . content . digicam_configure . shutter_speed = packet . param2 ;
cmd . content . digicam_configure . aperture = packet . param3 ;
cmd . content . digicam_configure . ISO = packet . param4 ;
cmd . content . digicam_configure . exposure_type = packet . x ;
cmd . content . digicam_configure . cmd_id = packet . y ;
cmd . content . digicam_configure . engine_cutoff_time = packet . z ;
break ;
2014-02-28 02:55:02 -04:00
case MAV_CMD_DO_DIGICAM_CONTROL : // MAV ID: 203
2015-03-28 22:29:21 -03:00
cmd . content . digicam_control . session = packet . param1 ;
cmd . content . digicam_control . zoom_pos = packet . param2 ;
cmd . content . digicam_control . zoom_step = packet . param3 ;
cmd . content . digicam_control . focus_lock = packet . param4 ;
cmd . content . digicam_control . shooting_cmd = packet . x ;
cmd . content . digicam_control . cmd_id = packet . y ;
2015-03-21 08:56:50 -03:00
break ;
2014-02-28 02:55:02 -04:00
case MAV_CMD_DO_MOUNT_CONTROL : // MAV ID: 205
2015-03-21 08:56:50 -03:00
cmd . content . mount_control . pitch = packet . param1 ;
cmd . content . mount_control . roll = packet . param2 ;
cmd . content . mount_control . yaw = packet . param3 ;
2014-02-28 02:55:02 -04:00
break ;
case MAV_CMD_DO_SET_CAM_TRIGG_DIST : // MAV ID: 206
2014-03-17 02:14:45 -03:00
cmd . content . cam_trigg_dist . meters = packet . param1 ; // distance between camera shots in meters
2014-02-28 02:55:02 -04:00
break ;
2014-10-25 18:19:21 -03:00
case MAV_CMD_DO_FENCE_ENABLE : // MAV ID: 207
cmd . p1 = packet . param1 ; // action 0=disable, 1=enable
break ;
2014-04-03 05:49:04 -03:00
case MAV_CMD_DO_PARACHUTE : // MAV ID: 208
cmd . p1 = packet . param1 ; // action 0=disable, 1=enable, 2=release. See PARACHUTE_ACTION enum
break ;
2014-06-05 02:44:18 -03:00
case MAV_CMD_DO_INVERTED_FLIGHT : // MAV ID: 210
cmd . p1 = packet . param1 ; // normal=0 inverted=1
break ;
2014-09-17 04:21:12 -03:00
case MAV_CMD_DO_GRIPPER : // MAV ID: 211
cmd . content . gripper . num = packet . param1 ; // gripper number
cmd . content . gripper . action = packet . param2 ; // action 0=release, 1=grab. See GRIPPER_ACTION enum
break ;
2014-10-13 04:03:56 -03:00
case MAV_CMD_DO_GUIDED_LIMITS : // MAV ID: 222
cmd . p1 = packet . param1 ; // max time in seconds the external controller will be allowed to control the vehicle
cmd . content . guided_limits . alt_min = packet . param2 ; // min alt below which the command will be aborted. 0 for no lower alt limit
cmd . content . guided_limits . alt_max = packet . param3 ; // max alt above which the command will be aborted. 0 for no upper alt limit
cmd . content . guided_limits . horiz_max = packet . param4 ; // max horizontal distance the vehicle can move before the command will be aborted. 0 for no horizontal limit
2015-07-16 23:25:42 -03:00
break ;
2014-04-23 09:36:56 -03:00
2014-08-14 03:03:01 -03:00
case MAV_CMD_DO_AUTOTUNE_ENABLE : // MAV ID: 211
cmd . p1 = packet . param1 ; // disable=0 enable=1
break ;
case MAV_CMD_NAV_ALTITUDE_WAIT : // MAV ID: 83
2014-04-23 09:36:56 -03:00
cmd . content . altitude_wait . altitude = packet . param1 ;
cmd . content . altitude_wait . descent_rate = packet . param2 ;
cmd . content . altitude_wait . wiggle_time = packet . param3 ;
2014-10-13 04:03:56 -03:00
break ;
2016-01-01 05:41:52 -04:00
case MAV_CMD_NAV_VTOL_TAKEOFF :
copy_location = true ;
break ;
case MAV_CMD_NAV_VTOL_LAND :
copy_location = true ;
break ;
2016-04-22 05:22:12 -03:00
case MAV_CMD_DO_VTOL_TRANSITION :
cmd . content . do_vtol_transition . target_state = packet . param1 ;
break ;
2016-07-23 06:02:48 -03:00
2016-07-14 04:35:49 -03:00
case MAV_CMD_DO_SET_REVERSE :
cmd . p1 = packet . param1 ; // 0 = forward, 1 = reverse
break ;
2016-07-23 06:02:48 -03:00
case MAV_CMD_DO_ENGINE_CONTROL :
cmd . content . do_engine_control . start_control = ( packet . param1 > 0 ) ;
cmd . content . do_engine_control . cold_start = ( packet . param2 > 0 ) ;
cmd . content . do_engine_control . height_delay_cm = packet . param3 * 100 ;
break ;
2016-11-17 01:19:05 -04:00
case MAV_CMD_NAV_PAYLOAD_PLACE :
cmd . p1 = packet . param1 * 100 ; // copy max-descend parameter (m->cm)
copy_location = true ;
break ;
2017-08-02 02:25:57 -03:00
case MAV_CMD_NAV_SET_YAW_SPEED :
cmd . content . set_yaw_speed . angle_deg = packet . param1 ; // target angle in degrees
cmd . content . set_yaw_speed . speed = packet . param2 ; // speed in meters/second
cmd . content . set_yaw_speed . relative_angle = packet . param3 ; // 0 = absolute angle, 1 = relative angle
break ;
2017-10-06 21:45:35 -03:00
case MAV_CMD_DO_WINCH : // MAV ID: 42600
cmd . content . winch . num = packet . param1 ; // winch number
cmd . content . winch . action = packet . param2 ; // action (0 = relax, 1 = length control, 2 = rate control). See WINCH_ACTION enum
cmd . content . winch . release_length = packet . param3 ; // cable distance to unwind in meters, negative numbers to wind in cable
cmd . content . winch . release_rate = packet . param4 ; // release rate in meters/second
break ;
2014-02-28 02:55:02 -04:00
default :
// unrecognised command
2015-12-21 01:02:23 -04:00
return MAV_MISSION_UNSUPPORTED ;
2014-02-28 02:55:02 -04:00
}
// copy location from mavlink to command
2014-03-03 01:36:37 -04:00
if ( copy_location | | copy_alt ) {
2015-08-27 02:22:05 -03:00
// sanity check location
if ( copy_location ) {
2016-06-06 17:08:37 -03:00
if ( ! check_lat ( packet . x ) ) {
2015-12-21 01:02:23 -04:00
return MAV_MISSION_INVALID_PARAM5_X ;
}
2016-06-06 17:08:37 -03:00
if ( ! check_lng ( packet . y ) ) {
2015-12-21 01:02:23 -04:00
return MAV_MISSION_INVALID_PARAM6_Y ;
2015-08-27 02:22:05 -03:00
}
}
2018-04-26 02:46:46 -03:00
if ( isnan ( packet . z ) | | fabsf ( packet . z ) > = LOCATION_ALT_MAX_M ) {
2015-12-21 01:02:23 -04:00
return MAV_MISSION_INVALID_PARAM7 ;
2015-10-19 04:14:00 -03:00
}
2015-08-27 02:22:05 -03:00
2017-10-13 15:16:41 -03:00
if ( copy_location ) {
cmd . content . location . lat = packet . x ;
cmd . content . location . lng = packet . y ;
}
cmd . content . location . alt = packet . z * 100.0f ; // convert packet's alt (m) to cmd alt (cm)
2014-03-03 01:36:37 -04:00
switch ( packet . frame ) {
case MAV_FRAME_MISSION :
case MAV_FRAME_GLOBAL :
cmd . content . location . flags . relative_alt = 0 ;
break ;
case MAV_FRAME_GLOBAL_RELATIVE_ALT :
cmd . content . location . flags . relative_alt = 1 ;
break ;
2014-07-24 19:33:44 -03:00
# if AP_TERRAIN_AVAILABLE
case MAV_FRAME_GLOBAL_TERRAIN_ALT :
// we mark it as a relative altitude, as it doesn't have
// home alt added
cmd . content . location . flags . relative_alt = 1 ;
// mark altitude as above terrain, not above home
cmd . content . location . flags . terrain_alt = 1 ;
break ;
# endif
2014-03-03 01:36:37 -04:00
default :
2015-12-21 01:02:23 -04:00
return MAV_MISSION_UNSUPPORTED_FRAME ;
2014-02-28 02:55:02 -04:00
}
}
2016-05-12 13:59:11 -03:00
// if we got this far then it must have been successful
2015-12-21 01:02:23 -04:00
return MAV_MISSION_ACCEPTED ;
2014-02-28 02:55:02 -04:00
}
2016-02-28 02:47:00 -04:00
// converts a mission_item to mission_item_int and returns a mission_command
MAV_MISSION_RESULT AP_Mission : : mavlink_to_mission_cmd ( const mavlink_mission_item_t & packet , AP_Mission : : Mission_Command & cmd )
{
mavlink_mission_item_int_t mav_cmd = { } ;
mav_cmd . param1 = packet . param1 ;
mav_cmd . param2 = packet . param2 ;
mav_cmd . param3 = packet . param3 ;
mav_cmd . param4 = packet . param4 ;
mav_cmd . z = packet . z ;
mav_cmd . seq = packet . seq ;
mav_cmd . command = packet . command ;
mav_cmd . target_system = packet . target_system ;
mav_cmd . target_component = packet . target_component ;
mav_cmd . frame = packet . frame ;
mav_cmd . current = packet . current ;
mav_cmd . autocontinue = packet . autocontinue ;
/*
the strategy for handling both MISSION_ITEM and MISSION_ITEM_INT
is to pass the lat / lng in MISSION_ITEM_INT straight through , and
for MISSION_ITEM multiply by 1e7 here . We need an exception for
any commands which use the x and y fields not as
latitude / longitude .
*/
switch ( packet . command ) {
case MAV_CMD_DO_DIGICAM_CONTROL :
case MAV_CMD_DO_DIGICAM_CONFIGURE :
mav_cmd . x = packet . x ;
mav_cmd . y = packet . y ;
break ;
default :
// all other commands use x and y as lat/lon. We need to
// multiply by 1e7 to convert to int32_t
2016-06-06 17:08:37 -03:00
if ( ! check_lat ( packet . x ) ) {
2016-06-06 05:55:22 -03:00
return MAV_MISSION_INVALID_PARAM5_X ;
}
2016-06-06 17:08:37 -03:00
if ( ! check_lng ( packet . y ) ) {
2016-06-06 05:55:22 -03:00
return MAV_MISSION_INVALID_PARAM6_Y ;
}
2016-06-06 17:08:37 -03:00
mav_cmd . x = packet . x * 1.0e7 f ;
mav_cmd . y = packet . y * 1.0e7 f ;
2016-02-28 02:47:00 -04:00
break ;
}
MAV_MISSION_RESULT ans = mavlink_int_to_mission_cmd ( mav_cmd , cmd ) ;
return ans ;
}
// converts a Mission_Command to mission_item_int and returns a mission_item
bool AP_Mission : : mission_cmd_to_mavlink ( const AP_Mission : : Mission_Command & cmd , mavlink_mission_item_t & packet )
{
mavlink_mission_item_int_t mav_cmd = { } ;
bool ans = mission_cmd_to_mavlink_int ( cmd , ( mavlink_mission_item_int_t & ) mav_cmd ) ;
packet . param1 = mav_cmd . param1 ;
packet . param2 = mav_cmd . param2 ;
packet . param3 = mav_cmd . param3 ;
packet . param4 = mav_cmd . param4 ;
packet . z = mav_cmd . z ;
packet . seq = mav_cmd . seq ;
packet . command = mav_cmd . command ;
packet . target_system = mav_cmd . target_system ;
packet . target_component = mav_cmd . target_component ;
packet . frame = mav_cmd . frame ;
packet . current = mav_cmd . current ;
packet . autocontinue = mav_cmd . autocontinue ;
/*
the strategy for handling both MISSION_ITEM and MISSION_ITEM_INT
is to pass the lat / lng in MISSION_ITEM_INT straight through , and
for MISSION_ITEM multiply by 1e-7 here . We need an exception for
any commands which use the x and y fields not as
latitude / longitude .
*/
switch ( packet . command ) {
case MAV_CMD_DO_DIGICAM_CONTROL :
case MAV_CMD_DO_DIGICAM_CONFIGURE :
packet . x = mav_cmd . x ;
packet . y = mav_cmd . y ;
break ;
default :
// all other commands use x and y as lat/lon. We need to
// multiply by 1e-7 to convert to int32_t
packet . x = mav_cmd . x * 1.0e-7 f ;
packet . y = mav_cmd . y * 1.0e-7 f ;
break ;
}
return ans ;
}
2016-05-06 14:26:54 -03:00
// mavlink_cmd_long_to_mission_cmd - converts a mavlink cmd long to an AP_Mission::Mission_Command object which can be stored to eeprom
// return MAV_MISSION_ACCEPTED on success, MAV_MISSION_RESULT error on failure
MAV_MISSION_RESULT AP_Mission : : mavlink_cmd_long_to_mission_cmd ( const mavlink_command_long_t & packet , AP_Mission : : Mission_Command & cmd )
{
mavlink_mission_item_t miss_item = { 0 } ;
miss_item . param1 = packet . param1 ;
miss_item . param2 = packet . param2 ;
miss_item . param3 = packet . param3 ;
miss_item . param4 = packet . param4 ;
miss_item . command = packet . command ;
miss_item . target_system = packet . target_system ;
miss_item . target_component = packet . target_component ;
return mavlink_to_mission_cmd ( miss_item , cmd ) ;
}
2014-02-28 02:55:02 -04:00
// mission_cmd_to_mavlink - converts an AP_Mission::Mission_Command object to a mavlink message which can be sent to the GCS
// return true on success, false on failure
2016-02-28 02:47:00 -04:00
bool AP_Mission : : mission_cmd_to_mavlink_int ( const AP_Mission : : Mission_Command & cmd , mavlink_mission_item_int_t & packet )
2014-02-28 02:55:02 -04:00
{
bool copy_location = false ;
2014-03-03 01:36:37 -04:00
bool copy_alt = false ;
2014-02-28 02:55:02 -04:00
// command's position in mission list and mavlink id
packet . seq = cmd . index ;
packet . command = cmd . id ;
// set defaults
packet . current = 0 ; // 1 if we are passing back the mission command that is currently being executed
packet . param1 = 0 ;
packet . param2 = 0 ;
packet . param3 = 0 ;
packet . param4 = 0 ;
packet . autocontinue = 1 ;
// command specific conversions from mission command to mavlink packet
switch ( cmd . id ) {
2016-04-22 04:58:42 -03:00
case 0 :
// this is reserved for 16 bit command IDs
return false ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_NAV_WAYPOINT : // MAV ID: 16
2014-02-28 02:55:02 -04:00
copy_location = true ;
2014-09-03 08:15:41 -03:00
# if APM_BUILD_TYPE(APM_BUILD_ArduPlane)
// acceptance radius in meters
2016-12-18 10:39:44 -04:00
packet . param2 = LOWBYTE ( cmd . p1 ) ; // param 2 is acceptance radius in meters is held in low p1
packet . param3 = HIGHBYTE ( cmd . p1 ) ; // param 3 is pass by distance in meters is held in high p1
2014-09-03 08:15:41 -03:00
# else
// delay at waypoint in seconds
packet . param1 = cmd . p1 ;
# endif
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_NAV_LOITER_UNLIM : // MAV ID: 17
2014-02-28 02:55:02 -04:00
copy_location = true ;
2016-12-05 21:09:58 -04:00
packet . param3 = ( float ) cmd . p1 ;
2014-03-18 04:32:28 -03:00
if ( cmd . content . location . flags . loiter_ccw ) {
2016-12-05 21:09:58 -04:00
packet . param3 * = - 1 ;
2014-03-18 04:32:28 -03:00
}
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_NAV_LOITER_TURNS : // MAV ID: 18
2014-02-28 02:55:02 -04:00
copy_location = true ;
2014-06-11 04:17:19 -03:00
packet . param1 = LOWBYTE ( cmd . p1 ) ; // number of times to circle is held in low byte of p1
packet . param3 = HIGHBYTE ( cmd . p1 ) ; // radius is held in high byte of p1
2014-03-18 04:32:28 -03:00
if ( cmd . content . location . flags . loiter_ccw ) {
2014-06-11 04:17:19 -03:00
packet . param3 = - packet . param3 ;
2014-03-18 04:32:28 -03:00
}
2016-03-14 15:42:49 -03:00
packet . param4 = cmd . content . location . flags . loiter_xtrack ; // 0 to xtrack from center of waypoint, 1 to xtrack from tangent exit location
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_NAV_LOITER_TIME : // MAV ID: 19
2014-02-28 02:55:02 -04:00
copy_location = true ;
2014-03-17 02:14:45 -03:00
packet . param1 = cmd . p1 ; // loiter time in seconds
2014-03-18 04:32:28 -03:00
if ( cmd . content . location . flags . loiter_ccw ) {
packet . param3 = - 1 ;
2016-03-02 11:16:27 -04:00
} else {
2014-03-18 04:32:28 -03:00
packet . param3 = 1 ;
}
2016-03-14 15:42:49 -03:00
packet . param4 = cmd . content . location . flags . loiter_xtrack ; // 0 to xtrack from center of waypoint, 1 to xtrack from tangent exit location
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_NAV_RETURN_TO_LAUNCH : // MAV ID: 20
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_NAV_LAND : // MAV ID: 21
2014-02-28 02:55:02 -04:00
copy_location = true ;
2015-08-28 22:33:48 -03:00
packet . param1 = cmd . p1 ; // abort target altitude(m) (plane only)
2017-10-03 21:30:41 -03:00
packet . param4 = cmd . content . location . flags . loiter_ccw ? - 1 : 1 ; // yaw direction, (plane deepstall only)
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_NAV_TAKEOFF : // MAV ID: 22
2014-02-28 02:55:02 -04:00
copy_location = true ; // only altitude is used
2014-03-03 01:36:37 -04:00
packet . param1 = cmd . p1 ; // minimum pitch (plane only)
2014-02-28 02:55:02 -04:00
break ;
2014-10-21 17:45:24 -03:00
case MAV_CMD_NAV_CONTINUE_AND_CHANGE_ALT : // MAV ID: 30
2015-08-24 06:40:49 -03:00
copy_location = true ; // lat/lng used for heading lock
2015-08-18 23:45:48 -03:00
packet . param1 = cmd . p1 ; // Climb/Descend
// 0 = Neutral, cmd complete at +/- 5 of indicated alt.
// 1 = Climb, cmd complete at or above indicated alt.
// 2 = Descend, cmd complete at or below indicated alt.
2014-10-21 17:45:24 -03:00
break ;
2015-03-13 18:47:37 -03:00
case MAV_CMD_NAV_LOITER_TO_ALT : // MAV ID: 31
copy_location = true ;
2016-03-02 11:16:27 -04:00
packet . param2 = cmd . p1 ; // loiter radius(m)
2015-03-13 18:47:37 -03:00
if ( cmd . content . location . flags . loiter_ccw ) {
packet . param2 = - packet . param2 ;
}
2016-03-14 15:42:49 -03:00
packet . param4 = cmd . content . location . flags . loiter_xtrack ; // 0 to xtrack from center of waypoint, 1 to xtrack from tangent exit location
2015-03-13 18:47:37 -03:00
break ;
2014-03-22 00:45:26 -03:00
case MAV_CMD_NAV_SPLINE_WAYPOINT : // MAV ID: 82
copy_location = true ;
packet . param1 = cmd . p1 ; // delay at waypoint in seconds
break ;
2014-10-13 04:03:56 -03:00
case MAV_CMD_NAV_GUIDED_ENABLE : // MAV ID: 92
packet . param1 = cmd . p1 ; // on/off. >0.5 means "on", hand-over control to external controller
2014-06-02 06:02:04 -03:00
break ;
2016-04-18 04:12:40 -03:00
case MAV_CMD_NAV_DELAY : // MAV ID: 94
packet . param1 = cmd . content . nav_delay . seconds ; // delay in seconds
packet . param2 = cmd . content . nav_delay . hour_utc ; // absolute time's day of week (utc)
packet . param3 = cmd . content . nav_delay . min_utc ; // absolute time's hour (utc)
packet . param4 = cmd . content . nav_delay . sec_utc ; // absolute time's min (utc)
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_CONDITION_DELAY : // MAV ID: 112
packet . param1 = cmd . content . delay . seconds ; // delay in seconds
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_CONDITION_DISTANCE : // MAV ID: 114
packet . param1 = cmd . content . distance . meters ; // distance in meters from next waypoint
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_CONDITION_YAW : // MAV ID: 115
packet . param1 = cmd . content . yaw . angle_deg ; // target angle in degrees
packet . param2 = cmd . content . yaw . turn_rate_dps ; // 0 = use default turn rate otherwise specific turn rate in deg/sec
packet . param3 = cmd . content . yaw . direction ; // -1 = ccw, +1 = cw
packet . param4 = cmd . content . yaw . relative_angle ; // 0 = absolute angle provided, 1 = relative angle provided
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_SET_MODE : // MAV ID: 176
packet . param1 = cmd . p1 ; // set flight mode identifier
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_JUMP : // MAV ID: 177
2014-02-28 02:55:02 -04:00
packet . param1 = cmd . content . jump . target ; // jump-to command number
packet . param2 = cmd . content . jump . num_times ; // repeat count
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_CHANGE_SPEED : // MAV ID: 178
packet . param1 = cmd . content . speed . speed_type ; // 0 = airspeed, 1 = ground speed
packet . param2 = cmd . content . speed . target_ms ; // speed in m/s
packet . param3 = cmd . content . speed . throttle_pct ; // throttle as a percentage from 0 ~ 100%
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_SET_HOME : // MAV ID: 179
2014-02-28 02:55:02 -04:00
copy_location = true ;
2014-03-17 02:14:45 -03:00
packet . param1 = cmd . p1 ; // p1=0 means use current location, p=1 means use provided location
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_SET_RELAY : // MAV ID: 181
packet . param1 = cmd . content . relay . num ; // relay number
packet . param2 = cmd . content . relay . state ; // 0:off, 1:on
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_REPEAT_RELAY : // MAV ID: 182
2014-03-18 23:13:04 -03:00
packet . param1 = cmd . content . repeat_relay . num ; // relay number
packet . param2 = cmd . content . repeat_relay . repeat_count ; // count
packet . param3 = cmd . content . repeat_relay . cycle_time ; // time in seconds
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_SET_SERVO : // MAV ID: 183
packet . param1 = cmd . content . servo . channel ; // channel
packet . param2 = cmd . content . servo . pwm ; // PWM
2014-02-28 02:55:02 -04:00
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_REPEAT_SERVO : // MAV ID: 184
2014-03-18 23:13:04 -03:00
packet . param1 = cmd . content . repeat_servo . channel ; // channel
packet . param2 = cmd . content . repeat_servo . pwm ; // PWM
packet . param3 = cmd . content . repeat_servo . repeat_count ; // count
packet . param4 = cmd . content . repeat_servo . cycle_time ; // time in milliseconds converted to seconds
2014-02-28 02:55:02 -04:00
break ;
2014-10-17 14:34:04 -03:00
case MAV_CMD_DO_LAND_START : // MAV ID: 189
copy_location = true ;
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_SET_ROI : // MAV ID: 201
2014-02-28 02:55:02 -04:00
copy_location = true ;
2014-03-17 02:14:45 -03:00
packet . param1 = cmd . p1 ; // 0 = no roi, 1 = next waypoint, 2 = waypoint number, 3 = fixed location, 4 = given target (not supported)
2014-02-28 02:55:02 -04:00
break ;
2015-03-28 22:29:21 -03:00
case MAV_CMD_DO_DIGICAM_CONFIGURE : // MAV ID: 202
packet . param1 = cmd . content . digicam_configure . shooting_mode ;
packet . param2 = cmd . content . digicam_configure . shutter_speed ;
packet . param3 = cmd . content . digicam_configure . aperture ;
packet . param4 = cmd . content . digicam_configure . ISO ;
packet . x = cmd . content . digicam_configure . exposure_type ;
packet . y = cmd . content . digicam_configure . cmd_id ;
packet . z = cmd . content . digicam_configure . engine_cutoff_time ;
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_DIGICAM_CONTROL : // MAV ID: 203
2015-03-28 22:29:21 -03:00
packet . param1 = cmd . content . digicam_control . session ;
packet . param2 = cmd . content . digicam_control . zoom_pos ;
packet . param3 = cmd . content . digicam_control . zoom_step ;
packet . param4 = cmd . content . digicam_control . focus_lock ;
packet . x = cmd . content . digicam_control . shooting_cmd ;
packet . y = cmd . content . digicam_control . cmd_id ;
2014-02-28 02:55:02 -04:00
break ;
2015-03-21 08:56:50 -03:00
case MAV_CMD_DO_MOUNT_CONTROL : // MAV ID: 205
packet . param1 = cmd . content . mount_control . pitch ;
packet . param2 = cmd . content . mount_control . roll ;
packet . param3 = cmd . content . mount_control . yaw ;
break ;
2014-03-17 02:14:45 -03:00
case MAV_CMD_DO_SET_CAM_TRIGG_DIST : // MAV ID: 206
packet . param1 = cmd . content . cam_trigg_dist . meters ; // distance between camera shots in meters
2014-02-28 02:55:02 -04:00
break ;
2014-10-25 18:19:21 -03:00
case MAV_CMD_DO_FENCE_ENABLE : // MAV ID: 207
packet . param1 = cmd . p1 ; // action 0=disable, 1=enable
break ;
2014-04-03 05:49:04 -03:00
case MAV_CMD_DO_PARACHUTE : // MAV ID: 208
packet . param1 = cmd . p1 ; // action 0=disable, 1=enable, 2=release. See PARACHUTE_ACTION enum
break ;
2014-06-05 02:44:18 -03:00
case MAV_CMD_DO_INVERTED_FLIGHT : // MAV ID: 210
packet . param1 = cmd . p1 ; // normal=0 inverted=1
break ;
2014-09-17 04:21:12 -03:00
case MAV_CMD_DO_GRIPPER : // MAV ID: 211
packet . param1 = cmd . content . gripper . num ; // gripper number
packet . param2 = cmd . content . gripper . action ; // action 0=release, 1=grab. See GRIPPER_ACTION enum
break ;
2014-10-13 04:03:56 -03:00
case MAV_CMD_DO_GUIDED_LIMITS : // MAV ID: 222
packet . param1 = cmd . p1 ; // max time in seconds the external controller will be allowed to control the vehicle
packet . param2 = cmd . content . guided_limits . alt_min ; // min alt below which the command will be aborted. 0 for no lower alt limit
packet . param3 = cmd . content . guided_limits . alt_max ; // max alt above which the command will be aborted. 0 for no upper alt limit
packet . param4 = cmd . content . guided_limits . horiz_max ; // max horizontal distance the vehicle can move before the command will be aborted. 0 for no horizontal limit
2015-07-16 23:25:42 -03:00
break ;
2014-04-23 09:36:56 -03:00
2014-08-14 03:03:01 -03:00
case MAV_CMD_DO_AUTOTUNE_ENABLE :
packet . param1 = cmd . p1 ; // disable=0 enable=1
break ;
2016-07-14 04:35:49 -03:00
case MAV_CMD_DO_SET_REVERSE :
packet . param1 = cmd . p1 ; // 0 = forward, 1 = reverse
break ;
2014-08-14 03:03:01 -03:00
case MAV_CMD_NAV_ALTITUDE_WAIT : // MAV ID: 83
2014-04-23 09:36:56 -03:00
packet . param1 = cmd . content . altitude_wait . altitude ;
packet . param2 = cmd . content . altitude_wait . descent_rate ;
packet . param3 = cmd . content . altitude_wait . wiggle_time ;
2014-10-13 04:03:56 -03:00
break ;
2016-01-01 05:41:52 -04:00
case MAV_CMD_NAV_VTOL_TAKEOFF :
copy_location = true ;
break ;
case MAV_CMD_NAV_VTOL_LAND :
copy_location = true ;
break ;
2016-04-22 05:22:12 -03:00
case MAV_CMD_DO_VTOL_TRANSITION :
packet . param1 = cmd . content . do_vtol_transition . target_state ;
break ;
2016-07-23 06:02:48 -03:00
case MAV_CMD_DO_ENGINE_CONTROL :
packet . param1 = cmd . content . do_engine_control . start_control ? 1 : 0 ;
packet . param2 = cmd . content . do_engine_control . cold_start ? 1 : 0 ;
packet . param3 = cmd . content . do_engine_control . height_delay_cm * 0.01f ;
break ;
2016-11-17 01:19:05 -04:00
case MAV_CMD_NAV_PAYLOAD_PLACE :
copy_location = true ;
packet . param1 = cmd . p1 / 100.0f ; // copy max-descend parameter (m->cm)
break ;
2017-08-02 02:25:57 -03:00
case MAV_CMD_NAV_SET_YAW_SPEED :
packet . param1 = cmd . content . set_yaw_speed . angle_deg ; // target angle in degrees
packet . param2 = cmd . content . set_yaw_speed . speed ; // speed in meters/second
packet . param3 = cmd . content . set_yaw_speed . relative_angle ; // 0 = absolute angle, 1 = relative angle
break ;
2017-10-06 21:45:35 -03:00
case MAV_CMD_DO_WINCH :
packet . param1 = cmd . content . winch . num ; // winch number
packet . param2 = cmd . content . winch . action ; // action (0 = relax, 1 = length control, 2 = rate control). See WINCH_ACTION enum
packet . param3 = cmd . content . winch . release_length ; // cable distance to unwind in meters, negative numbers to wind in cable
packet . param4 = cmd . content . winch . release_rate ; // release rate in meters/second
break ;
2014-02-28 02:55:02 -04:00
default :
// unrecognised command
return false ;
}
// copy location from mavlink to command
if ( copy_location ) {
2016-02-28 02:47:00 -04:00
packet . x = cmd . content . location . lat ;
packet . y = cmd . content . location . lng ;
2014-03-03 01:36:37 -04:00
}
if ( copy_location | | copy_alt ) {
2014-03-04 08:15:43 -04:00
packet . z = cmd . content . location . alt / 100.0f ; // cmd alt in cm to m
2014-03-03 01:36:37 -04:00
if ( cmd . content . location . flags . relative_alt ) {
2014-02-28 02:55:02 -04:00
packet . frame = MAV_FRAME_GLOBAL_RELATIVE_ALT ;
} else {
packet . frame = MAV_FRAME_GLOBAL ;
}
2014-07-24 19:33:44 -03:00
# if AP_TERRAIN_AVAILABLE
if ( cmd . content . location . flags . terrain_alt ) {
// this is a above-terrain altitude
if ( ! cmd . content . location . flags . relative_alt ) {
// refuse to return non-relative terrain mission
// items. Internally we do have these, and they
// have home.alt added, but we should never be
// returning them to the GCS, as the GCS doesn't know
// our home.alt, so it would have no way to properly
// interpret it
return false ;
}
packet . z = cmd . content . location . alt * 0.01f ;
packet . frame = MAV_FRAME_GLOBAL_TERRAIN_ALT ;
}
# else
// don't ever return terrain mission items if no terrain support
if ( cmd . content . location . flags . terrain_alt ) {
return false ;
}
# endif
2014-02-28 02:55:02 -04:00
}
2014-03-17 02:14:45 -03:00
// if we got this far then it must have been successful
2014-02-28 02:55:02 -04:00
return true ;
}
2014-02-23 03:54:53 -04:00
///
/// private methods
///
2014-02-22 20:14:44 -04:00
2014-02-23 03:54:53 -04:00
/// complete - mission is marked complete and clean-up performed including calling the mission_complete_fn
void AP_Mission : : complete ( )
2014-02-22 20:14:44 -04:00
{
2014-02-23 03:54:53 -04:00
// flag mission as complete
_flags . state = MISSION_COMPLETE ;
// callback to main program's mission complete function
_mission_complete_fn ( ) ;
2014-02-22 20:14:44 -04:00
}
2014-02-24 01:50:24 -04:00
/// advance_current_nav_cmd - moves current nav command forward
/// do command will also be loaded
/// accounts for do-jump commands
// returns true if command is advanced, false if failed (i.e. mission completed)
bool AP_Mission : : advance_current_nav_cmd ( )
2014-02-22 20:14:44 -04:00
{
2014-02-24 01:50:24 -04:00
Mission_Command cmd ;
2014-02-28 08:49:37 -04:00
uint16_t cmd_index ;
2014-02-24 01:50:24 -04:00
// exit immediately if we're not running
if ( _flags . state ! = MISSION_RUNNING ) {
return false ;
}
// exit immediately if current nav command has not completed
if ( _flags . nav_cmd_loaded ) {
return false ;
}
// stop the current running do command
_do_cmd . index = AP_MISSION_CMD_INDEX_NONE ;
_flags . do_cmd_loaded = false ;
2014-02-28 09:37:02 -04:00
_flags . do_cmd_all_done = false ;
2014-02-24 01:50:24 -04:00
// get starting point for search
cmd_index = _nav_cmd . index ;
if ( cmd_index = = AP_MISSION_CMD_INDEX_NONE ) {
2014-03-07 04:01:05 -04:00
// start from beginning of the mission command list
2014-02-27 09:02:12 -04:00
cmd_index = AP_MISSION_FIRST_REAL_COMMAND ;
2014-02-24 01:50:24 -04:00
} else {
// start from one position past the current nav command
cmd_index + + ;
}
2015-06-01 04:16:04 -03:00
// avoid endless loops
uint8_t max_loops = 255 ;
2014-02-24 01:50:24 -04:00
// search until we find next nav command or reach end of command list
2015-01-22 22:48:45 -04:00
while ( ! _flags . nav_cmd_loaded ) {
2014-02-24 01:50:24 -04:00
// get next command
if ( ! get_next_cmd ( cmd_index , cmd , true ) ) {
return false ;
}
// check if navigation or "do" command
if ( is_nav_cmd ( cmd ) ) {
// save previous nav command index
2016-05-13 20:06:25 -03:00
_prev_nav_cmd_id = _nav_cmd . id ;
2014-02-24 01:50:24 -04:00
_prev_nav_cmd_index = _nav_cmd . index ;
2015-08-23 22:06:31 -03:00
// save separate previous nav command index if it contains lat,long,alt
2015-08-27 02:42:42 -03:00
if ( ! ( cmd . content . location . lat = = 0 & & cmd . content . location . lng = = 0 ) ) {
2015-08-23 22:06:31 -03:00
_prev_nav_cmd_wp_index = _nav_cmd . index ;
}
2014-02-24 01:50:24 -04:00
// set current navigation command and start it
_nav_cmd = cmd ;
_flags . nav_cmd_loaded = true ;
_cmd_start_fn ( _nav_cmd ) ;
} else {
// set current do command and start it (if not already set)
if ( ! _flags . do_cmd_loaded ) {
_do_cmd = cmd ;
_flags . do_cmd_loaded = true ;
_cmd_start_fn ( _do_cmd ) ;
2015-06-01 04:16:04 -03:00
} else {
// protect against endless loops of do-commands
if ( max_loops - - = = 0 ) {
return false ;
}
2014-02-24 01:50:24 -04:00
}
}
// move onto next command
cmd_index = cmd . index + 1 ;
}
2015-07-17 00:13:28 -03:00
// if we have not found a do command then set flag to show there are no do-commands to be run before nav command completes
if ( ! _flags . do_cmd_loaded ) {
_flags . do_cmd_all_done = true ;
}
2014-02-24 01:50:24 -04:00
// if we got this far we must have successfully advanced the nav command
return true ;
}
/// advance_current_do_cmd - moves current do command forward
/// accounts for do-jump commands
void AP_Mission : : advance_current_do_cmd ( )
{
Mission_Command cmd ;
2014-02-28 08:49:37 -04:00
uint16_t cmd_index ;
2014-02-24 01:50:24 -04:00
2014-02-28 09:37:02 -04:00
// exit immediately if we're not running or we've completed all possible "do" commands
if ( _flags . state ! = MISSION_RUNNING | | _flags . do_cmd_all_done ) {
2014-02-24 01:50:24 -04:00
return ;
}
// get starting point for search
cmd_index = _do_cmd . index ;
if ( cmd_index = = AP_MISSION_CMD_INDEX_NONE ) {
2014-02-27 09:02:12 -04:00
cmd_index = AP_MISSION_FIRST_REAL_COMMAND ;
2014-02-24 01:50:24 -04:00
} else {
// start from one position past the current do command
cmd_index + + ;
}
// check if we've reached end of mission
2014-03-23 22:52:27 -03:00
if ( cmd_index > = ( unsigned ) _cmd_total ) {
2014-02-28 09:37:02 -04:00
// set flag to stop unnecessarily searching for do commands
_flags . do_cmd_all_done = true ;
2014-02-24 01:50:24 -04:00
return ;
}
// find next do command
if ( get_next_do_cmd ( cmd_index , cmd ) ) {
// set current do command and start it
_do_cmd = cmd ;
2014-03-16 01:10:16 -03:00
_flags . do_cmd_loaded = true ;
2014-02-24 01:50:24 -04:00
_cmd_start_fn ( _do_cmd ) ;
} else {
2014-02-28 09:37:02 -04:00
// set flag to stop unnecessarily searching for do commands
_flags . do_cmd_all_done = true ;
2014-02-24 01:50:24 -04:00
}
2014-02-22 20:14:44 -04:00
}
2014-02-23 03:54:53 -04:00
/// get_next_cmd - gets next command found at or after start_index
/// returns true if found, false if not found (i.e. mission complete)
/// accounts for do_jump commands
/// increment_jump_num_times_if_found should be set to true if advancing the active navigation command
2014-02-28 08:49:37 -04:00
bool AP_Mission : : get_next_cmd ( uint16_t start_index , Mission_Command & cmd , bool increment_jump_num_times_if_found )
2014-02-22 20:14:44 -04:00
{
2014-02-28 08:49:37 -04:00
uint16_t cmd_index = start_index ;
2014-02-23 03:54:53 -04:00
Mission_Command temp_cmd ;
2014-02-28 08:49:37 -04:00
uint16_t jump_index = AP_MISSION_CMD_INDEX_NONE ;
2014-02-23 03:54:53 -04:00
// search until the end of the mission command list
2015-01-22 22:13:54 -04:00
uint8_t max_loops = 64 ;
2014-03-23 22:52:27 -03:00
while ( cmd_index < ( unsigned ) _cmd_total ) {
2014-02-23 03:54:53 -04:00
// load the next command
2014-03-10 23:23:44 -03:00
if ( ! read_cmd_from_storage ( cmd_index , temp_cmd ) ) {
// this should never happen because of check above but just in case
return false ;
}
2014-02-23 03:54:53 -04:00
// check for do-jump command
if ( temp_cmd . id = = MAV_CMD_DO_JUMP ) {
2014-02-28 08:23:38 -04:00
2015-01-22 22:13:54 -04:00
if ( max_loops - - = = 0 ) {
return false ;
}
2014-02-28 08:23:38 -04:00
// check for invalid target
2015-04-21 08:37:09 -03:00
if ( ( temp_cmd . content . jump . target > = ( unsigned ) _cmd_total ) | | ( temp_cmd . content . jump . target = = 0 ) ) {
2014-02-28 08:23:38 -04:00
// To-Do: log an error?
return false ;
}
2014-02-23 03:54:53 -04:00
// check for endless loops
if ( ! increment_jump_num_times_if_found & & jump_index = = cmd_index ) {
// we have somehow reached this jump command twice and there is no chance it will complete
// To-Do: log an error?
return false ;
}
2014-02-28 08:23:38 -04:00
// record this command so we can check for endless loops
if ( jump_index = = AP_MISSION_CMD_INDEX_NONE ) {
jump_index = cmd_index ;
}
// check if jump command is 'repeat forever'
if ( temp_cmd . content . jump . num_times = = AP_MISSION_JUMP_REPEAT_FOREVER ) {
2014-02-23 03:54:53 -04:00
// continue searching from jump target
cmd_index = temp_cmd . content . jump . target ;
} else {
2014-02-28 08:23:38 -04:00
// get number of times jump command has already been run
int16_t jump_times_run = get_jump_times_run ( temp_cmd ) ;
if ( jump_times_run < temp_cmd . content . jump . num_times ) {
// update the record of the number of times run
if ( increment_jump_num_times_if_found ) {
increment_jump_times_run ( temp_cmd ) ;
}
// continue searching from jump target
cmd_index = temp_cmd . content . jump . target ;
} else {
// jump has been run specified number of times so move search to next command in mission
cmd_index + + ;
}
2014-02-23 03:54:53 -04:00
}
} else {
// this is a non-jump command so return it
cmd = temp_cmd ;
2014-02-22 20:14:44 -04:00
return true ;
}
}
2014-02-23 03:54:53 -04:00
// if we got this far we did not find a navigation command
2014-02-22 20:14:44 -04:00
return false ;
}
2014-02-23 03:54:53 -04:00
/// get_next_do_cmd - gets next "do" or "conditional" command after start_index
/// returns true if found, false if not found
/// stops and returns false if it hits another navigation command before it finds the first do or conditional command
/// accounts for do_jump commands but never increments the jump's num_times_run (advance_current_nav_cmd is responsible for this)
2014-02-28 08:49:37 -04:00
bool AP_Mission : : get_next_do_cmd ( uint16_t start_index , Mission_Command & cmd )
2014-02-22 20:14:44 -04:00
{
2014-02-23 03:54:53 -04:00
Mission_Command temp_cmd ;
2014-02-22 20:14:44 -04:00
2014-02-23 03:54:53 -04:00
// check we have not passed the end of the mission list
2014-03-23 22:52:27 -03:00
if ( start_index > = ( unsigned ) _cmd_total ) {
2014-02-23 03:54:53 -04:00
return false ;
}
2014-02-22 20:14:44 -04:00
2014-02-23 03:54:53 -04:00
// get next command
if ( ! get_next_cmd ( start_index , temp_cmd , false ) ) {
// no more commands so return failure
return false ;
} else if ( is_nav_cmd ( temp_cmd ) ) {
// if it's a "navigation" command then return false because we do not progress past nav commands
return false ;
} else {
// this must be a "do" or "conditional" and is not a do-jump command so return it
cmd = temp_cmd ;
return true ;
2014-02-22 20:14:44 -04:00
}
}
2014-02-23 03:54:53 -04:00
///
/// jump handling methods
///
2014-02-22 20:14:44 -04:00
2014-02-23 03:54:53 -04:00
// init_jump_tracking - initialise jump_tracking variables
void AP_Mission : : init_jump_tracking ( )
{
for ( uint8_t i = 0 ; i < AP_MISSION_MAX_NUM_DO_JUMP_COMMANDS ; i + + ) {
_jump_tracking [ i ] . index = AP_MISSION_CMD_INDEX_NONE ;
_jump_tracking [ i ] . num_times_run = 0 ;
2014-02-22 20:14:44 -04:00
}
}
2014-02-23 03:54:53 -04:00
/// get_jump_times_run - returns number of times the jump command has been run
2014-02-28 08:23:38 -04:00
int16_t AP_Mission : : get_jump_times_run ( const Mission_Command & cmd )
2014-02-22 20:14:44 -04:00
{
2016-05-12 13:59:11 -03:00
// exit immediately if cmd is not a do-jump command or target is invalid
2015-04-21 08:37:09 -03:00
if ( ( cmd . id ! = MAV_CMD_DO_JUMP ) | | ( cmd . content . jump . target > = ( unsigned ) _cmd_total ) | | ( cmd . content . jump . target = = 0 ) ) {
2014-02-23 03:54:53 -04:00
// To-Do: log an error?
return AP_MISSION_JUMP_TIMES_MAX ;
}
2014-02-22 20:14:44 -04:00
2014-02-23 03:54:53 -04:00
// search through jump_tracking array for this cmd
for ( uint8_t i = 0 ; i < AP_MISSION_MAX_NUM_DO_JUMP_COMMANDS ; i + + ) {
if ( _jump_tracking [ i ] . index = = cmd . index ) {
return _jump_tracking [ i ] . num_times_run ;
} else if ( _jump_tracking [ i ] . index = = AP_MISSION_CMD_INDEX_NONE ) {
// we've searched through all known jump commands and haven't found it so allocate new space in _jump_tracking array
_jump_tracking [ i ] . index = cmd . index ;
_jump_tracking [ i ] . num_times_run = 0 ;
return 0 ;
2014-02-22 20:14:44 -04:00
}
}
2014-02-23 03:54:53 -04:00
// if we've gotten this far then the _jump_tracking array must be full
// To-Do: log an error?
return AP_MISSION_JUMP_TIMES_MAX ;
}
2014-02-22 20:14:44 -04:00
2014-02-23 03:54:53 -04:00
/// increment_jump_times_run - increments the recorded number of times the jump command has been run
void AP_Mission : : increment_jump_times_run ( Mission_Command & cmd )
2014-02-22 20:14:44 -04:00
{
2014-02-24 01:50:24 -04:00
// exit immediately if cmd is not a do-jump command
2014-02-23 03:54:53 -04:00
if ( cmd . id ! = MAV_CMD_DO_JUMP ) {
// To-Do: log an error?
return ;
2014-02-22 20:14:44 -04:00
}
2014-02-23 03:54:53 -04:00
// search through jump_tracking array for this cmd
for ( uint8_t i = 0 ; i < AP_MISSION_MAX_NUM_DO_JUMP_COMMANDS ; i + + ) {
if ( _jump_tracking [ i ] . index = = cmd . index ) {
_jump_tracking [ i ] . num_times_run + + ;
return ;
} else if ( _jump_tracking [ i ] . index = = AP_MISSION_CMD_INDEX_NONE ) {
// we've searched through all known jump commands and haven't found it so allocate new space in _jump_tracking array
_jump_tracking [ i ] . index = cmd . index ;
_jump_tracking [ i ] . num_times_run = 1 ;
return ;
}
2014-02-22 20:14:44 -04:00
}
2014-02-23 03:54:53 -04:00
// if we've gotten this far then the _jump_tracking array must be full
// To-Do: log an error
return ;
2014-02-22 20:14:44 -04:00
}
2014-03-11 00:52:23 -03:00
// check_eeprom_version - checks version of missions stored in eeprom matches this library
// command list will be cleared if they do not match
void AP_Mission : : check_eeprom_version ( )
{
2014-08-13 01:43:37 -03:00
uint32_t eeprom_version = _storage . read_uint32 ( 0 ) ;
2014-03-11 00:52:23 -03:00
// if eeprom version does not match, clear the command list and update the eeprom version
if ( eeprom_version ! = AP_MISSION_EEPROM_VERSION ) {
if ( clear ( ) ) {
2014-08-13 01:43:37 -03:00
_storage . write_uint32 ( 0 , AP_MISSION_EEPROM_VERSION ) ;
2014-03-11 00:52:23 -03:00
}
}
}
2014-08-13 01:43:37 -03:00
/*
return total number of commands that can fit in storage space
*/
uint16_t AP_Mission : : num_commands_max ( void ) const
{
// -4 to remove space for eeprom version number
return ( _storage . size ( ) - 4 ) / AP_MISSION_EEPROM_COMMAND_SIZE ;
}
2014-10-17 14:34:04 -03:00
// find the nearest landing sequence starting point (DO_LAND_START) and
2014-10-24 00:06:35 -03:00
// return its index. Returns 0 if no appropriate DO_LAND_START point can
// be found.
uint16_t AP_Mission : : get_landing_sequence_start ( )
2014-10-17 22:40:18 -03:00
{
2014-10-17 14:34:04 -03:00
struct Location current_loc ;
2014-10-17 22:14:55 -03:00
if ( ! _ahrs . get_position ( current_loc ) ) {
2014-10-24 00:06:35 -03:00
return 0 ;
2014-10-17 14:34:04 -03:00
}
2014-10-24 00:06:35 -03:00
uint16_t landing_start_index = 0 ;
2014-10-17 22:40:18 -03:00
float min_distance = - 1 ;
2014-10-17 14:34:04 -03:00
// Go through mission looking for nearest landing start command
2014-10-17 22:40:18 -03:00
for ( uint16_t i = 0 ; i < num_commands ( ) ; i + + ) {
Mission_Command tmp ;
if ( ! read_cmd_from_storage ( i , tmp ) ) {
continue ;
}
if ( tmp . id = = MAV_CMD_DO_LAND_START ) {
float tmp_distance = get_distance ( tmp . content . location , current_loc ) ;
if ( min_distance < 0 | | tmp_distance < min_distance ) {
2014-10-17 14:34:04 -03:00
min_distance = tmp_distance ;
2014-10-17 22:40:18 -03:00
landing_start_index = i ;
2014-10-17 14:34:04 -03:00
}
}
}
2014-10-24 00:06:35 -03:00
return landing_start_index ;
2014-10-17 14:34:04 -03:00
}
2016-11-25 20:45:11 -04:00
/*
find the nearest landing sequence starting point ( DO_LAND_START ) and
switch to that mission item . Returns false if no DO_LAND_START
available .
*/
bool AP_Mission : : jump_to_landing_sequence ( void )
{
uint16_t land_idx = get_landing_sequence_start ( ) ;
if ( land_idx ! = 0 & & set_current_cmd ( land_idx ) ) {
//if the mission has ended it has to be restarted
if ( state ( ) = = AP_Mission : : MISSION_STOPPED ) {
resume ( ) ;
}
2017-07-09 01:13:22 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Landing sequence start " ) ;
2016-11-25 20:45:11 -04:00
return true ;
}
2017-07-09 01:13:22 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_WARNING , " Unable to start landing sequence " ) ;
2016-11-25 20:45:11 -04:00
return false ;
}
2017-11-26 18:24:05 -04:00
const char * AP_Mission : : Mission_Command : : type ( ) const {
switch ( id ) {
case MAV_CMD_NAV_WAYPOINT :
return " WP " ;
case MAV_CMD_NAV_RETURN_TO_LAUNCH :
return " RTL " ;
case MAV_CMD_NAV_LOITER_UNLIM :
return " LoitUnlim " ;
case MAV_CMD_NAV_LOITER_TIME :
return " LoitTime " ;
case MAV_CMD_NAV_SET_YAW_SPEED :
return " SetYawSpd " ;
case MAV_CMD_CONDITION_DELAY :
return " CondDelay " ;
case MAV_CMD_CONDITION_DISTANCE :
return " CondDist " ;
case MAV_CMD_DO_CHANGE_SPEED :
return " ChangeSpeed " ;
case MAV_CMD_DO_SET_HOME :
return " SetHome " ;
case MAV_CMD_DO_SET_SERVO :
return " SetServo " ;
case MAV_CMD_DO_SET_RELAY :
return " SetRelay " ;
case MAV_CMD_DO_REPEAT_SERVO :
return " RepeatServo " ;
case MAV_CMD_DO_REPEAT_RELAY :
return " RepeatRelay " ;
case MAV_CMD_DO_CONTROL_VIDEO :
return " CtrlVideo " ;
case MAV_CMD_DO_DIGICAM_CONFIGURE :
return " DigiCamCfg " ;
case MAV_CMD_DO_DIGICAM_CONTROL :
return " DigiCamCtrl " ;
case MAV_CMD_DO_SET_CAM_TRIGG_DIST :
return " SetCamTrigDst " ;
case MAV_CMD_DO_SET_ROI :
return " SetROI " ;
case MAV_CMD_DO_SET_REVERSE :
return " SetReverse " ;
default :
return " ? " ;
}
}