2012-08-04 15:12:36 -07:00
/****************************************************************************
*
2018-01-01 13:11:52 +01:00
* Copyright ( c ) 2013 - 2018 PX4 Development Team . All rights reserved .
2012-08-04 15:12:36 -07:00
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in
* the documentation and / or other materials provided with the
* distribution .
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS
* OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
2013-07-20 13:47:51 +02:00
* @ file commander . cpp
2016-02-13 11:40:41 +01:00
*
* Main state machine / business logic
2012-10-23 13:15:36 +02:00
*
2018-01-01 13:11:52 +01:00
* @ TODO This application is currently in a rewrite process . Main changes :
* - Calibration routines are moved into the event system
* - Commander is rewritten as class
* - State machines will be model driven
2012-08-04 15:12:36 -07:00
*/
2017-12-20 15:39:20 -05:00
# include "Commander.hpp"
2016-06-14 13:42:49 -04:00
/* commander module headers */
# include "accelerometer_calibration.h"
# include "airspeed_calibration.h"
2018-03-27 16:51:28 -04:00
# include "arm_auth.h"
2016-06-14 13:42:49 -04:00
# include "baro_calibration.h"
# include "calibration_routines.h"
# include "commander_helper.h"
# include "esc_calibration.h"
# include "gyro_calibration.h"
# include "mag_calibration.h"
# include "PreflightCheck.h"
# include "px4_custom_mode.h"
# include "rc_calibration.h"
# include "state_machine_helper.h"
/* PX4 headers */
# include <dataman/dataman.h>
# include <drivers/drv_hrt.h>
# include <drivers/drv_tone_alarm.h>
2018-03-19 00:33:20 -04:00
# include <lib/ecl/geo/geo.h>
2018-01-28 11:22:51 -05:00
# include <mathlib/mathlib.h>
2016-06-14 13:42:49 -04:00
# include <navigator/navigation.h>
2015-03-11 12:16:44 -07:00
# include <px4_config.h>
2018-03-27 16:51:28 -04:00
# include <px4_defines.h>
2015-04-24 01:24:31 -07:00
# include <px4_posix.h>
2017-04-18 14:06:30 +02:00
# include <px4_shutdown.h>
2015-09-11 21:48:36 +02:00
# include <px4_tasks.h>
2016-06-14 13:42:49 -04:00
# include <px4_time.h>
2014-05-25 20:34:32 +02:00
# include <systemlib/circuit_breaker.h>
2016-06-14 13:42:49 -04:00
# include <systemlib/err.h>
2018-03-27 16:51:28 -04:00
# include <systemlib/hysteresis/hysteresis.h>
2016-03-15 18:25:02 +00:00
# include <systemlib/mavlink_log.h>
2016-06-14 13:42:49 -04:00
# include <systemlib/param/param.h>
# include <systemlib/rc_check.h>
# include <systemlib/state_table.h>
2016-04-20 17:51:47 +02:00
2018-03-27 16:51:28 -04:00
# include <cmath>
# include <cfloat>
# include <cstring>
2017-02-04 18:29:10 +01:00
2016-06-14 13:42:49 -04:00
# include <uORB/topics/actuator_armed.h>
# include <uORB/topics/actuator_controls.h>
2013-01-01 13:30:24 +01:00
# include <uORB/topics/battery_status.h>
2016-06-14 13:42:49 -04:00
# include <uORB/topics/cpuload.h>
2018-03-27 16:51:28 -04:00
# include <uORB/topics/estimator_status.h>
2016-06-14 13:42:49 -04:00
# include <uORB/topics/geofence_result.h>
# include <uORB/topics/home_position.h>
2012-09-21 12:55:41 +02:00
# include <uORB/topics/manual_control_setpoint.h>
2016-06-14 13:42:49 -04:00
# include <uORB/topics/mavlink_log.h>
# include <uORB/topics/mission.h>
# include <uORB/topics/mission_result.h>
2015-02-13 23:19:43 +01:00
# include <uORB/topics/offboard_control_mode.h>
2016-05-19 23:46:06 +02:00
# include <uORB/topics/parameter_update.h>
2018-03-27 16:51:28 -04:00
# include <uORB/topics/power_button_state.h>
2013-07-15 22:15:15 +02:00
# include <uORB/topics/safety.h>
2016-06-14 13:42:49 -04:00
# include <uORB/topics/subsystem_info.h>
2014-05-25 08:22:54 +02:00
# include <uORB/topics/system_power.h>
2014-06-16 17:34:21 +02:00
# include <uORB/topics/telemetry_status.h>
2018-03-29 23:14:34 -04:00
# include <uORB/topics/vehicle_command.h>
2015-12-12 13:01:49 +01:00
# include <uORB/topics/vehicle_command_ack.h>
2016-06-14 13:42:49 -04:00
# include <uORB/topics/vehicle_global_position.h>
# include <uORB/topics/vehicle_land_detected.h>
# include <uORB/topics/vehicle_local_position.h>
2017-01-27 19:13:18 +01:00
# include <uORB/topics/vehicle_status_flags.h>
2016-06-14 13:42:49 -04:00
# include <uORB/topics/vtol_vehicle_status.h>
2018-03-27 16:51:28 -04:00
# include <uORB/uORB.h>
2013-03-11 10:39:57 -07:00
2016-07-01 18:04:09 +02:00
typedef enum VEHICLE_MODE_FLAG
{
VEHICLE_MODE_FLAG_CUSTOM_MODE_ENABLED = 1 , /* 0b00000001 Reserved for future use. | */
VEHICLE_MODE_FLAG_TEST_ENABLED = 2 , /* 0b00000010 system has a test mode enabled. This flag is intended for temporary system tests and should not be used for stable implementations. | */
VEHICLE_MODE_FLAG_AUTO_ENABLED = 4 , /* 0b00000100 autonomous mode enabled, system finds its own goal positions. Guided flag can be set or not, depends on the actual implementation. | */
VEHICLE_MODE_FLAG_GUIDED_ENABLED = 8 , /* 0b00001000 guided mode enabled, system flies MISSIONs / mission items. | */
VEHICLE_MODE_FLAG_STABILIZE_ENABLED = 16 , /* 0b00010000 system stabilizes electronically its attitude (and optionally position). It needs however further control inputs to move around. | */
VEHICLE_MODE_FLAG_HIL_ENABLED = 32 , /* 0b00100000 hardware in the loop simulation. All motors / actuators are blocked, but internal software is full operational. | */
VEHICLE_MODE_FLAG_MANUAL_INPUT_ENABLED = 64 , /* 0b01000000 remote control input is enabled. | */
VEHICLE_MODE_FLAG_SAFETY_ARMED = 128 , /* 0b10000000 MAV safety set to armed. Motors are enabled / running / can start. Ready to fly. | */
VEHICLE_MODE_FLAG_ENUM_END = 129 , /* | */
} VEHICLE_MODE_FLAG ;
2016-05-20 07:57:20 -06:00
/* Decouple update interval and hysteresis counters, all depends on intervals */
2016-05-09 23:01:06 +02:00
# define COMMANDER_MONITORING_INTERVAL 10000
2012-08-04 15:12:36 -07:00
# define COMMANDER_MONITORING_LOOPSPERMSEC (1 / (COMMANDER_MONITORING_INTERVAL / 1000.0f))
2014-04-03 20:23:34 +04:00
# define STICK_ON_OFF_LIMIT 0.9f
2012-08-04 15:12:36 -07:00
2014-05-16 12:12:43 +02:00
# define OFFBOARD_TIMEOUT 500000
2014-05-07 08:42:57 +02:00
# define DIFFPRESS_TIMEOUT 2000000
2013-03-11 10:39:57 -07:00
2018-03-29 23:14:34 -04:00
static constexpr uint64_t HOTPLUG_SENS_TIMEOUT = ( 8 * 1000 * 1000 ) ; /**< wait for hotplug sensors to come online for upto 8 seconds */
2015-11-10 19:33:14 +05:30
2013-07-31 20:58:27 +04:00
# define PRINT_INTERVAL 5000000
2016-03-06 12:34:31 +01:00
# define PRINT_MODE_REJECT_INTERVAL 500000
2015-06-08 16:48:42 +02:00
2015-11-29 18:49:58 +01:00
# define INAIR_RESTART_HOLDOFF_INTERVAL 500000
2013-07-31 20:58:27 +04:00
2016-03-15 18:25:02 +00:00
/* Mavlink log uORB handle */
2017-01-28 20:21:58 -05:00
static orb_advert_t mavlink_log_pub = nullptr ;
2017-07-24 13:05:52 +02:00
static orb_advert_t power_button_state_pub = nullptr ;
2013-02-16 13:40:09 -08:00
/* flags */
2015-03-23 10:52:32 -07:00
static volatile bool thread_should_exit = false ; /**< daemon exit flag */
2013-09-08 20:05:15 +02:00
static volatile bool thread_running = false ; /**< daemon status flag */
2017-12-20 15:39:20 -05:00
2015-06-08 17:18:25 +02:00
static hrt_abstime commander_boot_timestamp = 0 ;
2013-02-16 13:40:09 -08:00
2013-07-31 20:58:27 +04:00
static unsigned int leds_counter ;
/* To remember when last notification was sent */
static uint64_t last_print_mode_reject_time = 0 ;
2016-07-17 17:00:59 +01:00
static systemlib : : Hysteresis auto_disarm_hysteresis ( false ) ;
2013-07-31 20:58:27 +04:00
2017-02-04 21:05:28 +01:00
static float min_stick_change = 0.25f ;
2016-11-13 09:32:17 +11:00
2016-04-23 14:29:25 +02:00
static struct vehicle_status_s status = { } ;
static struct battery_status_s battery = { } ;
static struct actuator_armed_s armed = { } ;
static struct safety_s safety = { } ;
static struct vehicle_control_mode_s control_mode = { } ;
static struct offboard_control_mode_s offboard_control_mode = { } ;
static struct home_position_s _home = { } ;
2016-03-13 15:39:35 +01:00
static int32_t _flight_mode_slots [ manual_control_setpoint_s : : MODE_SLOT_MAX ] ;
2016-04-23 14:29:25 +02:00
static struct commander_state_s internal_state = { } ;
2014-01-16 10:58:05 +01:00
2016-04-22 21:52:47 +02:00
static uint8_t main_state_before_rtl = commander_state_s : : MAIN_STATE_MAX ;
2017-12-19 11:02:34 -05:00
2017-04-17 00:18:39 -04:00
static manual_control_setpoint_s sp_man = { } ; ///< the current manual control setpoint
2016-05-09 23:01:06 +02:00
static manual_control_setpoint_s _last_sp_man = { } ; ///< the manual control setpoint valid at the last mode switch
2016-11-28 11:29:58 +01:00
static uint8_t _last_sp_man_arm_switch = 0 ;
2015-06-13 18:37:19 +02:00
2016-03-06 14:56:25 +01:00
static struct vtol_vehicle_status_s vtol_status = { } ;
2016-02-26 18:14:03 -08:00
static struct cpuload_s cpuload = { } ;
2015-08-07 16:43:16 +02:00
2016-09-15 08:34:22 +02:00
static bool warning_action_on = false ;
2016-09-09 14:17:44 +02:00
static bool last_overload = false ;
2016-02-25 08:11:57 +00:00
2018-01-27 16:23:40 -05:00
static struct vehicle_status_flags_s status_flags = { } ;
2016-02-25 17:00:39 +00:00
2016-02-26 11:01:12 +00:00
static uint64_t rc_signal_lost_timestamp ; // Time at which the RC reception was lost
2017-05-08 18:30:47 -07:00
static uint8_t arm_requirements = ARM_REQ_NONE ;
2017-04-17 00:18:39 -04:00
2017-02-16 14:32:07 +01:00
static bool _last_condition_global_position_valid = false ;
2016-06-07 16:00:23 +02:00
2017-03-08 11:03:27 +11:00
static struct vehicle_land_detected_s land_detector = { } ;
2016-02-26 11:01:12 +00:00
2013-07-16 09:24:21 +02:00
/**
2013-07-16 09:35:31 +02:00
* The daemon app only briefly exists to start
* the background job . The stack size assigned in the
* Makefile does only apply to this management task .
*
* The actual stack size should be set in the call
* to task_create ( ) .
2013-07-20 13:47:51 +02:00
*
* @ ingroup apps
2013-07-16 09:24:21 +02:00
*/
2013-07-20 13:47:51 +02:00
extern " C " __EXPORT int commander_main ( int argc , char * argv [ ] ) ;
2012-08-04 15:12:36 -07:00
2012-08-20 23:52:13 +02:00
/**
2013-07-16 09:35:31 +02:00
* Print the correct usage .
2012-08-20 23:52:13 +02:00
*/
2013-07-16 09:35:31 +02:00
void usage ( const char * reason ) ;
2012-08-20 23:52:13 +02:00
2016-02-24 18:08:56 +00:00
void control_status_leds ( vehicle_status_s * status_local , const actuator_armed_s * actuator_armed , bool changed ,
2016-05-06 11:11:29 +02:00
battery_status_s * battery_local , const cpuload_s * cpuload_local ) ;
2013-08-27 23:08:00 +02:00
2015-04-27 13:29:36 +02:00
void get_circuit_breaker_params ( ) ;
2014-01-27 20:49:17 +01:00
void set_control_mode ( ) ;
2015-08-19 17:54:57 +02:00
bool stabilization_required ( ) ;
2018-03-27 15:16:19 -04:00
void print_reject_mode ( const char * msg ) ;
2013-08-27 23:08:00 +02:00
2013-08-16 09:23:39 +02:00
void print_reject_arm ( const char * msg ) ;
2013-07-31 20:58:27 +04:00
2013-08-17 15:47:42 +02:00
void print_status ( ) ;
2016-03-15 18:25:02 +00:00
transition_result_t arm_disarm ( bool arm , orb_advert_t * mavlink_log_pub , const char * armedBy ) ;
2014-03-16 21:38:23 -07:00
2013-07-16 09:35:31 +02:00
/**
* Loop that runs at a lower rate and priority for calibration and parameter tasks .
*/
void * commander_low_prio_loop ( void * arg ) ;
2018-03-27 15:16:19 -04:00
static void answer_command ( const vehicle_command_s & cmd , unsigned result , orb_advert_t & command_ack_pub ) ;
2017-04-18 14:09:48 +02:00
static int power_button_state_notification_cb ( board_power_button_state_notification_e request )
{
2017-07-24 13:05:52 +02:00
// Note: this can be called from IRQ handlers, so we publish a message that will be handled
// on the main thread of commander.
power_button_state_s button_state ;
button_state . timestamp = hrt_absolute_time ( ) ;
int ret = PWR_BUTTON_RESPONSE_SHUT_DOWN_PENDING ;
switch ( request ) {
case PWR_BUTTON_IDEL :
button_state . event = power_button_state_s : : PWR_BUTTON_STATE_IDEL ;
break ;
case PWR_BUTTON_DOWN :
button_state . event = power_button_state_s : : PWR_BUTTON_STATE_DOWN ;
break ;
case PWR_BUTTON_UP :
button_state . event = power_button_state_s : : PWR_BUTTON_STATE_UP ;
break ;
case PWR_BUTTON_REQUEST_SHUT_DOWN :
button_state . event = power_button_state_s : : PWR_BUTTON_STATE_REQUEST_SHUTDOWN ;
break ;
default :
PX4_ERR ( " unhandled power button state: %i " , ( int ) request ) ;
return ret ;
2017-04-18 14:09:48 +02:00
}
2017-07-24 13:05:52 +02:00
2017-07-24 14:33:38 +02:00
if ( power_button_state_pub ! = nullptr ) {
orb_publish ( ORB_ID ( power_button_state ) , power_button_state_pub , & button_state ) ;
} else {
PX4_ERR ( " power_button_state_pub not properly initialized " ) ;
}
2017-07-24 13:05:52 +02:00
return ret ;
2017-04-18 14:09:48 +02:00
}
2013-07-16 09:35:31 +02:00
int commander_main ( int argc , char * argv [ ] )
{
2015-03-17 13:37:01 -04:00
if ( argc < 2 ) {
2013-07-16 09:35:31 +02:00
usage ( " missing command " ) ;
2015-04-15 19:38:59 -07:00
return 1 ;
2014-05-11 13:36:51 +02:00
}
2013-07-16 09:35:31 +02:00
if ( ! strcmp ( argv [ 1 ] , " start " ) ) {
if ( thread_running ) {
2015-08-11 09:24:13 +02:00
warnx ( " already running " ) ;
2013-07-16 09:35:31 +02:00
/* this is not an error */
2015-04-15 19:38:59 -07:00
return 0 ;
2013-07-16 09:35:31 +02:00
}
thread_should_exit = false ;
2017-12-20 15:39:20 -05:00
Commander : : main ( argc , argv ) ;
2013-09-08 20:05:15 +02:00
2015-08-11 09:24:13 +02:00
unsigned constexpr max_wait_us = 1000000 ;
unsigned constexpr max_wait_steps = 2000 ;
unsigned i ;
for ( i = 0 ; i < max_wait_steps ; i + + ) {
usleep ( max_wait_us / max_wait_steps ) ;
if ( thread_running ) {
break ;
}
2013-09-08 20:05:15 +02:00
}
2015-08-11 11:03:01 +02:00
return ! ( i < max_wait_steps ) ;
2013-07-16 09:35:31 +02:00
}
2012-08-04 15:12:36 -07:00
2013-07-16 09:35:31 +02:00
if ( ! strcmp ( argv [ 1 ] , " stop " ) ) {
2013-09-08 20:05:15 +02:00
2014-05-11 13:36:51 +02:00
if ( ! thread_running ) {
2015-04-15 19:38:59 -07:00
warnx ( " commander already stopped " ) ;
return 0 ;
2014-05-11 13:36:51 +02:00
}
2013-09-08 20:05:15 +02:00
2013-07-16 09:35:31 +02:00
thread_should_exit = true ;
2013-09-08 20:05:15 +02:00
2017-12-20 15:39:20 -05:00
Commander : : main ( argc , argv ) ;
2013-09-08 20:05:15 +02:00
warnx ( " terminated. " ) ;
2015-04-15 19:38:59 -07:00
return 0 ;
2013-07-16 09:35:31 +02:00
}
2013-03-25 14:53:54 -07:00
2014-07-11 14:51:13 +02:00
/* commands needing the app to run below */
if ( ! thread_running ) {
warnx ( " \t commander not started " ) ;
2015-04-15 19:38:59 -07:00
return 1 ;
2014-07-11 14:51:13 +02:00
}
2013-07-16 09:35:31 +02:00
2014-07-11 14:51:13 +02:00
if ( ! strcmp ( argv [ 1 ] , " status " ) ) {
print_status ( ) ;
2015-04-15 19:38:59 -07:00
return 0 ;
2014-07-11 14:51:13 +02:00
}
2013-07-16 09:35:31 +02:00
2015-02-09 13:56:53 +01:00
if ( ! strcmp ( argv [ 1 ] , " calibrate " ) ) {
if ( argc > 2 ) {
int calib_ret = OK ;
if ( ! strcmp ( argv [ 2 ] , " mag " ) ) {
2016-03-15 18:25:02 +00:00
calib_ret = do_mag_calibration ( & mavlink_log_pub ) ;
2015-02-09 13:56:53 +01:00
} else if ( ! strcmp ( argv [ 2 ] , " accel " ) ) {
2016-03-15 18:25:02 +00:00
calib_ret = do_accel_calibration ( & mavlink_log_pub ) ;
2015-02-09 13:56:53 +01:00
} else if ( ! strcmp ( argv [ 2 ] , " gyro " ) ) {
2016-03-15 18:25:02 +00:00
calib_ret = do_gyro_calibration ( & mavlink_log_pub ) ;
2015-05-19 14:20:00 +02:00
} else if ( ! strcmp ( argv [ 2 ] , " level " ) ) {
2016-03-15 18:25:02 +00:00
calib_ret = do_level_calibration ( & mavlink_log_pub ) ;
2015-05-22 09:28:52 -07:00
} else if ( ! strcmp ( argv [ 2 ] , " esc " ) ) {
2016-03-15 18:25:02 +00:00
calib_ret = do_esc_calibration ( & mavlink_log_pub , & armed ) ;
2015-11-17 12:59:45 +01:00
} else if ( ! strcmp ( argv [ 2 ] , " airspeed " ) ) {
2016-03-15 18:25:02 +00:00
calib_ret = do_airspeed_calibration ( & mavlink_log_pub ) ;
2015-02-09 13:56:53 +01:00
} else {
warnx ( " argument %s unsupported. " , argv [ 2 ] ) ;
}
if ( calib_ret ) {
2015-04-15 19:38:59 -07:00
warnx ( " calibration failed, exiting. " ) ;
2015-08-26 16:17:07 +02:00
return 1 ;
2015-02-09 13:56:53 +01:00
} else {
2015-04-15 19:38:59 -07:00
return 0 ;
2015-02-09 13:56:53 +01:00
}
} else {
warnx ( " missing argument " ) ;
}
}
2014-07-11 14:51:13 +02:00
if ( ! strcmp ( argv [ 1 ] , " check " ) ) {
2018-03-29 23:14:34 -04:00
bool preflight_check_res = Commander : : preflight_check ( true ) ;
PX4_INFO ( " Preflight check: %s " , preflight_check_res ? " OK " : " FAILED " ) ;
2018-03-29 23:14:34 -04:00
bool prearm_check_res = prearm_check ( & mavlink_log_pub , status_flags , battery , safety , arm_requirements , hrt_elapsed_time ( & commander_boot_timestamp ) ) ;
2018-03-29 23:14:34 -04:00
PX4_INFO ( " Prearm check: %s " , prearm_check_res ? " OK " : " FAILED " ) ;
2017-04-17 00:18:39 -04:00
2015-04-15 19:38:59 -07:00
return 0 ;
2013-07-16 09:35:31 +02:00
}
2014-01-16 10:58:05 +01:00
if ( ! strcmp ( argv [ 1 ] , " arm " ) ) {
2016-03-15 18:25:02 +00:00
if ( TRANSITION_CHANGED ! = arm_disarm ( true , & mavlink_log_pub , " command line " ) ) {
2015-11-14 15:02:56 +01:00
warnx ( " arming failed " ) ;
}
2015-04-15 19:38:59 -07:00
return 0 ;
2014-01-16 10:58:05 +01:00
}
2014-07-11 14:55:46 +02:00
if ( ! strcmp ( argv [ 1 ] , " disarm " ) ) {
2016-03-15 18:25:02 +00:00
if ( TRANSITION_DENIED = = arm_disarm ( false , & mavlink_log_pub , " command line " ) ) {
2015-11-14 15:02:56 +01:00
warnx ( " rejected disarm " ) ;
}
2015-08-26 16:17:07 +02:00
return 0 ;
2014-01-16 10:58:05 +01:00
}
2015-11-20 11:15:17 +01:00
if ( ! strcmp ( argv [ 1 ] , " takeoff " ) ) {
2015-12-20 20:29:22 +01:00
/* see if we got a home position */
2017-02-06 16:48:37 +01:00
if ( status_flags . condition_local_position_valid ) {
2015-12-20 20:29:22 +01:00
2016-03-15 18:25:02 +00:00
if ( TRANSITION_DENIED ! = arm_disarm ( true , & mavlink_log_pub , " command line " ) ) {
2015-12-20 20:29:22 +01:00
2017-07-27 17:08:22 -07:00
struct vehicle_command_s cmd = {
. timestamp = hrt_absolute_time ( ) ,
. param5 = NAN ,
. param6 = NAN ,
/* minimum pitch */
. param1 = NAN ,
. param2 = NAN ,
. param3 = NAN ,
. param4 = NAN ,
. param7 = NAN ,
. command = vehicle_command_s : : VEHICLE_CMD_NAV_TAKEOFF ,
2017-09-26 12:25:02 -04:00
. target_system = status . system_id ,
. target_component = status . component_id
2017-07-27 17:08:22 -07:00
} ;
2017-07-04 08:56:33 +02:00
2016-09-07 14:24:09 +02:00
orb_advert_t h = orb_advertise_queue ( ORB_ID ( vehicle_command ) , & cmd , vehicle_command_s : : ORB_QUEUE_LENGTH ) ;
2016-05-13 22:05:46 +02:00
( void ) orb_unadvertise ( h ) ;
2015-11-20 11:15:17 +01:00
} else {
2015-12-20 20:29:22 +01:00
warnx ( " arming failed " ) ;
2015-11-20 11:15:17 +01:00
}
} else {
2015-12-20 20:29:22 +01:00
warnx ( " rejecting takeoff, no position lock yet. Please retry.. " ) ;
2015-11-20 11:15:17 +01:00
}
2015-12-20 20:29:22 +01:00
2015-11-20 11:15:17 +01:00
return 0 ;
}
2015-12-28 16:00:32 +01:00
if ( ! strcmp ( argv [ 1 ] , " land " ) ) {
2017-07-27 17:08:22 -07:00
struct vehicle_command_s cmd = {
. timestamp = 0 ,
. param5 = NAN ,
. param6 = NAN ,
/* minimum pitch */
. param1 = NAN ,
. param2 = NAN ,
. param3 = NAN ,
. param4 = NAN ,
. param7 = NAN ,
. command = vehicle_command_s : : VEHICLE_CMD_NAV_LAND ,
2017-09-26 12:25:02 -04:00
. target_system = status . system_id ,
. target_component = status . component_id
2017-07-27 17:08:22 -07:00
} ;
2016-05-13 22:05:46 +02:00
2016-09-07 14:24:09 +02:00
orb_advert_t h = orb_advertise_queue ( ORB_ID ( vehicle_command ) , & cmd , vehicle_command_s : : ORB_QUEUE_LENGTH ) ;
2016-05-13 22:05:46 +02:00
( void ) orb_unadvertise ( h ) ;
2015-12-28 16:00:32 +01:00
return 0 ;
}
2016-06-15 20:42:56 +02:00
if ( ! strcmp ( argv [ 1 ] , " transition " ) ) {
2017-07-27 17:08:22 -07:00
struct vehicle_command_s cmd = {
. timestamp = 0 ,
. param5 = NAN ,
. param6 = NAN ,
/* transition to the other mode */
. param1 = ( float ) ( ( status . is_rotary_wing ) ? vtol_vehicle_status_s : : VEHICLE_VTOL_STATE_FW : vtol_vehicle_status_s : : VEHICLE_VTOL_STATE_MC ) ,
. param2 = NAN ,
. param3 = NAN ,
. param4 = NAN ,
. param7 = NAN ,
. command = vehicle_command_s : : VEHICLE_CMD_DO_VTOL_TRANSITION ,
2017-09-26 12:25:02 -04:00
. target_system = status . system_id ,
. target_component = status . component_id
2017-07-27 17:08:22 -07:00
} ;
2016-06-15 20:42:56 +02:00
2016-09-07 14:24:09 +02:00
orb_advert_t h = orb_advertise_queue ( ORB_ID ( vehicle_command ) , & cmd , vehicle_command_s : : ORB_QUEUE_LENGTH ) ;
2016-06-15 20:42:56 +02:00
( void ) orb_unadvertise ( h ) ;
return 0 ;
}
2016-03-10 11:48:02 -05:00
if ( ! strcmp ( argv [ 1 ] , " mode " ) ) {
if ( argc > 2 ) {
2016-04-04 13:23:30 +02:00
uint8_t new_main_state = commander_state_s : : MAIN_STATE_MAX ;
2016-03-10 11:48:02 -05:00
if ( ! strcmp ( argv [ 2 ] , " manual " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_MANUAL ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " altctl " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_ALTCTL ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " posctl " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_POSCTL ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " auto:mission " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_AUTO_MISSION ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " auto:loiter " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_AUTO_LOITER ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " auto:rtl " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_AUTO_RTL ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " acro " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_ACRO ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " offboard " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_OFFBOARD ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " stabilized " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_STAB ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " rattitude " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_RATTITUDE ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " auto:takeoff " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_AUTO_TAKEOFF ;
2016-03-10 11:48:02 -05:00
} else if ( ! strcmp ( argv [ 2 ] , " auto:land " ) ) {
2016-04-04 13:23:30 +02:00
new_main_state = commander_state_s : : MAIN_STATE_AUTO_LAND ;
2018-01-14 23:23:14 +05:30
} else if ( ! strcmp ( argv [ 2 ] , " auto:precland " ) ) {
new_main_state = commander_state_s : : MAIN_STATE_AUTO_PRECLAND ;
2016-03-10 11:48:02 -05:00
} else {
warnx ( " argument %s unsupported. " , argv [ 2 ] ) ;
}
2018-03-27 15:35:55 -04:00
if ( TRANSITION_DENIED = = main_state_transition ( status , new_main_state , status_flags , & internal_state ) ) {
2016-03-10 11:48:02 -05:00
warnx ( " mode change failed " ) ;
}
return 0 ;
} else {
warnx ( " missing argument " ) ;
}
}
2016-02-22 22:15:12 +01:00
if ( ! strcmp ( argv [ 1 ] , " lockdown " ) ) {
2016-02-23 13:06:41 +01:00
if ( argc < 3 ) {
usage ( " not enough arguments, missing [on, off] " ) ;
return 1 ;
}
2017-07-27 17:08:22 -07:00
struct vehicle_command_s cmd = {
. timestamp = 0 ,
. param5 = 0.0f ,
. param6 = 0.0f ,
/* if the comparison matches for off (== 0) set 0.0f, 2.0f (on) else */
. param1 = strcmp ( argv [ 2 ] , " off " ) ? 2.0f : 0.0f , /* lockdown */
. param2 = 0.0f ,
. param3 = 0.0f ,
. param4 = 0.0f ,
. param7 = 0.0f ,
. command = vehicle_command_s : : VEHICLE_CMD_DO_FLIGHTTERMINATION ,
2017-09-26 12:25:02 -04:00
. target_system = status . system_id ,
. target_component = status . component_id
2017-07-27 17:08:22 -07:00
} ;
2016-02-22 22:15:12 +01:00
2016-09-07 14:24:09 +02:00
orb_advert_t h = orb_advertise_queue ( ORB_ID ( vehicle_command ) , & cmd , vehicle_command_s : : ORB_QUEUE_LENGTH ) ;
( void ) orb_unadvertise ( h ) ;
2016-02-22 22:15:12 +01:00
return 0 ;
}
2013-07-16 09:35:31 +02:00
usage ( " unrecognized command " ) ;
2015-04-15 19:38:59 -07:00
return 1 ;
2013-07-16 09:35:31 +02:00
}
void usage ( const char * reason )
{
2015-11-03 22:53:03 +01:00
if ( reason & & * reason > 0 ) {
PX4_INFO ( " %s " , reason ) ;
2014-05-11 13:36:51 +02:00
}
2013-07-16 09:35:31 +02:00
2016-06-15 20:42:56 +02:00
PX4_INFO ( " usage: commander {start|stop|status|calibrate|check|arm|disarm|takeoff|land|transition|mode} \n " ) ;
2013-07-16 09:35:31 +02:00
}
2013-02-24 21:57:38 +01:00
2013-08-27 23:08:00 +02:00
void print_status ( )
{
2015-02-27 19:31:04 +01:00
warnx ( " type: %s " , ( status . is_rotary_wing ) ? " symmetric motion " : " forward motion " ) ;
2016-04-21 10:36:14 +02:00
warnx ( " safety: USB enabled: %s, power state valid: %s " , ( status_flags . usb_connected ) ? " [OK] " : " [NO] " ,
2016-02-26 11:01:12 +00:00
( status_flags . condition_power_input_valid ) ? " [OK] " : " [NO] " ) ;
2015-12-28 15:13:09 +01:00
warnx ( " home: lat = %.7f, lon = %.7f, alt = %.2f, yaw: %.2f " , _home . lat , _home . lon , ( double ) _home . alt , ( double ) _home . yaw ) ;
2015-06-08 15:19:41 +02:00
warnx ( " home: x = %.7f, y = %.7f, z = %.2f " , ( double ) _home . x , ( double ) _home . y , ( double ) _home . z ) ;
2017-12-21 16:43:34 +01:00
warnx ( " datalink: %s %s " , ( status . data_link_lost ) ? " LOST " : " OK " , ( status . high_latency_data_link_active ) ? " (high latency) " : " " ) ;
2016-04-04 13:23:30 +02:00
warnx ( " main state: %d " , internal_state . main_state ) ;
2016-03-13 19:49:18 +01:00
warnx ( " nav state: %d " , status . nav_state ) ;
2018-01-28 00:22:29 +09:00
warnx ( " arming: %s " , arming_state_names [ status . arming_state ] ) ;
2013-08-17 15:47:42 +02:00
}
2013-09-08 21:06:55 +02:00
static orb_advert_t status_pub ;
2016-03-15 18:25:02 +00:00
transition_result_t arm_disarm ( bool arm , orb_advert_t * mavlink_log_pub_local , const char * armedBy )
2014-01-16 10:58:05 +01:00
{
2014-05-11 13:36:51 +02:00
transition_result_t arming_res = TRANSITION_NOT_CHANGED ;
2016-04-04 13:23:30 +02:00
// Transition the armed state. By passing mavlink_log_pub to arming_state_transition it will
2016-02-24 08:00:33 +00:00
// output appropriate error messages if the state cannot transition.
2016-04-07 16:19:20 +02:00
arming_res = arming_state_transition ( & status ,
2018-03-27 16:27:47 -04:00
battery ,
safety ,
2016-02-24 08:00:33 +00:00
arm ? vehicle_status_s : : ARMING_STATE_ARMED : vehicle_status_s : : ARMING_STATE_STANDBY ,
& armed ,
true /* fRunPreArmChecks */ ,
mavlink_log_pub_local ,
2016-02-26 11:01:12 +00:00
& status_flags ,
2017-05-08 18:30:47 -07:00
arm_requirements ,
2016-11-14 00:15:20 +01:00
hrt_elapsed_time ( & commander_boot_timestamp ) ) ;
2014-05-11 13:36:51 +02:00
2016-03-15 18:25:02 +00:00
if ( arming_res = = TRANSITION_CHANGED ) {
2016-10-30 17:10:52 -04:00
mavlink_log_info ( mavlink_log_pub_local , " %s by %s " , arm ? " ARMED " : " DISARMED " , armedBy ) ;
2014-05-11 13:36:51 +02:00
} else if ( arming_res = = TRANSITION_DENIED ) {
tune_negative ( true ) ;
}
return arming_res ;
2014-01-16 10:58:05 +01:00
}
2018-03-23 14:13:09 +01:00
Commander : : Commander ( ) :
ModuleParams ( nullptr ) ,
2018-03-15 01:15:35 -04:00
_mission_result_sub ( ORB_ID ( mission_result ) ) ,
_global_position_sub ( ORB_ID ( vehicle_global_position ) ) ,
_local_position_sub ( ORB_ID ( vehicle_local_position ) )
2018-03-23 14:13:09 +01:00
{
}
2017-12-20 15:39:20 -05:00
bool
2018-03-15 01:15:35 -04:00
Commander : : handle_command ( vehicle_status_s * status_local , const vehicle_command_s & cmd , actuator_armed_s * armed_local ,
home_position_s * home , orb_advert_t * home_pub , orb_advert_t * command_ack_pub , bool * changed )
2012-08-04 15:12:36 -07:00
{
2014-04-08 17:06:52 +02:00
/* only handle commands that are meant to be handled by this system and component */
2018-03-27 15:16:19 -04:00
if ( cmd . target_system ! = status_local - > system_id | | ( ( cmd . target_component ! = status_local - > component_id )
& & ( cmd . target_component ! = 0 ) ) ) { // component_id 0: valid for all components
2014-04-08 17:06:52 +02:00
return false ;
}
2014-05-27 21:56:32 +02:00
/* result of the command */
2015-05-26 22:55:14 -07:00
unsigned cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_UNSUPPORTED ;
2013-08-17 18:39:46 +02:00
2012-08-04 15:12:36 -07:00
/* request to set different system mode */
2018-03-27 15:16:19 -04:00
switch ( cmd . command ) {
2016-04-23 20:12:27 +02:00
case vehicle_command_s : : VEHICLE_CMD_DO_REPOSITION : {
// Just switch the flight mode here, the navigator takes care of
// doing something sensible with the coordinates. Its designed
// to not require navigator and command to receive / process
// the data at the exact same time.
2016-04-24 11:54:50 +02:00
// Check if a mode switch had been requested
2018-03-27 15:16:19 -04:00
if ( ( ( ( uint32_t ) cmd . param2 ) & 1 ) > 0 ) {
2018-03-27 15:35:55 -04:00
transition_result_t main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_LOITER , status_flags , & internal_state ) ;
2016-04-24 11:54:50 +02:00
if ( ( main_ret ! = TRANSITION_DENIED ) ) {
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
2016-04-23 20:12:27 +02:00
2016-04-24 11:54:50 +02:00
} else {
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
mavlink_log_critical ( & mavlink_log_pub , " Rejecting reposition command " ) ;
}
2016-04-23 20:12:27 +02:00
} else {
2016-04-24 11:54:50 +02:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
2016-04-23 20:12:27 +02:00
}
}
break ;
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_DO_SET_MODE : {
2018-03-27 15:16:19 -04:00
uint8_t base_mode = ( uint8_t ) cmd . param1 ;
uint8_t custom_main_mode = ( uint8_t ) cmd . param2 ;
uint8_t custom_sub_mode = ( uint8_t ) cmd . param3 ;
2013-08-07 20:21:49 +02:00
2014-05-27 21:56:32 +02:00
transition_result_t arming_ret = TRANSITION_NOT_CHANGED ;
2013-10-21 20:07:47 +02:00
2014-05-27 21:56:32 +02:00
transition_result_t main_ret = TRANSITION_NOT_CHANGED ;
2014-01-26 11:52:33 +01:00
2014-05-27 21:56:32 +02:00
/* set HIL state */
2016-07-01 18:04:09 +02:00
hil_state_t new_hil_state = ( base_mode & VEHICLE_MODE_FLAG_HIL_ENABLED ) ? vehicle_status_s : : HIL_STATE_ON : vehicle_status_s : : HIL_STATE_OFF ;
2016-03-15 18:25:02 +00:00
transition_result_t hil_ret = hil_state_transition ( new_hil_state , status_pub , status_local , & mavlink_log_pub ) ;
2013-09-08 21:06:55 +02:00
2016-12-06 17:25:49 +01:00
// We ignore base_mode & VEHICLE_MODE_FLAG_SAFETY_ARMED because
// the command VEHICLE_CMD_COMPONENT_ARM_DISARM should be used
// instead according to the latest mavlink spec.
2012-08-04 15:12:36 -07:00
2016-07-01 18:04:09 +02:00
if ( base_mode & VEHICLE_MODE_FLAG_CUSTOM_MODE_ENABLED ) {
2014-05-27 21:56:32 +02:00
/* use autopilot-specific mode */
if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_MANUAL ) {
/* MANUAL */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2013-08-07 20:21:49 +02:00
2014-05-11 13:35:05 +02:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_ALTCTL ) {
/* ALTCTL */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_ALTCTL , status_flags , & internal_state ) ;
2012-12-27 17:13:48 +01:00
2014-05-11 13:35:05 +02:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_POSCTL ) {
/* POSCTL */
2018-03-15 01:15:35 -04:00
reset_posvel_validity ( changed ) ;
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_POSCTL , status_flags , & internal_state ) ;
2012-12-27 17:13:48 +01:00
2013-08-25 20:17:42 +02:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_AUTO ) {
2013-08-07 20:21:49 +02:00
/* AUTO */
2015-11-29 19:26:45 +01:00
if ( custom_sub_mode > 0 ) {
2018-03-15 01:15:35 -04:00
reset_posvel_validity ( changed ) ;
2015-11-29 19:26:45 +01:00
switch ( custom_sub_mode ) {
case PX4_CUSTOM_SUB_MODE_AUTO_LOITER :
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_LOITER , status_flags , & internal_state ) ;
2015-11-29 19:26:45 +01:00
break ;
2018-04-12 01:09:56 -04:00
2015-11-29 19:26:45 +01:00
case PX4_CUSTOM_SUB_MODE_AUTO_MISSION :
2017-12-19 11:02:34 -05:00
if ( status_flags . condition_auto_mission_available ) {
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_MISSION , status_flags , & internal_state ) ;
2017-07-09 13:50:45 +02:00
} else {
main_ret = TRANSITION_DENIED ;
}
2018-04-12 01:09:56 -04:00
2015-11-29 19:26:45 +01:00
break ;
2018-04-12 01:09:56 -04:00
2015-11-29 19:26:45 +01:00
case PX4_CUSTOM_SUB_MODE_AUTO_RTL :
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_RTL , status_flags , & internal_state ) ;
2015-11-29 19:26:45 +01:00
break ;
2018-04-12 01:09:56 -04:00
2015-12-02 12:04:34 +01:00
case PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF :
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_TAKEOFF , status_flags , & internal_state ) ;
2015-12-02 12:04:34 +01:00
break ;
2018-04-12 01:09:56 -04:00
2015-12-18 09:48:47 +01:00
case PX4_CUSTOM_SUB_MODE_AUTO_LAND :
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_LAND , status_flags , & internal_state ) ;
2015-12-18 09:48:47 +01:00
break ;
2018-04-12 01:09:56 -04:00
2016-06-14 13:30:59 -04:00
case PX4_CUSTOM_SUB_MODE_AUTO_FOLLOW_TARGET :
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_FOLLOW_TARGET , status_flags , & internal_state ) ;
2016-02-18 06:57:01 -08:00
break ;
2018-04-12 01:09:56 -04:00
2018-04-07 01:48:04 +03:00
case PX4_CUSTOM_SUB_MODE_AUTO_PRECLAND :
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_PRECLAND , status_flags , & internal_state ) ;
break ;
2015-11-29 19:26:45 +01:00
default :
main_ret = TRANSITION_DENIED ;
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " Unsupported auto mode " ) ;
2015-11-29 19:26:45 +01:00
break ;
}
} else {
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_MISSION , status_flags , & internal_state ) ;
2015-11-25 16:22:23 -05:00
}
2014-05-20 00:03:00 +02:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_ACRO ) {
/* ACRO */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_ACRO , status_flags , & internal_state ) ;
2014-05-21 10:40:58 +02:00
2016-03-09 16:30:56 -05:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_RATTITUDE ) {
/* RATTITUDE */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_RATTITUDE , status_flags , & internal_state ) ;
2016-03-09 16:30:56 -05:00
2015-05-17 12:58:44 +02:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_STABILIZED ) {
/* STABILIZED */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_STAB , status_flags , & internal_state ) ;
2015-05-17 12:58:44 +02:00
2014-01-29 21:21:16 +01:00
} else if ( custom_main_mode = = PX4_CUSTOM_MAIN_MODE_OFFBOARD ) {
2018-03-15 01:15:35 -04:00
reset_posvel_validity ( changed ) ;
2014-01-29 21:21:16 +01:00
/* OFFBOARD */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_OFFBOARD , status_flags , & internal_state ) ;
2013-08-07 20:21:49 +02:00
}
2012-12-27 17:13:48 +01:00
2014-05-27 21:56:32 +02:00
} else {
2013-08-07 20:21:49 +02:00
/* use base mode */
2016-07-01 18:04:09 +02:00
if ( base_mode & VEHICLE_MODE_FLAG_AUTO_ENABLED ) {
2013-08-07 20:21:49 +02:00
/* AUTO */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_MISSION , status_flags , & internal_state ) ;
2013-08-07 20:21:49 +02:00
2016-07-01 18:04:09 +02:00
} else if ( base_mode & VEHICLE_MODE_FLAG_MANUAL_INPUT_ENABLED ) {
if ( base_mode & VEHICLE_MODE_FLAG_GUIDED_ENABLED ) {
2014-05-11 13:35:05 +02:00
/* POSCTL */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_POSCTL , status_flags , & internal_state ) ;
2013-08-07 20:21:49 +02:00
2016-07-01 18:04:09 +02:00
} else if ( base_mode & VEHICLE_MODE_FLAG_STABILIZE_ENABLED ) {
2015-05-17 12:58:44 +02:00
/* STABILIZED */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_STAB , status_flags , & internal_state ) ;
2018-04-12 01:09:56 -04:00
2015-05-17 12:58:44 +02:00
} else {
2013-07-31 20:58:27 +04:00
/* MANUAL */
2018-03-27 15:35:55 -04:00
main_ret = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2013-07-31 20:58:27 +04:00
}
2013-02-19 12:32:47 -08:00
}
2013-07-31 20:58:27 +04:00
}
2014-01-26 11:52:33 +01:00
2016-01-18 23:16:31 -08:00
if ( ( hil_ret ! = TRANSITION_DENIED ) & & ( arming_ret ! = TRANSITION_DENIED ) & & ( main_ret ! = TRANSITION_DENIED ) ) {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
2012-08-29 14:20:55 +02:00
2014-05-27 21:56:32 +02:00
} else {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
2015-10-07 16:35:51 +02:00
if ( arming_ret = = TRANSITION_DENIED ) {
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " Rejecting arming cmd " ) ;
2015-10-07 16:35:51 +02:00
}
2014-05-27 21:56:32 +02:00
}
2013-07-31 20:58:27 +04:00
}
2014-04-27 02:26:09 +02:00
break ;
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_COMPONENT_ARM_DISARM : {
2015-03-08 14:49:55 +01:00
2014-07-13 11:41:39 +02:00
// Adhere to MAVLink specs, but base on knowledge that these fundamentally encode ints
// for logic state parameters
2018-03-27 15:16:19 -04:00
if ( static_cast < int > ( cmd . param1 + 0.5f ) ! = 0 & & static_cast < int > ( cmd . param1 + 0.5f ) ! = 1 ) {
mavlink_log_critical ( & mavlink_log_pub , " Unsupported ARM_DISARM param: %.3f " , ( double ) cmd . param1 ) ;
2014-05-06 14:57:06 +02:00
2014-05-11 13:36:51 +02:00
} else {
2018-03-27 15:16:19 -04:00
bool cmd_arms = ( static_cast < int > ( cmd . param1 + 0.5f ) = = 1 ) ;
2014-07-13 11:41:39 +02:00
2014-05-11 13:36:51 +02:00
// Flick to inair restore first if this comes from an onboard system
2018-03-27 15:16:19 -04:00
if ( cmd . source_system = = status_local - > system_id & & cmd . source_component = = status_local - > component_id ) {
2016-02-26 15:41:03 +00:00
status . arming_state = vehicle_status_s : : ARMING_STATE_IN_AIR_RESTORE ;
2015-03-17 10:06:02 +01:00
2016-06-21 16:20:33 +08:00
} else {
2015-04-26 17:39:00 +02:00
// Refuse to arm if preflight checks have failed
2016-05-09 23:01:06 +02:00
if ( ( ! status_local - > hil_state ) ! = vehicle_status_s : : HIL_STATE_ON & & ! status_flags . condition_system_sensors_initialized ) {
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " Arming DENIED. Preflight checks have failed. " ) ;
2016-02-12 21:39:50 -08:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED ;
2015-03-17 10:06:02 +01:00
break ;
}
2016-02-12 21:39:50 -08:00
2016-05-09 23:01:06 +02:00
// Refuse to arm if in manual with non-zero throttle
2016-10-30 17:10:52 -04:00
if ( cmd_arms
2018-04-12 01:09:56 -04:00
& & ( status_local - > nav_state = = vehicle_status_s : : NAVIGATION_STATE_MANUAL
2016-10-31 11:46:17 -04:00
| | status_local - > nav_state = = vehicle_status_s : : NAVIGATION_STATE_ACRO
2016-10-30 17:10:52 -04:00
| | status_local - > nav_state = = vehicle_status_s : : NAVIGATION_STATE_STAB
2016-10-31 11:46:17 -04:00
| | status_local - > nav_state = = vehicle_status_s : : NAVIGATION_STATE_RATTITUDE )
2018-04-12 01:09:56 -04:00
& & ( sp_man . z > 0.1f ) ) {
2016-10-30 17:10:52 -04:00
2016-05-09 23:01:06 +02:00
mavlink_log_critical ( & mavlink_log_pub , " Arming DENIED. Manual throttle non-zero. " ) ;
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED ;
break ;
}
2015-03-17 10:06:02 +01:00
}
2014-05-11 13:36:51 +02:00
2016-10-30 17:10:52 -04:00
transition_result_t arming_res = arm_disarm ( cmd_arms , & mavlink_log_pub , " arm/disarm component command " ) ;
2014-05-11 13:36:51 +02:00
if ( arming_res = = TRANSITION_DENIED ) {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
2014-05-11 13:36:51 +02:00
} else {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
2015-12-20 20:29:22 +01:00
/* update home position on arming if at least 500 ms from commander start spent to avoid setting home on in-air restart */
if ( cmd_arms & & ( arming_res = = TRANSITION_CHANGED ) & &
2018-04-12 01:09:56 -04:00
( hrt_absolute_time ( ) > ( commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL ) ) & &
! home - > manual_home ) {
2015-12-20 20:29:22 +01:00
2018-03-15 01:15:35 -04:00
set_home_position ( * home_pub , * home , false ) ;
2015-12-20 20:29:22 +01:00
}
2014-05-11 13:36:51 +02:00
}
}
2013-09-22 14:43:12 +02:00
}
2013-07-31 20:58:27 +04:00
break ;
2013-01-11 07:42:09 +01:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_DO_FLIGHTTERMINATION : {
2018-03-27 15:16:19 -04:00
if ( cmd . param1 > 1.5f ) {
2016-02-22 22:15:12 +01:00
armed_local - > lockdown = true ;
warnx ( " forcing lockdown (motors off) " ) ;
2018-03-27 15:16:19 -04:00
} else if ( cmd . param1 > 0.5f ) {
2014-07-19 14:39:41 +02:00
//XXX update state machine?
armed_local - > force_failsafe = true ;
2014-08-15 00:07:38 +02:00
warnx ( " forcing failsafe (termination) " ) ;
2014-10-23 16:17:20 +02:00
2018-03-27 15:16:19 -04:00
if ( ( int ) cmd . param2 < = 0 ) {
2016-02-23 13:06:41 +01:00
/* reset all commanded failure modes */
warnx ( " reset all non-flighttermination failsafe commands " ) ;
}
2013-12-08 16:52:41 +01:00
} else {
2014-07-19 14:39:41 +02:00
armed_local - > force_failsafe = false ;
2016-02-22 22:15:12 +01:00
armed_local - > lockdown = false ;
2016-02-23 13:06:41 +01:00
warnx ( " disabling failsafe and lockdown " ) ;
2013-12-08 16:52:41 +01:00
}
2014-10-23 16:17:20 +02:00
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
2013-12-08 16:52:41 +01:00
}
break ;
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_DO_SET_HOME : {
2018-03-27 15:16:19 -04:00
bool use_current = cmd . param1 > 0.5f ;
2014-05-11 13:36:51 +02:00
2014-04-02 16:53:22 +04:00
if ( use_current ) {
/* use current position */
2018-03-15 01:15:35 -04:00
if ( set_home_position ( * home_pub , * home , false ) ) {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
2014-04-02 16:53:22 +04:00
} else {
2015-05-26 22:55:14 -07:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
2014-04-02 16:53:22 +04:00
}
} else {
2018-03-27 15:16:19 -04:00
const double lat = cmd . param5 ;
const double lon = cmd . param6 ;
const float alt = cmd . param7 ;
2014-04-02 16:53:22 +04:00
2017-12-18 22:11:12 -05:00
if ( PX4_ISFINITE ( lat ) & & PX4_ISFINITE ( lon ) & & PX4_ISFINITE ( alt ) ) {
2018-03-15 01:15:35 -04:00
const vehicle_local_position_s & local_pos = _local_position_sub . get ( ) ;
2018-03-27 15:16:19 -04:00
if ( local_pos . xy_global & & local_pos . z_global ) {
2017-12-18 22:11:12 -05:00
/* use specified position */
home - > timestamp = hrt_absolute_time ( ) ;
home - > lat = lat ;
home - > lon = lon ;
home - > alt = alt ;
2014-04-02 16:53:22 +04:00
2017-12-18 22:11:12 -05:00
home - > manual_home = true ;
home - > valid_alt = true ;
home - > valid_hpos = true ;
// update local projection reference including altitude
struct map_projection_reference_s ref_pos ;
2018-03-27 15:16:19 -04:00
map_projection_init ( & ref_pos , local_pos . ref_lat , local_pos . ref_lon ) ;
2017-12-18 22:11:12 -05:00
map_projection_project ( & ref_pos , lat , lon , & home - > x , & home - > y ) ;
2018-03-27 15:16:19 -04:00
home - > z = - ( alt - local_pos . ref_alt ) ;
2017-12-18 22:11:12 -05:00
/* announce new home position */
if ( * home_pub ! = nullptr ) {
orb_publish ( ORB_ID ( home_position ) , * home_pub , home ) ;
} else {
* home_pub = orb_advertise ( ORB_ID ( home_position ) , home ) ;
}
2014-04-02 16:53:22 +04:00
2017-12-18 22:11:12 -05:00
/* mark home position as set */
status_flags . condition_home_position_valid = true ;
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
} else {
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
}
2014-04-02 16:53:22 +04:00
} else {
2017-12-18 22:11:12 -05:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED ;
2014-04-02 16:53:22 +04:00
}
}
}
break ;
2014-10-23 16:17:20 +02:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_NAV_GUIDED_ENABLE : {
2014-07-14 11:19:06 +02:00
transition_result_t res = TRANSITION_DENIED ;
2016-02-26 15:41:03 +00:00
static main_state_t main_state_pre_offboard = commander_state_s : : MAIN_STATE_MANUAL ;
2014-10-23 16:17:20 +02:00
2016-02-26 15:41:03 +00:00
if ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_OFFBOARD ) {
main_state_pre_offboard = internal_state . main_state ;
2014-07-14 11:19:06 +02:00
}
2014-10-23 16:17:20 +02:00
2018-03-27 15:16:19 -04:00
if ( cmd . param1 > 0.5f ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_OFFBOARD , status_flags , & internal_state ) ;
2014-10-23 16:17:20 +02:00
2014-07-14 11:19:06 +02:00
if ( res = = TRANSITION_DENIED ) {
2018-03-27 15:16:19 -04:00
print_reject_mode ( " OFFBOARD " ) ;
2016-02-26 10:20:52 +00:00
status_flags . offboard_control_set_by_command = false ;
2014-10-23 16:17:20 +02:00
2014-07-16 09:38:57 +02:00
} else {
/* Set flag that offboard was set via command, main state is not overridden by rc */
2016-02-26 10:20:52 +00:00
status_flags . offboard_control_set_by_command = true ;
2014-07-14 11:19:06 +02:00
}
2014-10-23 16:17:20 +02:00
2014-07-14 11:19:06 +02:00
} else {
/* If the mavlink command is used to enable or disable offboard control:
* switch back to previous mode when disabling */
2018-03-27 15:35:55 -04:00
res = main_state_transition ( * status_local , main_state_pre_offboard , status_flags , & internal_state ) ;
2016-02-26 10:20:52 +00:00
status_flags . offboard_control_set_by_command = false ;
2014-07-14 11:19:06 +02:00
}
2016-06-21 16:20:33 +08:00
if ( res = = TRANSITION_DENIED ) {
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
} else {
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
}
2014-07-14 11:19:06 +02:00
}
break ;
2014-10-23 16:17:20 +02:00
2016-10-30 16:10:02 -04:00
case vehicle_command_s : : VEHICLE_CMD_NAV_RETURN_TO_LAUNCH : {
2017-04-16 17:07:19 -07:00
/* switch to RTL which ends the mission */
2018-03-27 15:35:55 -04:00
if ( TRANSITION_CHANGED = = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_RTL , status_flags , & internal_state ) ) {
2016-10-30 16:10:02 -04:00
mavlink_and_console_log_info ( & mavlink_log_pub , " Returning to launch " ) ;
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
} else {
mavlink_log_critical ( & mavlink_log_pub , " Return to launch denied " ) ;
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
}
}
break ;
2015-11-20 11:15:17 +01:00
case vehicle_command_s : : VEHICLE_CMD_NAV_TAKEOFF : {
/* ok, home set, use it to take off */
2018-03-27 15:35:55 -04:00
if ( TRANSITION_CHANGED = = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_TAKEOFF , status_flags , & internal_state ) ) {
2017-02-04 21:05:28 +01:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
} else if ( internal_state . main_state = = commander_state_s : : MAIN_STATE_AUTO_TAKEOFF ) {
2016-06-21 16:20:33 +08:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
2015-11-20 11:15:17 +01:00
} else {
2016-09-20 12:56:08 +02:00
mavlink_log_critical ( & mavlink_log_pub , " Takeoff denied, disarm and re-try " ) ;
2016-06-21 16:20:33 +08:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
2015-11-20 11:15:17 +01:00
}
}
break ;
2015-12-28 16:00:32 +01:00
case vehicle_command_s : : VEHICLE_CMD_NAV_LAND : {
2018-03-27 15:35:55 -04:00
if ( TRANSITION_CHANGED = = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_LAND , status_flags , & internal_state ) ) {
2016-05-13 11:03:18 +02:00
mavlink_and_console_log_info ( & mavlink_log_pub , " Landing at current position " ) ;
2016-06-21 16:20:33 +08:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
2015-12-28 16:00:32 +01:00
} else {
2016-10-30 16:10:02 -04:00
mavlink_log_critical ( & mavlink_log_pub , " Landing denied, land manually " ) ;
2016-06-21 16:20:33 +08:00
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
2015-12-28 16:00:32 +01:00
}
}
break ;
2018-01-14 23:23:14 +05:30
case vehicle_command_s : : VEHICLE_CMD_NAV_PRECLAND : {
2018-03-27 15:35:55 -04:00
if ( TRANSITION_CHANGED = = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_PRECLAND , status_flags , & internal_state ) ) {
2018-01-14 23:23:14 +05:30
mavlink_and_console_log_info ( & mavlink_log_pub , " Precision landing " ) ;
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
} else {
mavlink_log_critical ( & mavlink_log_pub , " Precision landing denied, land manually " ) ;
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
}
}
break ;
2016-08-22 01:03:58 -04:00
case vehicle_command_s : : VEHICLE_CMD_MISSION_START : {
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED ;
// check if current mission and first item are valid
2017-12-19 11:02:34 -05:00
if ( status_flags . condition_auto_mission_available ) {
2016-08-22 01:03:58 -04:00
// requested first mission item valid
2018-03-27 15:16:19 -04:00
if ( PX4_ISFINITE ( cmd . param1 ) & & ( cmd . param1 > = - 1 ) & & ( cmd . param1 < _mission_result_sub . get ( ) . seq_total ) ) {
2016-05-19 23:46:06 +02:00
2016-08-22 01:03:58 -04:00
// switch to AUTO_MISSION and ARM
2018-03-27 15:35:55 -04:00
if ( ( TRANSITION_DENIED ! = main_state_transition ( * status_local , commander_state_s : : MAIN_STATE_AUTO_MISSION , status_flags , & internal_state ) )
2016-08-22 01:03:58 -04:00
& & ( TRANSITION_DENIED ! = arm_disarm ( true , & mavlink_log_pub , " mission start command " ) ) ) {
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
} else {
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED ;
mavlink_log_critical ( & mavlink_log_pub , " Mission start denied " ) ;
}
}
} else {
mavlink_log_critical ( & mavlink_log_pub , " Mission start denied, no valid mission " ) ;
}
}
break ;
2018-04-06 17:45:02 +02:00
case vehicle_command_s : : VEHICLE_CMD_CONTROL_HIGH_LATENCY : {
2018-04-12 01:09:56 -04:00
// only send the acknowledge from the commander, the command actually is handled by each mavlink instance
cmd_result = vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED ;
}
break ;
2016-07-04 14:17:27 -04:00
case vehicle_command_s : : VEHICLE_CMD_CUSTOM_0 :
case vehicle_command_s : : VEHICLE_CMD_CUSTOM_1 :
case vehicle_command_s : : VEHICLE_CMD_CUSTOM_2 :
2016-05-19 23:46:06 +02:00
case vehicle_command_s : : VEHICLE_CMD_DO_MOUNT_CONTROL :
case vehicle_command_s : : VEHICLE_CMD_DO_MOUNT_CONFIGURE :
case vehicle_command_s : : VEHICLE_CMD_DO_MOUNT_CONTROL_QUAT :
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_PREFLIGHT_REBOOT_SHUTDOWN :
case vehicle_command_s : : VEHICLE_CMD_PREFLIGHT_CALIBRATION :
case vehicle_command_s : : VEHICLE_CMD_PREFLIGHT_SET_SENSOR_OFFSETS :
case vehicle_command_s : : VEHICLE_CMD_PREFLIGHT_STORAGE :
2015-08-23 13:50:59 +02:00
case vehicle_command_s : : VEHICLE_CMD_PREFLIGHT_UAVCAN :
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_PAYLOAD_PREPARE_DEPLOY :
case vehicle_command_s : : VEHICLE_CMD_PAYLOAD_CONTROL_DEPLOY :
2015-08-06 00:02:54 +02:00
case vehicle_command_s : : VEHICLE_CMD_DO_VTOL_TRANSITION :
2017-04-13 15:25:51 +02:00
case vehicle_command_s : : VEHICLE_CMD_DO_TRIGGER_CONTROL :
2016-02-23 09:25:29 +01:00
case vehicle_command_s : : VEHICLE_CMD_DO_DIGICAM_CONTROL :
case vehicle_command_s : : VEHICLE_CMD_DO_SET_CAM_TRIGG_DIST :
2017-05-01 19:05:50 +02:00
case vehicle_command_s : : VEHICLE_CMD_DO_SET_CAM_TRIGG_INTERVAL :
2017-05-11 21:57:47 +02:00
case vehicle_command_s : : VEHICLE_CMD_SET_CAMERA_MODE :
2016-02-17 16:50:13 +01:00
case vehicle_command_s : : VEHICLE_CMD_DO_CHANGE_SPEED :
2016-08-22 01:03:58 -04:00
case vehicle_command_s : : VEHICLE_CMD_DO_LAND_START :
2016-08-29 23:35:56 +02:00
case vehicle_command_s : : VEHICLE_CMD_DO_GO_AROUND :
2016-06-21 13:36:35 +02:00
case vehicle_command_s : : VEHICLE_CMD_START_RX_PAIR :
2016-10-12 16:42:57 +02:00
case vehicle_command_s : : VEHICLE_CMD_LOGGING_START :
case vehicle_command_s : : VEHICLE_CMD_LOGGING_STOP :
2017-04-16 17:07:19 -07:00
case vehicle_command_s : : VEHICLE_CMD_NAV_DELAY :
2017-11-27 21:43:39 +01:00
case vehicle_command_s : : VEHICLE_CMD_DO_SET_ROI :
case vehicle_command_s : : VEHICLE_CMD_NAV_ROI :
2018-01-24 17:59:29 +01:00
case vehicle_command_s : : VEHICLE_CMD_DO_SET_ROI_LOCATION :
2018-01-22 11:49:36 -08:00
case vehicle_command_s : : VEHICLE_CMD_DO_SET_ROI_WPNEXT_OFFSET :
case vehicle_command_s : : VEHICLE_CMD_DO_SET_ROI_NONE :
2017-10-06 13:15:14 -04:00
/* ignore commands that are handled by other parts of the system */
2013-12-29 12:16:49 +04:00
break ;
2013-05-17 11:24:02 +02:00
default :
2014-04-07 21:42:19 +02:00
/* Warn about unsupported commands, this makes sense because only commands
* to this component ID ( or all ) are passed by mavlink . */
2018-03-27 15:16:19 -04:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_UNSUPPORTED , * command_ack_pub ) ;
2012-08-04 15:12:36 -07:00
break ;
}
2014-05-11 13:36:51 +02:00
2015-05-26 22:55:14 -07:00
if ( cmd_result ! = vehicle_command_s : : VEHICLE_CMD_RESULT_UNSUPPORTED ) {
2014-04-07 21:42:19 +02:00
/* already warned about unsupported commands in "default" case */
2018-03-27 15:16:19 -04:00
answer_command ( cmd , cmd_result , * command_ack_pub ) ;
2012-08-04 15:12:36 -07:00
}
2014-06-29 13:55:55 -07:00
return true ;
2012-08-04 15:12:36 -07:00
}
2015-01-16 16:43:11 +01:00
/**
2017-12-07 08:37:04 +11:00
* @ brief This function initializes the home position an altitude of the vehicle . This happens first time we get a good GPS fix and each
2015-01-16 16:43:11 +01:00
* time the vehicle is armed with a good GPS fix .
* */
2017-12-20 15:39:20 -05:00
bool
2018-03-15 01:15:35 -04:00
Commander : : set_home_position ( orb_advert_t & homePub , home_position_s & home , bool set_alt_only_to_lpos_ref )
2015-01-16 16:43:11 +01:00
{
2018-03-15 01:15:35 -04:00
const vehicle_local_position_s & localPosition = _local_position_sub . get ( ) ;
const vehicle_global_position_s & globalPosition = _global_position_sub . get ( ) ;
2017-12-07 08:37:04 +11:00
if ( ! set_alt_only_to_lpos_ref ) {
//Need global and local position fix to be able to set home
if ( ! status_flags . condition_global_position_valid | | ! status_flags . condition_local_position_valid ) {
2017-12-18 22:11:12 -05:00
return false ;
2017-12-07 08:37:04 +11:00
}
//Ensure that the GPS accuracy is good enough for intializing home
2018-01-28 13:19:59 -05:00
if ( globalPosition . eph > _home_eph_threshold . get ( ) | | globalPosition . epv > _home_epv_threshold . get ( ) ) {
2017-12-18 22:11:12 -05:00
return false ;
2017-12-07 08:37:04 +11:00
}
2015-01-16 16:43:11 +01:00
2017-12-18 22:11:12 -05:00
// Set home position
2017-12-06 09:54:06 +11:00
home . lat = globalPosition . lat ;
home . lon = globalPosition . lon ;
home . valid_hpos = true ;
home . alt = globalPosition . alt ;
home . valid_alt = true ;
2015-01-16 16:43:11 +01:00
2017-12-06 09:54:06 +11:00
home . x = localPosition . x ;
home . y = localPosition . y ;
home . z = localPosition . z ;
2017-12-06 07:34:30 +11:00
2018-02-18 18:23:12 -05:00
home . yaw = localPosition . yaw ;
2015-01-16 16:43:11 +01:00
2017-12-06 09:54:06 +11:00
//Play tune first time we initialize HOME
if ( ! status_flags . condition_home_position_valid ) {
tune_home_set ( true ) ;
}
/* mark home position as set */
status_flags . condition_home_position_valid = true ;
2015-10-27 09:58:54 +01:00
2017-12-06 09:54:06 +11:00
} else if ( ! home . valid_alt & & localPosition . z_global ) {
2017-12-07 08:37:04 +11:00
// handle special case where we are setting only altitude using local position reference
2017-12-06 09:54:06 +11:00
home . alt = localPosition . ref_alt ;
home . valid_alt = true ;
2017-12-07 08:37:04 +11:00
2017-12-06 09:54:06 +11:00
} else {
2017-12-18 22:11:12 -05:00
return false ;
2017-12-06 09:54:06 +11:00
}
2015-01-16 16:43:11 +01:00
2017-12-18 22:11:12 -05:00
home . timestamp = hrt_absolute_time ( ) ;
home . manual_home = false ;
2015-01-16 16:43:11 +01:00
/* announce new home position */
2015-05-25 22:21:23 -07:00
if ( homePub ! = nullptr ) {
2015-01-16 16:43:11 +01:00
orb_publish ( ORB_ID ( home_position ) , homePub , & home ) ;
2017-12-07 08:37:04 +11:00
2015-01-16 16:43:11 +01:00
} else {
homePub = orb_advertise ( ORB_ID ( home_position ) , & home ) ;
}
2017-12-18 22:11:12 -05:00
return true ;
2015-01-16 16:43:11 +01:00
}
2017-12-20 15:39:20 -05:00
void
Commander : : run ( )
2012-08-04 15:12:36 -07:00
{
2015-11-10 19:33:14 +05:30
bool sensor_fail_tune_played = false ;
2013-06-25 13:15:38 +02:00
bool arm_tune_played = false ;
2015-10-24 19:14:23 +02:00
bool was_landed = true ;
2016-01-28 13:26:49 +01:00
bool was_falling = false ;
2014-04-02 11:57:41 +04:00
bool was_armed = false ;
2013-06-25 13:15:38 +02:00
2016-02-25 17:00:39 +00:00
// XXX for now just set sensors as initialized
status_flags . condition_system_sensors_initialized = true ;
2012-09-21 12:55:41 +02:00
/* set parameters */
2012-12-31 12:31:31 -08:00
param_t _param_sys_type = param_find ( " MAV_TYPE " ) ;
2013-02-17 16:06:33 +01:00
param_t _param_system_id = param_find ( " MAV_SYS_ID " ) ;
param_t _param_component_id = param_find ( " MAV_COMP_ID " ) ;
2016-04-23 16:51:10 +02:00
param_t _param_enable_datalink_loss = param_find ( " NAV_DLL_ACT " ) ;
2016-06-20 19:23:11 +02:00
param_t _param_offboard_loss_act = param_find ( " COM_OBL_ACT " ) ;
param_t _param_offboard_loss_rc_act = param_find ( " COM_OBL_RC_ACT " ) ;
2016-06-06 11:19:10 +02:00
param_t _param_enable_rc_loss = param_find ( " NAV_RCL_ACT " ) ;
2014-07-20 17:53:04 +02:00
param_t _param_datalink_loss_timeout = param_find ( " COM_DL_LOSS_T " ) ;
2017-12-21 16:43:34 +01:00
param_t _param_highlatencydatalink_loss_timeout = param_find ( " COM_HLDL_LOSS_T " ) ;
2014-09-05 12:06:05 +02:00
param_t _param_rc_loss_timeout = param_find ( " COM_RC_LOSS_T " ) ;
2014-07-24 08:57:58 +02:00
param_t _param_datalink_regain_timeout = param_find ( " COM_DL_REG_T " ) ;
2017-12-21 16:43:34 +01:00
param_t _param_highlatencydatalink_regain_timeout = param_find ( " COM_HLDL_REG_T " ) ;
2014-09-05 08:59:00 +02:00
param_t _param_ef_throttle_thres = param_find ( " COM_EF_THROT " ) ;
param_t _param_ef_current2throttle_thres = param_find ( " COM_EF_C2T " ) ;
param_t _param_ef_time_thres = param_find ( " COM_EF_TIME " ) ;
2015-05-24 17:40:06 +02:00
param_t _param_rc_in_off = param_find ( " COM_RC_IN_MODE " ) ;
2016-05-20 09:59:23 -06:00
param_t _param_rc_arm_hyst = param_find ( " COM_RC_ARM_HYST " ) ;
2017-02-04 21:05:28 +01:00
param_t _param_min_stick_change = param_find ( " COM_RC_STICK_OV " ) ;
2015-09-27 19:49:01 -04:00
param_t _param_geofence_action = param_find ( " GF_ACTION " ) ;
2015-10-26 09:22:34 +01:00
param_t _param_disarm_land = param_find ( " COM_DISARM_LAND " ) ;
2016-04-23 00:30:50 +02:00
param_t _param_low_bat_act = param_find ( " COM_LOW_BAT_ACT " ) ;
2015-11-26 17:45:20 +01:00
param_t _param_offboard_loss_timeout = param_find ( " COM_OF_LOSS_T " ) ;
2016-06-06 11:18:26 +02:00
param_t _param_arm_without_gps = param_find ( " COM_ARM_WO_GPS " ) ;
2016-11-28 11:29:58 +01:00
param_t _param_arm_switch_is_button = param_find ( " COM_ARM_SWISBTN " ) ;
2017-04-12 02:22:46 +02:00
param_t _param_rc_override = param_find ( " COM_RC_OVERRIDE " ) ;
2017-04-17 00:18:39 -04:00
param_t _param_arm_mission_required = param_find ( " COM_ARM_MIS_REQ " ) ;
2017-10-16 16:53:52 +02:00
param_t _param_flight_uuid = param_find ( " COM_FLIGHT_UUID " ) ;
2017-12-31 19:58:20 +01:00
param_t _param_takeoff_finished_action = param_find ( " COM_TAKEOFF_ACT " ) ;
2012-12-13 10:23:02 +01:00
2016-03-04 11:47:33 +01:00
param_t _param_fmode_1 = param_find ( " COM_FLTMODE1 " ) ;
param_t _param_fmode_2 = param_find ( " COM_FLTMODE2 " ) ;
param_t _param_fmode_3 = param_find ( " COM_FLTMODE3 " ) ;
param_t _param_fmode_4 = param_find ( " COM_FLTMODE4 " ) ;
param_t _param_fmode_5 = param_find ( " COM_FLTMODE5 " ) ;
param_t _param_fmode_6 = param_find ( " COM_FLTMODE6 " ) ;
2017-05-06 09:57:17 +10:00
/* failsafe response to loss of navigation accuracy */
param_t _param_posctl_nav_loss_act = param_find ( " COM_POSCTL_NAVL " ) ;
2013-07-16 09:24:21 +02:00
/* pthread for slow low prio thread */
2013-03-25 14:53:54 -07:00
pthread_t commander_low_prio_thread ;
2012-08-04 15:12:36 -07:00
/* initialize */
2015-03-28 13:54:05 -07:00
if ( led_init ( ) ! = OK ) {
2016-04-21 16:56:37 +02:00
PX4_WARN ( " LED init failed " ) ;
2012-08-04 15:12:36 -07:00
}
2013-06-25 16:30:35 +02:00
if ( buzzer_init ( ) ! = OK ) {
2016-04-21 16:56:37 +02:00
PX4_WARN ( " Buzzer init failed " ) ;
2015-03-28 13:54:05 -07:00
}
2017-07-24 14:33:38 +02:00
int power_button_state_sub = orb_subscribe ( ORB_ID ( power_button_state ) ) ;
{
// we need to do an initial publication to make sure uORB allocates the buffer, which cannot happen
// in IRQ context.
power_button_state_s button_state ;
button_state . timestamp = 0 ;
button_state . event = 0xff ;
power_button_state_pub = orb_advertise ( ORB_ID ( power_button_state ) , & button_state ) ;
orb_copy ( ORB_ID ( power_button_state ) , power_button_state_sub , & button_state ) ;
}
2017-04-18 14:09:48 +02:00
if ( board_register_power_state_notification_cb ( power_button_state_notification_cb ) ! = 0 ) {
PX4_ERR ( " Failed to register power notification callback " ) ;
}
2014-02-01 13:21:51 +01:00
// We want to accept RC inputs as default
2016-02-26 11:01:12 +00:00
status_flags . rc_input_blocked = false ;
2015-05-25 16:34:42 +02:00
status . rc_input_mode = vehicle_status_s : : RC_IN_MODE_DEFAULT ;
2016-04-22 15:15:37 -04:00
internal_state . main_state = commander_state_s : : MAIN_STATE_MANUAL ;
2016-07-19 09:21:35 +02:00
internal_state . timestamp = hrt_absolute_time ( ) ;
2015-01-28 07:58:42 +01:00
status . nav_state = vehicle_status_s : : NAVIGATION_STATE_MANUAL ;
status . arming_state = vehicle_status_s : : ARMING_STATE_INIT ;
2015-08-25 21:59:01 -07:00
2014-06-16 17:34:21 +02:00
status . failsafe = false ;
2013-02-16 13:40:09 -08:00
2012-10-02 13:02:57 +02:00
/* neither manual nor offboard control commands have been received */
2016-02-26 10:20:52 +00:00
status_flags . offboard_control_signal_found_once = false ;
2016-02-26 11:01:12 +00:00
status_flags . rc_signal_found_once = false ;
2013-02-16 13:40:09 -08:00
2012-10-02 13:02:57 +02:00
/* mark all signals lost as long as they haven't been found */
2013-07-28 23:12:16 +04:00
status . rc_signal_lost = true ;
2016-02-26 10:20:52 +00:00
status_flags . offboard_control_signal_lost = true ;
2014-06-16 17:34:21 +02:00
status . data_link_lost = true ;
2015-11-26 17:45:20 +01:00
status_flags . offboard_control_loss_timeout = false ;
2013-02-16 13:40:09 -08:00
2016-02-25 17:00:39 +00:00
status_flags . condition_system_hotplug_timeout = false ;
2013-02-17 23:07:07 -08:00
2013-07-28 23:12:16 +04:00
status . timestamp = hrt_absolute_time ( ) ;
2014-01-27 20:49:17 +01:00
2016-02-25 17:00:39 +00:00
status_flags . condition_power_input_valid = true ;
status_flags . usb_connected = false ;
2014-05-25 08:22:54 +02:00
2014-05-25 20:34:32 +02:00
// CIRCUIT BREAKERS
2016-02-25 17:00:39 +00:00
status_flags . circuit_breaker_engaged_power_check = false ;
status_flags . circuit_breaker_engaged_airspd_check = false ;
status_flags . circuit_breaker_engaged_enginefailure_check = false ;
status_flags . circuit_breaker_engaged_gpsfailure_check = false ;
2015-05-14 19:19:30 +02:00
get_circuit_breaker_params ( ) ;
2014-05-25 20:34:32 +02:00
2017-03-08 11:03:27 +11:00
/* Set position and velocity validty to false */
status_flags . condition_global_position_valid = false ;
status_flags . condition_local_position_valid = false ;
status_flags . condition_local_velocity_valid = false ;
status_flags . condition_local_altitude_valid = false ;
2014-01-27 20:49:17 +01:00
/* publish initial state */
status_pub = orb_advertise ( ORB_ID ( vehicle_status ) , & status ) ;
2014-10-23 16:17:20 +02:00
2015-05-25 22:21:23 -07:00
if ( status_pub = = nullptr ) {
2014-06-13 23:40:48 +02:00
warnx ( " ERROR: orb_advertise for topic vehicle_status failed (uorb app running?). \n " ) ;
warnx ( " exiting. " ) ;
2016-09-20 10:30:18 +02:00
px4_task_exit ( PX4_ERROR ) ;
2014-06-13 23:40:48 +02:00
}
2014-01-27 20:49:17 +01:00
/* Initialize armed with all false */
memset ( & armed , 0 , sizeof ( armed ) ) ;
2015-10-24 19:14:23 +02:00
/* armed topic */
orb_advert_t armed_pub = orb_advertise ( ORB_ID ( actuator_armed ) , & armed ) ;
2014-01-27 20:49:17 +01:00
/* vehicle control mode topic */
memset ( & control_mode , 0 , sizeof ( control_mode ) ) ;
orb_advert_t control_mode_pub = orb_advertise ( ORB_ID ( vehicle_control_mode ) , & control_mode ) ;
2013-06-25 16:30:35 +02:00
2013-01-19 14:46:26 +01:00
/* home position */
2015-05-25 22:21:23 -07:00
orb_advert_t home_pub = nullptr ;
2015-06-08 15:19:41 +02:00
memset ( & _home , 0 , sizeof ( _home ) ) ;
2013-01-19 14:46:26 +01:00
2015-12-12 13:01:49 +01:00
/* command ack */
orb_advert_t command_ack_pub = nullptr ;
2016-02-29 09:40:11 +00:00
orb_advert_t commander_state_pub = nullptr ;
2017-01-27 19:13:18 +01:00
orb_advert_t vehicle_status_flags_pub = nullptr ;
2017-11-14 16:36:11 -05:00
/* init mission state, do it here to allow navigator to use stored mission even if mavlink failed to start */
2017-12-26 16:57:52 -05:00
mission_init ( ) ;
2012-08-04 15:12:36 -07:00
/* Start monitoring loop */
2013-07-16 18:55:32 +02:00
unsigned counter = 0 ;
unsigned stick_off_counter = 0 ;
unsigned stick_on_counter = 0 ;
2012-08-04 15:12:36 -07:00
2013-08-15 17:27:29 +02:00
bool low_battery_voltage_actions_done = false ;
bool critical_battery_voltage_actions_done = false ;
2017-02-22 22:04:04 +01:00
bool emergency_battery_voltage_actions_done = false ;
2013-07-16 18:55:32 +02:00
2013-07-31 20:58:27 +04:00
bool status_changed = true ;
2013-07-16 10:05:51 +02:00
bool param_init_forced = true ;
2013-07-31 20:58:27 +04:00
bool updated = false ;
2013-07-16 10:05:51 +02:00
2013-07-15 22:15:15 +02:00
/* Subscribe to safety topic */
int safety_sub = orb_subscribe ( ORB_ID ( safety ) ) ;
memset ( & safety , 0 , sizeof ( safety ) ) ;
2013-08-15 09:52:22 +02:00
safety . safety_switch_available = false ;
safety . safety_off = false ;
2013-07-15 22:15:15 +02:00
2014-12-19 22:26:31 +00:00
/* Subscribe to geofence result topic */
int geofence_result_sub = orb_subscribe ( ORB_ID ( geofence_result ) ) ;
struct geofence_result_s geofence_result ;
memset ( & geofence_result , 0 , sizeof ( geofence_result ) ) ;
2012-09-21 12:55:41 +02:00
/* Subscribe to manual control data */
int sp_man_sub = orb_subscribe ( ORB_ID ( manual_control_setpoint ) ) ;
memset ( & sp_man , 0 , sizeof ( sp_man ) ) ;
/* Subscribe to offboard control data */
2015-02-13 23:19:43 +01:00
int offboard_control_mode_sub = orb_subscribe ( ORB_ID ( offboard_control_mode ) ) ;
memset ( & offboard_control_mode , 0 , sizeof ( offboard_control_mode ) ) ;
2012-08-04 15:12:36 -07:00
2015-01-06 12:25:18 +01:00
/* Subscribe to land detector */
int land_detector_sub = orb_subscribe ( ORB_ID ( vehicle_land_detected ) ) ;
2016-04-29 12:34:28 +02:00
land_detector . landed = true ;
2015-01-06 12:25:18 +01:00
2012-10-15 08:52:41 +02:00
/* Subscribe to command topic */
int cmd_sub = orb_subscribe ( ORB_ID ( vehicle_command ) ) ;
2012-12-13 10:23:02 +01:00
/* Subscribe to parameters changed topic */
int param_changed_sub = orb_subscribe ( ORB_ID ( parameter_update ) ) ;
2013-07-16 10:05:51 +02:00
/* Subscribe to battery topic */
2013-01-01 13:30:24 +01:00
int battery_sub = orb_subscribe ( ORB_ID ( battery_status ) ) ;
memset ( & battery , 0 , sizeof ( battery ) ) ;
2013-07-16 09:24:21 +02:00
/* Subscribe to subsystem info topic */
int subsys_sub = orb_subscribe ( ORB_ID ( subsystem_info ) ) ;
struct subsystem_info_s info ;
memset ( & info , 0 , sizeof ( info ) ) ;
2014-05-25 08:22:54 +02:00
/* Subscribe to system power */
int system_power_sub = orb_subscribe ( ORB_ID ( system_power ) ) ;
2014-07-19 14:12:33 +02:00
/* Subscribe to actuator controls (outputs) */
int actuator_controls_sub = orb_subscribe ( ORB_ID_VEHICLE_ATTITUDE_CONTROLS ) ;
2014-12-02 10:47:07 +01:00
/* Subscribe to vtol vehicle status topic */
int vtol_vehicle_status_sub = orb_subscribe ( ORB_ID ( vtol_vehicle_status ) ) ;
2015-08-07 16:43:16 +02:00
//struct vtol_vehicle_status_s vtol_status;
2014-12-02 10:47:07 +01:00
memset ( & vtol_status , 0 , sizeof ( vtol_status ) ) ;
vtol_status . vtol_in_rw_mode = true ; //default for vtol is rotary wing
2017-11-29 21:18:48 +11:00
/* subscribe to estimator status topic */
int estimator_status_sub = orb_subscribe ( ORB_ID ( estimator_status ) ) ;
struct estimator_status_s estimator_status ;
/* class variables used to check for navigation failure after takeoff */
hrt_abstime time_at_takeoff = 0 ; // last time we were on the ground
hrt_abstime time_last_innov_pass = 0 ; // last time velocity innovations passed
bool nav_test_passed = false ; // true if the post takeoff navigation test has passed
bool nav_test_failed = false ; // true if the post takeoff navigation test has failed
2016-02-26 18:14:03 -08:00
int cpuload_sub = orb_subscribe ( ORB_ID ( cpuload ) ) ;
memset ( & cpuload , 0 , sizeof ( cpuload ) ) ;
2014-12-02 10:47:07 +01:00
2016-02-26 18:14:03 -08:00
control_status_leds ( & status , & armed , true , & battery , & cpuload ) ;
2013-08-29 16:45:33 +02:00
2013-02-18 16:45:59 +01:00
thread_running = true ;
2012-08-04 15:12:36 -07:00
2015-04-22 09:53:09 +02:00
/* update vehicle status to find out vehicle type (required for preflight checks) */
2017-10-24 22:04:07 +02:00
int32_t system_type ;
param_get ( _param_sys_type , & system_type ) ; // get system type
status . system_type = ( uint8_t ) system_type ;
2015-04-22 09:53:09 +02:00
status . is_rotary_wing = is_rotary_wing ( & status ) | | is_vtol ( & status ) ;
2016-11-24 12:18:08 +01:00
status . is_vtol = is_vtol ( & status ) ;
2015-04-22 09:53:09 +02:00
2017-07-08 14:01:51 -04:00
commander_boot_timestamp = hrt_absolute_time ( ) ;
2018-01-28 11:22:51 -05:00
// initially set to failed
2018-03-15 01:15:35 -04:00
_last_lpos_fail_time_us = commander_boot_timestamp ;
_last_gpos_fail_time_us = commander_boot_timestamp ;
_last_lvel_fail_time_us = commander_boot_timestamp ;
2018-01-28 11:22:51 -05:00
2015-04-27 13:29:36 +02:00
// Run preflight check
2015-09-04 19:57:44 +02:00
int32_t rc_in_off = 0 ;
2017-04-17 00:18:39 -04:00
2015-10-06 11:48:35 +02:00
param_get ( _param_rc_in_off , & rc_in_off ) ;
2017-04-17 00:18:39 -04:00
2016-11-28 11:29:58 +01:00
int32_t arm_switch_is_button = 0 ;
param_get ( _param_arm_switch_is_button , & arm_switch_is_button ) ;
2017-04-17 00:18:39 -04:00
int32_t arm_without_gps_param = 0 ;
param_get ( _param_arm_without_gps , & arm_without_gps_param ) ;
2017-08-11 01:27:08 -04:00
arm_requirements = ( arm_without_gps_param = = 1 ) ? ARM_REQ_NONE : ARM_REQ_GPS_BIT ;
2017-04-17 00:18:39 -04:00
int32_t arm_mission_required_param = 0 ;
param_get ( _param_arm_mission_required , & arm_mission_required_param ) ;
2017-05-08 18:30:47 -07:00
arm_requirements | = ( arm_mission_required_param & ( ARM_REQ_MISSION_BIT | ARM_REQ_ARM_AUTH_BIT ) ) ;
2017-04-17 00:18:39 -04:00
2015-10-06 11:48:35 +02:00
status . rc_input_mode = rc_in_off ;
2015-03-08 14:50:35 +01:00
2016-05-20 09:59:23 -06:00
// user adjustable duration required to assert arm/disarm via throttle/rudder stick
int32_t rc_arm_hyst = 100 ;
param_get ( _param_rc_arm_hyst , & rc_arm_hyst ) ;
rc_arm_hyst * = COMMANDER_MONITORING_LOOPSPERMSEC ;
2016-12-15 10:38:59 -08:00
int32_t datalink_loss_act = 0 ;
int32_t rc_loss_act = 0 ;
2014-07-20 17:53:04 +02:00
int32_t datalink_loss_timeout = 10 ;
2017-12-21 16:43:34 +01:00
int32_t highlatencydatalink_loss_timeout = 120 ;
2014-09-05 12:06:05 +02:00
float rc_loss_timeout = 0.5 ;
2014-07-24 08:57:58 +02:00
int32_t datalink_regain_timeout = 0 ;
2017-12-21 16:43:34 +01:00
int32_t highlatencydatalink_regain_timeout = 0 ;
2015-11-26 17:45:20 +01:00
float offboard_loss_timeout = 0.0f ;
int32_t offboard_loss_act = 0 ;
int32_t offboard_loss_rc_act = 0 ;
2017-05-06 09:57:17 +10:00
int32_t posctl_nav_loss_act = 0 ;
2014-09-05 08:59:00 +02:00
2015-11-02 11:51:50 +01:00
int32_t geofence_action = 0 ;
2015-09-27 19:49:01 -04:00
2017-10-16 16:53:52 +02:00
int32_t flight_uuid = 0 ;
2017-04-12 02:22:46 +02:00
/* RC override auto modes */
int32_t rc_override = 0 ;
2017-12-31 19:58:20 +01:00
int32_t takeoff_complete_act = 0 ;
2017-04-12 02:22:46 +02:00
2014-09-05 08:59:00 +02:00
/* Thresholds for engine failure detection */
2017-10-24 22:05:09 +02:00
float ef_throttle_thres = 1.0f ;
float ef_current2throttle_thres = 0.0f ;
float ef_time_thres = 1000.0f ;
2014-09-30 13:40:03 +02:00
uint64_t timestamp_engine_healthy = 0 ; /**< absolute time when engine was healty */
2014-06-18 19:01:41 +02:00
2015-10-26 09:22:34 +01:00
int32_t disarm_when_landed = 0 ;
2016-04-23 00:30:50 +02:00
int32_t low_bat_action = 0 ;
2015-10-26 09:22:34 +01:00
2014-05-27 21:56:32 +02:00
/* check which state machines for changes, clear "changed" flag */
bool main_state_changed = false ;
2014-06-17 13:19:50 +02:00
bool failsafe_old = false ;
2014-05-27 21:56:32 +02:00
2016-09-29 11:30:34 +02:00
bool have_taken_off_since_arming = false ;
2015-03-15 14:33:22 +01:00
/* initialize low priority thread */
pthread_attr_t commander_low_prio_attr ;
pthread_attr_init ( & commander_low_prio_attr ) ;
2016-09-07 22:05:38 +02:00
pthread_attr_setstacksize ( & commander_low_prio_attr , PX4_STACK_ADJUSTED ( 3000 ) ) ;
2015-03-15 14:33:22 +01:00
2016-01-18 23:16:31 -08:00
# ifndef __PX4_QURT
2016-02-16 21:11:03 +01:00
// This is not supported by QURT (yet).
2015-03-15 14:33:22 +01:00
struct sched_param param ;
( void ) pthread_attr_getschedparam ( & commander_low_prio_attr , & param ) ;
/* low priority */
param . sched_priority = SCHED_PRIORITY_DEFAULT - 50 ;
( void ) pthread_attr_setschedparam ( & commander_low_prio_attr , & param ) ;
2016-01-18 23:16:31 -08:00
# endif
2017-01-28 20:21:58 -05:00
pthread_create ( & commander_low_prio_thread , & commander_low_prio_attr , commander_low_prio_loop , nullptr ) ;
2015-03-15 14:33:22 +01:00
pthread_attr_destroy ( & commander_low_prio_attr ) ;
2017-09-26 12:25:02 -04:00
arm_auth_init ( & mavlink_log_pub , & status . system_id ) ;
2017-05-08 18:33:58 -07:00
2017-12-20 15:39:20 -05:00
while ( ! should_exit ( ) ) {
2012-08-04 15:12:36 -07:00
2018-02-18 18:35:43 -05:00
transition_result_t arming_ret = TRANSITION_NOT_CHANGED ;
2014-05-27 21:56:32 +02:00
2013-06-09 14:09:09 +02:00
/* update parameters */
2017-12-11 13:51:28 -05:00
bool params_updated = false ;
orb_check ( param_changed_sub , & params_updated ) ;
2013-06-09 14:09:09 +02:00
2017-12-11 13:51:28 -05:00
if ( params_updated | | param_init_forced ) {
2015-03-23 10:52:32 -07:00
2013-06-09 14:09:09 +02:00
/* parameters changed */
2015-03-23 10:52:32 -07:00
struct parameter_update_s param_changed ;
2013-06-09 14:09:09 +02:00
orb_copy ( ORB_ID ( parameter_update ) , param_changed_sub , & param_changed ) ;
2018-02-18 20:23:50 -05:00
updateParams ( ) ;
2013-06-09 14:09:09 +02:00
/* update parameters */
2013-07-15 22:15:15 +02:00
if ( ! armed . armed ) {
2017-10-24 22:04:07 +02:00
if ( param_get ( _param_sys_type , & system_type ) ! = OK ) {
PX4_ERR ( " failed getting new system type " ) ;
2018-04-12 01:09:56 -04:00
2017-10-24 22:04:07 +02:00
} else {
status . system_type = ( uint8_t ) system_type ;
2013-06-09 14:09:09 +02:00
}
/* disable manual override for all systems that rely on electronic stabilization */
2015-04-22 09:53:09 +02:00
if ( is_rotary_wing ( & status ) | | ( is_vtol ( & status ) & & vtol_status . vtol_in_rw_mode ) ) {
2013-07-28 23:12:16 +04:00
status . is_rotary_wing = true ;
2013-06-09 14:09:09 +02:00
} else {
2013-07-28 23:12:16 +04:00
status . is_rotary_wing = false ;
2013-06-09 14:09:09 +02:00
}
2014-12-18 14:46:31 +01:00
/* set vehicle_status.is_vtol flag */
2015-04-22 09:53:09 +02:00
status . is_vtol = is_vtol ( & status ) ;
2014-12-18 14:46:31 +01:00
2013-06-09 14:09:09 +02:00
/* check and update system / component ID */
2017-09-26 12:25:02 -04:00
int32_t sys_id = 0 ;
param_get ( _param_system_id , & sys_id ) ;
status . system_id = sys_id ;
int32_t comp_id = 0 ;
param_get ( _param_component_id , & comp_id ) ;
status . component_id = comp_id ;
2014-05-25 20:34:32 +02:00
2015-04-27 13:29:36 +02:00
get_circuit_breaker_params ( ) ;
2014-05-25 20:34:32 +02:00
2013-07-31 20:58:27 +04:00
status_changed = true ;
2013-06-09 14:09:09 +02:00
}
2014-05-11 13:36:51 +02:00
2014-12-18 14:46:31 +01:00
/* Safety parameters */
2016-12-15 10:38:59 -08:00
param_get ( _param_enable_datalink_loss , & datalink_loss_act ) ;
param_get ( _param_enable_rc_loss , & rc_loss_act ) ;
2014-07-20 17:53:04 +02:00
param_get ( _param_datalink_loss_timeout , & datalink_loss_timeout ) ;
2017-12-21 16:43:34 +01:00
param_get ( _param_highlatencydatalink_loss_timeout , & highlatencydatalink_loss_timeout ) ;
2014-09-05 12:06:05 +02:00
param_get ( _param_rc_loss_timeout , & rc_loss_timeout ) ;
2015-05-24 13:15:28 +02:00
param_get ( _param_rc_in_off , & rc_in_off ) ;
2015-05-25 16:34:42 +02:00
status . rc_input_mode = rc_in_off ;
2016-05-20 09:59:23 -06:00
param_get ( _param_rc_arm_hyst , & rc_arm_hyst ) ;
2017-02-04 21:05:28 +01:00
param_get ( _param_min_stick_change , & min_stick_change ) ;
2017-04-12 02:22:46 +02:00
param_get ( _param_rc_override , & rc_override ) ;
2017-02-04 21:05:28 +01:00
// percentage (* 0.01) needs to be doubled because RC total interval is 2, not 1
min_stick_change * = 0.02f ;
2016-05-20 09:59:23 -06:00
rc_arm_hyst * = COMMANDER_MONITORING_LOOPSPERMSEC ;
2014-07-24 08:57:58 +02:00
param_get ( _param_datalink_regain_timeout , & datalink_regain_timeout ) ;
2017-12-21 16:43:34 +01:00
param_get ( _param_highlatencydatalink_regain_timeout , & highlatencydatalink_regain_timeout ) ;
2014-09-05 08:59:00 +02:00
param_get ( _param_ef_throttle_thres , & ef_throttle_thres ) ;
param_get ( _param_ef_current2throttle_thres , & ef_current2throttle_thres ) ;
param_get ( _param_ef_time_thres , & ef_time_thres ) ;
2015-09-27 19:49:01 -04:00
param_get ( _param_geofence_action , & geofence_action ) ;
2015-10-26 09:22:34 +01:00
param_get ( _param_disarm_land , & disarm_when_landed ) ;
2017-10-16 16:53:52 +02:00
param_get ( _param_flight_uuid , & flight_uuid ) ;
2016-07-17 17:00:59 +01:00
2016-10-02 11:17:32 +02:00
// If we update parameters the first time
// make sure the hysteresis time gets set.
// After that it will be set in the main state
// machine based on the arming state.
if ( param_init_forced ) {
2017-12-20 15:39:20 -05:00
auto_disarm_hysteresis . set_hysteresis_time_from ( false , ( hrt_abstime ) disarm_when_landed * 1000000 ) ;
2016-10-02 11:17:32 +02:00
}
2016-04-23 00:30:50 +02:00
param_get ( _param_low_bat_act , & low_bat_action ) ;
2015-11-26 17:45:20 +01:00
param_get ( _param_offboard_loss_timeout , & offboard_loss_timeout ) ;
2016-06-08 13:21:17 +02:00
param_get ( _param_offboard_loss_act , & offboard_loss_act ) ;
param_get ( _param_offboard_loss_rc_act , & offboard_loss_rc_act ) ;
2016-11-28 11:29:58 +01:00
param_get ( _param_arm_switch_is_button , & arm_switch_is_button ) ;
2017-04-17 00:18:39 -04:00
param_get ( _param_arm_without_gps , & arm_without_gps_param ) ;
2017-08-11 01:27:08 -04:00
arm_requirements = ( arm_without_gps_param = = 1 ) ? ARM_REQ_NONE : ARM_REQ_GPS_BIT ;
2017-04-17 00:18:39 -04:00
param_get ( _param_arm_mission_required , & arm_mission_required_param ) ;
2017-05-08 18:30:47 -07:00
arm_requirements | = ( arm_mission_required_param & ( ARM_REQ_MISSION_BIT | ARM_REQ_ARM_AUTH_BIT ) ) ;
2014-12-18 14:46:31 +01:00
2016-03-04 11:47:33 +01:00
/* flight mode slots */
param_get ( _param_fmode_1 , & _flight_mode_slots [ 0 ] ) ;
param_get ( _param_fmode_2 , & _flight_mode_slots [ 1 ] ) ;
param_get ( _param_fmode_3 , & _flight_mode_slots [ 2 ] ) ;
param_get ( _param_fmode_4 , & _flight_mode_slots [ 3 ] ) ;
param_get ( _param_fmode_5 , & _flight_mode_slots [ 4 ] ) ;
param_get ( _param_fmode_6 , & _flight_mode_slots [ 5 ] ) ;
2017-05-06 09:57:17 +10:00
/* failsafe response to loss of navigation accuracy */
param_get ( _param_posctl_nav_loss_act , & posctl_nav_loss_act ) ;
2017-12-31 19:58:20 +01:00
param_get ( _param_takeoff_finished_action , & takeoff_complete_act ) ;
2016-10-02 11:17:32 +02:00
param_init_forced = false ;
2013-06-09 14:09:09 +02:00
}
2017-07-24 13:05:52 +02:00
/* handle power button state */
orb_check ( power_button_state_sub , & updated ) ;
if ( updated ) {
power_button_state_s button_state ;
orb_copy ( ORB_ID ( power_button_state ) , power_button_state_sub , & button_state ) ;
2018-04-12 01:09:56 -04:00
2017-07-24 13:05:52 +02:00
if ( button_state . event = = power_button_state_s : : PWR_BUTTON_STATE_REQUEST_SHUTDOWN ) {
px4_shutdown_request ( false , false ) ;
}
}
2013-07-31 20:58:27 +04:00
orb_check ( sp_man_sub , & updated ) ;
2013-01-11 07:42:09 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2012-09-26 21:30:03 +02:00
orb_copy ( ORB_ID ( manual_control_setpoint ) , sp_man_sub , & sp_man ) ;
}
2015-02-13 23:19:43 +01:00
orb_check ( offboard_control_mode_sub , & updated ) ;
2013-01-11 07:42:09 +01:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2015-02-13 23:19:43 +01:00
orb_copy ( ORB_ID ( offboard_control_mode ) , offboard_control_mode_sub , & offboard_control_mode ) ;
2012-09-26 21:30:03 +02:00
}
2012-12-19 11:34:51 +01:00
2015-02-13 23:19:43 +01:00
if ( offboard_control_mode . timestamp ! = 0 & &
offboard_control_mode . timestamp + OFFBOARD_TIMEOUT > hrt_absolute_time ( ) ) {
2016-02-26 10:20:52 +00:00
if ( status_flags . offboard_control_signal_lost ) {
status_flags . offboard_control_signal_lost = false ;
2015-11-26 17:45:20 +01:00
status_flags . offboard_control_loss_timeout = false ;
2014-06-21 12:24:37 +02:00
status_changed = true ;
}
2014-10-23 16:17:20 +02:00
2014-06-21 12:24:37 +02:00
} else {
2016-02-26 10:20:52 +00:00
if ( ! status_flags . offboard_control_signal_lost ) {
status_flags . offboard_control_signal_lost = true ;
2016-06-02 20:43:47 +02:00
status_changed = true ;
}
2015-11-26 17:45:20 +01:00
2016-06-02 20:43:47 +02:00
/* check timer if offboard was there but now lost */
if ( ! status_flags . offboard_control_loss_timeout & & offboard_control_mode . timestamp ! = 0 ) {
2015-11-26 17:45:20 +01:00
if ( offboard_loss_timeout < FLT_EPSILON ) {
/* execute loss action immediately */
status_flags . offboard_control_loss_timeout = true ;
} else {
/* wait for timeout if set */
status_flags . offboard_control_loss_timeout = offboard_control_mode . timestamp +
2018-04-12 01:09:56 -04:00
OFFBOARD_TIMEOUT + offboard_loss_timeout * 1e6 f < hrt_absolute_time ( ) ;
2016-06-02 20:43:47 +02:00
}
if ( status_flags . offboard_control_loss_timeout ) {
status_changed = true ;
2015-11-26 17:45:20 +01:00
}
2014-06-21 12:24:37 +02:00
}
}
2018-03-23 14:13:09 +01:00
// poll the telemetry status
2018-04-12 01:09:56 -04:00
poll_telemetry_status ( ) ;
2014-06-16 17:34:21 +02:00
2014-05-25 08:22:54 +02:00
orb_check ( system_power_sub , & updated ) ;
if ( updated ) {
2018-04-12 01:09:56 -04:00
system_power_s system_power = { } ;
2014-05-25 08:22:54 +02:00
orb_copy ( ORB_ID ( system_power ) , system_power_sub , & system_power ) ;
if ( hrt_elapsed_time ( & system_power . timestamp ) < 200000 ) {
if ( system_power . servo_valid & &
2014-10-23 16:17:20 +02:00
! system_power . brick_valid & &
! system_power . usb_connected ) {
2014-05-25 08:22:54 +02:00
/* flying only on servo rail, this is unsafe */
2016-02-25 17:00:39 +00:00
status_flags . condition_power_input_valid = false ;
2014-10-23 16:17:20 +02:00
2014-05-25 08:22:54 +02:00
} else {
2016-02-25 17:00:39 +00:00
status_flags . condition_power_input_valid = true ;
2014-05-25 08:22:54 +02:00
}
2014-06-30 14:33:56 +02:00
2015-11-04 18:23:19 +01:00
/* if the USB hardware connection went away, reboot */
2016-02-25 17:00:39 +00:00
if ( status_flags . usb_connected & & ! system_power . usb_connected ) {
2015-10-23 17:47:22 +02:00
/*
* apparently the USB cable went away but we are still powered ,
* so lets reset to a classic non - usb state .
*/
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " USB disconnected, rebooting. " )
2015-10-23 17:47:22 +02:00
usleep ( 400000 ) ;
2017-04-18 14:06:30 +02:00
px4_shutdown_request ( true , false ) ;
2015-10-23 17:47:22 +02:00
}
2014-05-25 08:22:54 +02:00
}
}
2013-06-25 13:15:38 +02:00
/* update safety topic */
2013-07-31 20:58:27 +04:00
orb_check ( safety_sub , & updated ) ;
2013-06-25 13:15:38 +02:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2015-01-15 11:09:31 +01:00
bool previous_safety_off = safety . safety_off ;
2018-04-12 01:09:56 -04:00
2018-01-17 09:51:49 -05:00
if ( orb_copy ( ORB_ID ( safety ) , safety_sub , & safety ) = = PX4_OK ) {
/* disarm if safety is now on and still armed */
if ( armed . armed & & ( status . hil_state = = vehicle_status_s : : HIL_STATE_OFF )
2018-04-12 01:09:56 -04:00
& & safety . safety_switch_available & & ! safety . safety_off ) {
2018-01-17 09:51:49 -05:00
2018-04-12 01:09:56 -04:00
if ( TRANSITION_CHANGED = = arming_state_transition ( & status , battery , safety , vehicle_status_s : : ARMING_STATE_STANDBY ,
& armed , true /* fRunPreArmChecks */ , & mavlink_log_pub ,
& status_flags , arm_requirements , hrt_elapsed_time ( & commander_boot_timestamp ) )
) {
2018-03-27 16:27:47 -04:00
status_changed = true ;
2018-01-17 09:51:49 -05:00
}
2014-02-17 22:45:54 +04:00
}
2015-01-15 11:09:31 +01:00
2018-01-17 09:51:49 -05:00
// Notify the user if the status of the safety switch changes
if ( safety . safety_switch_available & & previous_safety_off ! = safety . safety_off ) {
2015-01-15 11:09:31 +01:00
2018-01-17 09:51:49 -05:00
if ( safety . safety_off ) {
set_tune ( TONE_NOTIFY_POSITIVE_TUNE ) ;
2015-01-16 16:46:16 +01:00
2018-01-17 09:51:49 -05:00
} else {
tune_neutral ( true ) ;
}
2015-01-15 11:09:31 +01:00
2018-01-17 09:51:49 -05:00
status_changed = true ;
}
2015-01-15 11:09:31 +01:00
}
2013-06-25 13:15:38 +02:00
}
2014-12-02 10:47:07 +01:00
/* update vtol vehicle status*/
orb_check ( vtol_vehicle_status_sub , & updated ) ;
if ( updated ) {
/* vtol status changed */
orb_copy ( ORB_ID ( vtol_vehicle_status ) , vtol_vehicle_status_sub , & vtol_status ) ;
2014-12-31 16:25:15 +01:00
status . vtol_fw_permanent_stab = vtol_status . fw_permanent_stab ;
2015-01-16 16:46:16 +01:00
2015-08-10 16:24:57 +02:00
/* Make sure that this is only adjusted if vehicle really is of type vtol */
2015-04-22 09:53:09 +02:00
if ( is_vtol ( & status ) ) {
2017-03-08 20:45:28 +01:00
2017-12-31 16:11:57 +01:00
// Check if there has been any change while updating the flags
if ( status . is_rotary_wing ! = vtol_status . vtol_in_rw_mode ) {
status . is_rotary_wing = vtol_status . vtol_in_rw_mode ;
status_changed = true ;
}
if ( status . in_transition_mode ! = vtol_status . vtol_in_trans_mode ) {
status . in_transition_mode = vtol_status . vtol_in_trans_mode ;
status_changed = true ;
}
2016-01-28 10:23:23 +01:00
2017-12-31 16:11:57 +01:00
if ( status . in_transition_to_fw ! = vtol_status . in_transition_to_fw ) {
status . in_transition_to_fw = vtol_status . in_transition_to_fw ;
status_changed = true ;
}
if ( status_flags . vtol_transition_failure ! = vtol_status . vtol_transition_failsafe ) {
status_flags . vtol_transition_failure = vtol_status . vtol_transition_failsafe ;
status_changed = true ;
}
if ( armed . soft_stop ! = ! status . is_rotary_wing ) {
armed . soft_stop = ! status . is_rotary_wing ;
status_changed = true ;
}
}
2014-12-02 10:47:07 +01:00
}
2018-03-15 01:15:35 -04:00
_local_position_sub . update ( ) ;
_global_position_sub . update ( ) ;
2015-07-04 10:45:01 +02:00
2018-03-15 01:15:35 -04:00
// Check if quality checking of position accuracy and consistency is to be performed
const bool run_quality_checks = ! status_flags . circuit_breaker_engaged_posfailure_check ;
2017-05-06 20:57:28 +10:00
2017-11-29 21:18:48 +11:00
/* Check estimator status for signs of bad yaw induced post takeoff navigation failure
* for a short time interval after takeoff . Fixed wing vehicles can recover using GPS heading ,
2017-12-22 08:57:06 +11:00
* but rotary wing vehicles cannot so the position and velocity validity needs to be latched
2017-11-29 21:18:48 +11:00
* to false after failure to prevent flyaway crashes */
if ( run_quality_checks & & status . is_rotary_wing ) {
bool estimator_status_updated = false ;
orb_check ( estimator_status_sub , & estimator_status_updated ) ;
2018-04-12 01:09:56 -04:00
2017-11-29 21:18:48 +11:00
if ( estimator_status_updated ) {
orb_copy ( ORB_ID ( estimator_status ) , estimator_status_sub , & estimator_status ) ;
2018-04-12 01:09:56 -04:00
2017-12-04 13:15:50 +11:00
if ( status . arming_state = = vehicle_status_s : : ARMING_STATE_STANDBY ) {
// reset flags and timer
time_at_takeoff = hrt_absolute_time ( ) ;
nav_test_failed = false ;
nav_test_passed = false ;
2018-04-12 01:09:56 -04:00
2017-12-04 13:15:50 +11:00
} else if ( land_detector . landed ) {
// record time of takeoff
2017-11-29 21:18:48 +11:00
time_at_takeoff = hrt_absolute_time ( ) ;
2018-04-12 01:09:56 -04:00
2017-11-29 21:18:48 +11:00
} else {
// if nav status is unconfirmed, confirm yaw angle as passed after 30 seconds or achieving 5 m/s of speed
2018-03-15 01:15:35 -04:00
const bool sufficient_time = ( hrt_elapsed_time ( & time_at_takeoff ) > 30 * 1 _s ) ;
const vehicle_local_position_s & lpos = _local_position_sub . get ( ) ;
const bool sufficient_speed = ( lpos . vx * lpos . vx + lpos . vy * lpos . vy > 25.0f ) ;
2017-11-29 21:18:48 +11:00
bool innovation_pass = estimator_status . vel_test_ratio < 1.0f & & estimator_status . pos_test_ratio < 1.0f ;
2018-04-12 01:09:56 -04:00
2017-11-29 21:18:48 +11:00
if ( ! nav_test_failed ) {
if ( ! nav_test_passed ) {
// pass if sufficient time or speed
if ( sufficient_time | | sufficient_speed ) {
nav_test_passed = true ;
}
// record the last time the innovation check passed
if ( innovation_pass ) {
time_last_innov_pass = hrt_absolute_time ( ) ;
}
// if the innovation test has failed continuously, declare the nav as failed
2018-03-15 01:15:35 -04:00
if ( ( hrt_absolute_time ( ) - time_last_innov_pass ) > 1 _s ) {
2017-11-29 21:18:48 +11:00
nav_test_failed = true ;
2018-03-15 01:15:35 -04:00
status_flags . condition_local_position_valid = false ;
status_flags . condition_local_velocity_valid = false ;
status_flags . condition_global_position_valid = false ;
2017-11-29 21:18:48 +11:00
mavlink_log_emergency ( & mavlink_log_pub , " CRITICAL NAVIGATION FAILURE - CHECK SENSOR CALIBRATION " ) ;
}
}
}
}
}
}
2017-05-06 20:57:28 +10:00
/* run global position accuracy checks */
2018-03-15 01:15:35 -04:00
// Check if quality checking of position accuracy and consistency is to be performed
if ( run_quality_checks ) {
// use global position message to determine validity
const vehicle_global_position_s & global_position = _global_position_sub . get ( ) ;
check_posvel_validity ( true , global_position . eph , _eph_threshold . get ( ) , global_position . timestamp , & _last_gpos_fail_time_us , & _gpos_probation_time_us , & status_flags . condition_global_position_valid , & status_changed ) ;
2018-04-12 01:09:56 -04:00
2018-03-15 01:15:35 -04:00
// use local position message to determine validity
const vehicle_local_position_s & local_position = _local_position_sub . get ( ) ;
check_posvel_validity ( local_position . xy_valid , local_position . eph , _eph_threshold . get ( ) , local_position . timestamp , & _last_lpos_fail_time_us , & _lpos_probation_time_us , & status_flags . condition_local_position_valid , & status_changed ) ;
check_posvel_validity ( local_position . v_xy_valid , local_position . evh , _evh_threshold . get ( ) , local_position . timestamp , & _last_lvel_fail_time_us , & _lvel_probation_time_us , & status_flags . condition_local_velocity_valid , & status_changed ) ;
2012-12-13 10:23:02 +01:00
}
2018-03-15 01:15:35 -04:00
check_valid ( _local_position_sub . get ( ) . timestamp , _failsafe_pos_delay . get ( ) * sec_to_usec , _local_position_sub . get ( ) . z_valid , & ( status_flags . condition_local_altitude_valid ) , & status_changed ) ;
2013-08-27 23:08:00 +02:00
2015-01-06 12:25:18 +01:00
/* Update land detector */
orb_check ( land_detector_sub , & updated ) ;
2018-04-12 01:09:56 -04:00
2015-05-24 11:43:18 +02:00
if ( updated ) {
2015-01-06 12:25:18 +01:00
orb_copy ( ORB_ID ( vehicle_land_detected ) , land_detector_sub , & land_detector ) ;
2018-01-01 15:13:46 +01:00
// Only take actions if armed
if ( armed . armed ) {
if ( was_landed ! = land_detector . landed ) {
if ( land_detector . landed ) {
mavlink_and_console_log_info ( & mavlink_log_pub , " Landing detected " ) ;
2018-04-12 01:09:56 -04:00
2018-01-01 15:13:46 +01:00
} else {
mavlink_and_console_log_info ( & mavlink_log_pub , " Takeoff detected " ) ;
have_taken_off_since_arming = true ;
// Set all position and velocity test probation durations to takeoff value
// This is a larger value to give the vehicle time to complete a failsafe landing
// if faulty sensors cause loss of navigation shortly after takeoff.
2018-03-15 01:15:35 -04:00
_gpos_probation_time_us = _failsafe_pos_probation . get ( ) * sec_to_usec ;
_lpos_probation_time_us = _failsafe_pos_probation . get ( ) * sec_to_usec ;
_lvel_probation_time_us = _failsafe_pos_probation . get ( ) * sec_to_usec ;
2018-01-01 15:13:46 +01:00
}
2013-08-20 12:17:15 +02:00
}
2015-10-23 19:18:36 +02:00
2018-01-01 15:13:46 +01:00
if ( was_falling ! = land_detector . freefall ) {
if ( land_detector . freefall ) {
mavlink_and_console_log_info ( & mavlink_log_pub , " Freefall detected " ) ;
}
2016-04-23 15:47:59 +02:00
}
}
2016-06-05 14:34:46 +02:00
was_landed = land_detector . landed ;
was_falling = land_detector . freefall ;
2013-08-20 12:17:15 +02:00
}
2013-03-11 10:39:57 -07:00
2016-09-29 11:30:34 +02:00
/* Update hysteresis time. Use a time of factor 5 longer if we have not taken off yet. */
hrt_abstime timeout_time = disarm_when_landed * 1000000 ;
if ( ! have_taken_off_since_arming ) {
timeout_time * = 5 ;
}
auto_disarm_hysteresis . set_hysteresis_time_from ( false , timeout_time ) ;
2016-07-17 17:00:59 +01:00
// Check for auto-disarm
if ( armed . armed & & land_detector . landed & & disarm_when_landed > 0 ) {
auto_disarm_hysteresis . set_state_and_update ( true ) ;
2018-04-12 01:09:56 -04:00
2016-07-17 17:00:59 +01:00
} else {
auto_disarm_hysteresis . set_state_and_update ( false ) ;
}
if ( auto_disarm_hysteresis . get_state ( ) ) {
arm_disarm ( false , & mavlink_log_pub , " auto disarm on land " ) ;
}
2016-09-15 08:34:22 +02:00
if ( ! warning_action_on ) {
2016-04-23 00:30:50 +02:00
// store the last good main_state when not in an navigation
// hold state
main_state_before_rtl = internal_state . main_state ;
2016-09-07 16:54:58 +02:00
2016-09-15 08:34:22 +02:00
} else if ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_AUTO_RTL
2018-04-12 01:09:56 -04:00
& & internal_state . main_state ! = commander_state_s : : MAIN_STATE_AUTO_LOITER
& & internal_state . main_state ! = commander_state_s : : MAIN_STATE_AUTO_LAND ) {
2016-09-07 16:54:58 +02:00
// reset flag again when we switched out of it
2016-09-15 08:34:22 +02:00
warning_action_on = false ;
2016-04-23 00:30:50 +02:00
}
2016-02-26 18:14:03 -08:00
orb_check ( cpuload_sub , & updated ) ;
if ( updated ) {
orb_copy ( ORB_ID ( cpuload ) , cpuload_sub , & cpuload ) ;
}
2013-01-12 00:38:49 +01:00
/* update battery status */
2013-07-31 20:58:27 +04:00
orb_check ( battery_sub , & updated ) ;
2013-07-28 23:12:16 +04:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2013-01-01 13:30:24 +01:00
orb_copy ( ORB_ID ( battery_status ) , battery_sub , & battery ) ;
2014-01-26 11:52:33 +01:00
2016-09-07 07:26:06 +02:00
/* only consider battery voltage if system has been running 6s (usb most likely detected) and battery voltage is valid */
if ( hrt_absolute_time ( ) > commander_boot_timestamp + 6000000
2016-04-23 15:12:20 +02:00
& & battery . voltage_filtered_v > 2.0f * FLT_EPSILON ) {
2016-02-24 18:08:56 +00:00
/* if battery voltage is getting lower, warn using buzzer, etc. */
if ( battery . warning = = battery_status_s : : BATTERY_WARNING_LOW & &
2016-04-27 14:37:55 +02:00
! low_battery_voltage_actions_done ) {
2018-04-12 01:09:56 -04:00
2016-02-24 18:08:56 +00:00
low_battery_voltage_actions_done = true ;
2018-04-12 01:09:56 -04:00
2016-02-24 18:08:56 +00:00
if ( armed . armed ) {
mavlink_log_critical ( & mavlink_log_pub , " LOW BATTERY, RETURN TO LAND ADVISED " ) ;
2018-04-12 01:09:56 -04:00
2016-02-24 18:08:56 +00:00
} else {
mavlink_log_critical ( & mavlink_log_pub , " LOW BATTERY, TAKEOFF DISCOURAGED " ) ;
}
2014-07-19 14:12:33 +02:00
2017-02-03 11:39:50 +01:00
status_changed = true ;
2018-04-05 09:25:57 +02:00
} else if ( battery . warning = = battery_status_s : : BATTERY_WARNING_CRITICAL & &
2016-09-07 07:26:06 +02:00
! critical_battery_voltage_actions_done ) {
2018-04-12 01:09:56 -04:00
2016-02-24 18:08:56 +00:00
critical_battery_voltage_actions_done = true ;
2016-04-04 13:23:30 +02:00
if ( ! armed . armed ) {
2016-09-20 12:56:08 +02:00
mavlink_log_critical ( & mavlink_log_pub , " CRITICAL BATTERY, SHUT SYSTEM DOWN " ) ;
2016-09-06 16:55:59 +02:00
2016-02-24 18:08:56 +00:00
} else {
2017-02-22 22:04:04 +01:00
if ( low_bat_action = = 1 | | low_bat_action = = 3 ) {
2016-09-06 16:55:59 +02:00
// let us send the critical message even if already in RTL
2018-03-27 15:35:55 -04:00
if ( TRANSITION_DENIED ! = main_state_transition ( status , commander_state_s : : MAIN_STATE_AUTO_RTL , status_flags , & internal_state ) ) {
2016-09-15 08:34:22 +02:00
warning_action_on = true ;
2016-09-20 12:56:08 +02:00
mavlink_log_emergency ( & mavlink_log_pub , " CRITICAL BATTERY, RETURNING TO LAND " ) ;
2016-09-06 16:55:59 +02:00
} else {
2016-09-20 12:56:08 +02:00
mavlink_log_emergency ( & mavlink_log_pub , " CRITICAL BATTERY, RTL FAILED " ) ;
2016-04-23 00:30:50 +02:00
}
2016-09-06 16:55:59 +02:00
2016-04-27 14:37:55 +02:00
} else if ( low_bat_action = = 2 ) {
2018-03-27 15:35:55 -04:00
if ( TRANSITION_DENIED ! = main_state_transition ( status , commander_state_s : : MAIN_STATE_AUTO_LAND , status_flags , & internal_state ) ) {
2016-09-15 08:34:22 +02:00
warning_action_on = true ;
2016-09-20 12:56:08 +02:00
mavlink_log_emergency ( & mavlink_log_pub , " CRITICAL BATTERY, LANDING AT CURRENT POSITION " ) ;
2016-09-06 16:55:59 +02:00
2016-04-27 14:37:55 +02:00
} else {
2016-09-20 12:56:08 +02:00
mavlink_log_emergency ( & mavlink_log_pub , " CRITICAL BATTERY, LANDING FAILED " ) ;
2016-04-27 14:37:55 +02:00
}
2016-09-06 16:55:59 +02:00
2016-04-23 00:30:50 +02:00
} else {
2017-02-22 22:04:04 +01:00
mavlink_log_emergency ( & mavlink_log_pub , " CRITICAL BATTERY, RETURN TO LAUNCH ADVISED! " ) ;
}
}
status_changed = true ;
2018-04-05 09:25:57 +02:00
} else if ( battery . warning = = battery_status_s : : BATTERY_WARNING_EMERGENCY & &
2017-02-22 22:04:04 +01:00
! emergency_battery_voltage_actions_done ) {
2018-04-12 01:09:56 -04:00
2017-02-22 22:04:04 +01:00
emergency_battery_voltage_actions_done = true ;
if ( ! armed . armed ) {
mavlink_log_critical ( & mavlink_log_pub , " DANGEROUSLY LOW BATTERY, SHUT SYSTEM DOWN " ) ;
usleep ( 200000 ) ;
2017-04-18 14:06:30 +02:00
int ret_val = px4_shutdown_request ( false , false ) ;
2018-04-12 01:09:56 -04:00
2017-04-18 14:06:30 +02:00
if ( ret_val ) {
mavlink_log_critical ( & mavlink_log_pub , " SYSTEM DOES NOT SUPPORT SHUTDOWN " ) ;
2018-04-12 01:09:56 -04:00
2017-04-18 14:06:30 +02:00
} else {
2018-04-12 01:09:56 -04:00
while ( 1 ) { usleep ( 1 ) ; }
2017-04-18 14:06:30 +02:00
}
2017-02-22 22:04:04 +01:00
} else {
if ( low_bat_action = = 2 | | low_bat_action = = 3 ) {
2018-03-27 15:35:55 -04:00
if ( TRANSITION_CHANGED = = main_state_transition ( status , commander_state_s : : MAIN_STATE_AUTO_LAND , status_flags , & internal_state ) ) {
2017-02-22 22:04:04 +01:00
warning_action_on = true ;
mavlink_log_emergency ( & mavlink_log_pub , " DANGEROUS BATTERY LEVEL, LANDING IMMEDIATELY " ) ;
} else {
mavlink_log_emergency ( & mavlink_log_pub , " DANGEROUS BATTERY LEVEL, LANDING FAILED " ) ;
}
} else {
mavlink_log_emergency ( & mavlink_log_pub , " DANGEROUS BATTERY LEVEL, LANDING ADVISED! " ) ;
2016-04-23 00:30:50 +02:00
}
2016-02-24 18:08:56 +00:00
}
status_changed = true ;
}
/* End battery voltage check */
2013-08-15 17:27:29 +02:00
}
2012-09-05 18:05:11 +02:00
}
2012-08-04 15:12:36 -07:00
2013-07-16 09:24:21 +02:00
/* update subsystem */
2013-07-31 20:58:27 +04:00
orb_check ( subsys_sub , & updated ) ;
2013-07-28 23:12:16 +04:00
2013-07-31 20:58:27 +04:00
if ( updated ) {
2013-07-16 09:24:21 +02:00
orb_copy ( ORB_ID ( subsystem_info ) , subsys_sub , & info ) ;
2015-01-20 22:28:58 +01:00
//warnx("subsystem changed: %d\n", (int)info.subsystem_type);
2013-07-16 09:24:21 +02:00
/* mark / unmark as present */
if ( info . present ) {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_present | = info . subsystem_type ;
2013-07-16 09:24:21 +02:00
} else {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_present & = ~ info . subsystem_type ;
2013-07-16 09:24:21 +02:00
}
/* mark / unmark as enabled */
if ( info . enabled ) {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_enabled | = info . subsystem_type ;
2013-07-16 09:24:21 +02:00
} else {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_enabled & = ~ info . subsystem_type ;
2013-07-16 09:24:21 +02:00
}
/* mark / unmark as ok */
if ( info . ok ) {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_health | = info . subsystem_type ;
2013-07-16 09:24:21 +02:00
} else {
2013-07-28 23:12:16 +04:00
status . onboard_control_sensors_health & = ~ info . subsystem_type ;
2013-07-16 09:24:21 +02:00
}
2012-08-04 15:12:36 -07:00
2013-07-31 20:58:27 +04:00
status_changed = true ;
2013-02-16 13:40:09 -08:00
}
2012-08-04 15:12:36 -07:00
2013-02-18 16:35:34 -08:00
/* If in INIT state, try to proceed to STANDBY state */
2016-02-25 17:00:39 +00:00
if ( ! status_flags . condition_calibration_enabled & & status . arming_state = = vehicle_status_s : : ARMING_STATE_INIT ) {
2018-03-27 16:27:47 -04:00
arming_ret = arming_state_transition ( & status , battery , safety , vehicle_status_s : : ARMING_STATE_STANDBY , & armed ,
2018-04-12 01:09:56 -04:00
true /* fRunPreArmChecks */ , & mavlink_log_pub , & status_flags ,
arm_requirements , hrt_elapsed_time ( & commander_boot_timestamp ) ) ;
2014-05-27 21:56:32 +02:00
2017-10-16 16:51:14 +02:00
if ( arming_ret = = TRANSITION_DENIED ) {
2015-10-10 01:14:42 +02:00
/* do not complain if not allowed into standby */
arming_ret = TRANSITION_NOT_CHANGED ;
2014-05-27 21:56:32 +02:00
}
2013-02-18 16:35:34 -08:00
}
2014-07-01 09:34:26 +02:00
/* start mission result check */
2017-12-26 16:48:34 -05:00
const auto prev_mission_instance_count = _mission_result_sub . get ( ) . instance_count ;
2018-04-12 01:09:56 -04:00
2017-12-26 16:48:34 -05:00
if ( _mission_result_sub . update ( ) ) {
2018-04-12 01:09:56 -04:00
const mission_result_s & mission_result = _mission_result_sub . get ( ) ;
2017-04-17 00:18:39 -04:00
2017-12-26 16:48:34 -05:00
// if mission_result is valid for the current mission
const bool mission_result_ok = ( mission_result . timestamp > commander_boot_timestamp ) & & ( mission_result . instance_count > 0 ) ;
2017-12-19 11:02:34 -05:00
2017-12-26 16:48:34 -05:00
status_flags . condition_auto_mission_available = mission_result_ok & & mission_result . valid ;
2017-12-19 11:02:34 -05:00
2017-12-26 16:48:34 -05:00
if ( mission_result_ok ) {
2017-12-19 11:02:34 -05:00
2017-12-26 16:48:34 -05:00
if ( status . mission_failure ! = mission_result . failure ) {
status . mission_failure = mission_result . failure ;
status_changed = true ;
2016-02-13 01:08:07 +01:00
2017-12-26 16:48:34 -05:00
if ( status . mission_failure ) {
mavlink_log_critical ( & mavlink_log_pub , " Mission cannot be completed " ) ;
2017-12-19 11:02:34 -05:00
}
2017-12-26 16:48:34 -05:00
}
2017-12-19 11:02:34 -05:00
2017-12-26 16:48:34 -05:00
/* Only evaluate mission state if home is set */
if ( status_flags . condition_home_position_valid & &
2018-04-12 01:09:56 -04:00
( prev_mission_instance_count ! = mission_result . instance_count ) ) {
2017-12-19 11:02:34 -05:00
2017-12-26 16:48:34 -05:00
if ( ! status_flags . condition_auto_mission_available ) {
/* the mission is invalid */
tune_mission_fail ( true ) ;
2018-04-12 01:09:56 -04:00
2017-12-26 16:48:34 -05:00
} else if ( mission_result . warning ) {
/* the mission has a warning */
tune_mission_fail ( true ) ;
2018-04-12 01:09:56 -04:00
2017-12-26 16:48:34 -05:00
} else {
/* the mission is valid */
tune_mission_ok ( true ) ;
2017-12-19 11:02:34 -05:00
}
2016-02-13 01:08:07 +01:00
}
}
2014-12-19 22:26:31 +00:00
}
2014-08-24 17:45:15 +02:00
2014-12-19 22:26:31 +00:00
/* start geofence result check */
orb_check ( geofence_result_sub , & updated ) ;
2014-10-23 16:17:20 +02:00
2014-12-19 22:26:31 +00:00
if ( updated ) {
orb_copy ( ORB_ID ( geofence_result ) , geofence_result_sub , & geofence_result ) ;
2014-05-27 21:56:32 +02:00
}
2015-09-27 19:49:01 -04:00
// Geofence actions
if ( armed . armed & & ( geofence_result . geofence_action ! = geofence_result_s : : GF_ACTION_NONE ) ) {
static bool geofence_loiter_on = false ;
static bool geofence_rtl_on = false ;
// check for geofence violation
if ( geofence_result . geofence_violated ) {
static hrt_abstime last_geofence_violation = 0 ;
const hrt_abstime geofence_violation_action_interval = 10000000 ; // 10 seconds
2018-04-12 01:09:56 -04:00
2015-09-27 19:49:01 -04:00
if ( hrt_elapsed_time ( & last_geofence_violation ) > geofence_violation_action_interval ) {
last_geofence_violation = hrt_absolute_time ( ) ;
switch ( geofence_result . geofence_action ) {
case ( geofence_result_s : : GF_ACTION_NONE ) : {
// do nothing
break ;
}
case ( geofence_result_s : : GF_ACTION_WARN ) : {
// do nothing, mavlink critical messages are sent by navigator
break ;
}
case ( geofence_result_s : : GF_ACTION_LOITER ) : {
2018-03-27 15:35:55 -04:00
if ( TRANSITION_CHANGED = = main_state_transition ( status , commander_state_s : : MAIN_STATE_AUTO_LOITER , status_flags , & internal_state ) ) {
2015-09-27 19:49:01 -04:00
geofence_loiter_on = true ;
}
2018-04-12 01:09:56 -04:00
2015-09-27 19:49:01 -04:00
break ;
}
case ( geofence_result_s : : GF_ACTION_RTL ) : {
2018-03-27 15:35:55 -04:00
if ( TRANSITION_CHANGED = = main_state_transition ( status , commander_state_s : : MAIN_STATE_AUTO_RTL , status_flags , & internal_state ) ) {
2015-09-27 19:49:01 -04:00
geofence_rtl_on = true ;
}
2018-04-12 01:09:56 -04:00
2015-09-27 19:49:01 -04:00
break ;
}
case ( geofence_result_s : : GF_ACTION_TERMINATE ) : {
warnx ( " Flight termination because of geofence " ) ;
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " Geofence violation: flight termination " ) ;
2015-09-27 19:49:01 -04:00
armed . force_failsafe = true ;
status_changed = true ;
break ;
}
}
}
}
// reset if no longer in LOITER or if manually switched to LOITER
geofence_loiter_on = geofence_loiter_on
2018-04-12 01:09:56 -04:00
& & ( internal_state . main_state = = commander_state_s : : MAIN_STATE_AUTO_LOITER )
& & ( sp_man . loiter_switch = = manual_control_setpoint_s : : SWITCH_POS_OFF
| | sp_man . loiter_switch = = manual_control_setpoint_s : : SWITCH_POS_NONE ) ;
2015-09-27 19:49:01 -04:00
// reset if no longer in RTL or if manually switched to RTL
geofence_rtl_on = geofence_rtl_on
2018-04-12 01:09:56 -04:00
& & ( internal_state . main_state = = commander_state_s : : MAIN_STATE_AUTO_RTL )
& & ( sp_man . return_switch = = manual_control_setpoint_s : : SWITCH_POS_OFF
| | sp_man . return_switch = = manual_control_setpoint_s : : SWITCH_POS_NONE ) ;
2015-09-27 19:49:01 -04:00
2016-09-15 08:34:22 +02:00
warning_action_on = warning_action_on | | ( geofence_loiter_on | | geofence_rtl_on ) ;
2016-04-23 00:30:50 +02:00
}
2015-09-27 19:49:01 -04:00
2017-03-09 21:18:35 +01:00
// revert geofence failsafe transition if sticks are moved and we were previously in a manual mode
// but only if not in a low battery handling action
2017-04-12 02:22:46 +02:00
if ( rc_override ! = 0 & & ! critical_battery_voltage_actions_done & & ( warning_action_on & &
2018-04-12 01:09:56 -04:00
( main_state_before_rtl = = commander_state_s : : MAIN_STATE_MANUAL | |
main_state_before_rtl = = commander_state_s : : MAIN_STATE_ALTCTL | |
main_state_before_rtl = = commander_state_s : : MAIN_STATE_POSCTL | |
main_state_before_rtl = = commander_state_s : : MAIN_STATE_ACRO | |
main_state_before_rtl = = commander_state_s : : MAIN_STATE_RATTITUDE | |
main_state_before_rtl = = commander_state_s : : MAIN_STATE_STAB ) ) ) {
2016-04-23 00:30:50 +02:00
2017-02-04 21:05:28 +01:00
// transition to previous state if sticks are touched
2016-04-23 00:30:50 +02:00
if ( ( _last_sp_man . timestamp ! = sp_man . timestamp ) & &
2018-04-12 01:09:56 -04:00
( ( fabsf ( sp_man . x - _last_sp_man . x ) > min_stick_change ) | |
( fabsf ( sp_man . y - _last_sp_man . y ) > min_stick_change ) | |
( fabsf ( sp_man . z - _last_sp_man . z ) > min_stick_change ) | |
( fabsf ( sp_man . r - _last_sp_man . r ) > min_stick_change ) ) ) {
2016-04-23 00:30:50 +02:00
2017-02-04 21:05:28 +01:00
// revert to position control in any case
2018-03-27 15:35:55 -04:00
main_state_transition ( status , commander_state_s : : MAIN_STATE_POSCTL , status_flags , & internal_state ) ;
2017-03-09 21:18:35 +01:00
mavlink_log_critical ( & mavlink_log_pub , " Autopilot off, returned control to pilot " ) ;
2017-02-04 21:05:28 +01:00
}
}
// abort landing or auto or loiter if sticks are moved significantly
2017-03-09 21:18:35 +01:00
// but only if not in a low battery handling action
2017-04-12 02:22:46 +02:00
if ( rc_override ! = 0 & & ! critical_battery_voltage_actions_done & &
2018-04-12 01:09:56 -04:00
( internal_state . main_state = = commander_state_s : : MAIN_STATE_AUTO_LAND | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_AUTO_MISSION | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_AUTO_LOITER ) ) {
2017-02-04 21:05:28 +01:00
// transition to previous state if sticks are touched
2017-03-11 10:52:38 +01:00
2017-02-04 21:05:28 +01:00
if ( ( _last_sp_man . timestamp ! = sp_man . timestamp ) & &
2018-04-12 01:09:56 -04:00
( ( fabsf ( sp_man . x - _last_sp_man . x ) > min_stick_change ) | |
( fabsf ( sp_man . y - _last_sp_man . y ) > min_stick_change ) | |
( fabsf ( sp_man . z - _last_sp_man . z ) > min_stick_change ) | |
( fabsf ( sp_man . r - _last_sp_man . r ) > min_stick_change ) ) ) {
2017-02-04 21:05:28 +01:00
// revert to position control in any case
2018-03-27 15:35:55 -04:00
main_state_transition ( status , commander_state_s : : MAIN_STATE_POSCTL , status_flags , & internal_state ) ;
2017-02-04 21:05:28 +01:00
mavlink_log_critical ( & mavlink_log_pub , " Autopilot off, returned control to pilot " ) ;
2015-09-27 19:49:01 -04:00
}
}
/* Check for mission flight termination */
2017-12-26 16:48:34 -05:00
if ( armed . armed & & _mission_result_sub . get ( ) . flight_termination & &
2016-06-06 13:55:18 +02:00
! status_flags . circuit_breaker_flight_termination_disabled ) {
2016-08-22 01:03:58 -04:00
2014-12-19 22:26:31 +00:00
armed . force_failsafe = true ;
status_changed = true ;
static bool flight_termination_printed = false ;
if ( ! flight_termination_printed ) {
2016-09-20 12:56:08 +02:00
mavlink_log_critical ( & mavlink_log_pub , " Geofence violation: flight termination " ) ;
2014-12-19 22:26:31 +00:00
flight_termination_printed = true ;
}
if ( counter % ( 1000000 / COMMANDER_MONITORING_INTERVAL ) = = 0 ) {
2016-09-20 12:56:08 +02:00
mavlink_log_critical ( & mavlink_log_pub , " Flight termination active " ) ;
2014-12-19 22:26:31 +00:00
}
2015-09-27 19:49:01 -04:00
}
2014-12-19 22:26:31 +00:00
2014-06-16 17:34:21 +02:00
/* RC input check */
2016-02-26 11:01:12 +00:00
if ( ! status_flags . rc_input_blocked & & sp_man . timestamp ! = 0 & &
2015-09-04 14:57:23 +02:00
( hrt_absolute_time ( ) < sp_man . timestamp + ( uint64_t ) ( rc_loss_timeout * 1e6 f ) ) ) {
2014-01-26 14:12:27 +01:00
/* handle the case where RC signal was regained */
2016-02-26 11:01:12 +00:00
if ( ! status_flags . rc_signal_found_once ) {
status_flags . rc_signal_found_once = true ;
2014-01-26 14:12:27 +01:00
status_changed = true ;
2013-02-20 10:38:06 -08:00
2014-01-26 14:12:27 +01:00
} else {
if ( status . rc_signal_lost ) {
2016-03-15 18:25:02 +00:00
mavlink_log_info ( & mavlink_log_pub , " MANUAL CONTROL REGAINED after %llums " ,
2018-04-12 01:09:56 -04:00
( hrt_absolute_time ( ) - rc_signal_lost_timestamp ) / 1000 ) ;
2014-01-26 14:12:27 +01:00
status_changed = true ;
2013-02-20 10:38:06 -08:00
}
2014-01-26 14:12:27 +01:00
}
2012-12-27 18:27:08 +01:00
2014-01-26 14:12:27 +01:00
status . rc_signal_lost = false ;
2012-12-27 18:27:08 +01:00
2018-03-27 16:04:17 -04:00
const bool in_armed_state = ( status . arming_state = = vehicle_status_s : : ARMING_STATE_ARMED ) ;
2018-04-12 01:09:56 -04:00
const bool arm_button_pressed = arm_switch_is_button = = 1
& & sp_man . arm_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ;
2016-12-05 12:51:40 +01:00
2016-12-05 10:09:50 +01:00
/* DISARM
* check if left stick is in lower left position or arm button is pushed or arm switch has transition from arm to disarm
* and we are in MANUAL , Rattitude , or AUTO_READY mode or ( ASSIST mode and landed )
2016-04-23 18:27:18 +02:00
* do it only for rotary wings in manual mode or fixed wing if landed */
2016-12-05 12:51:40 +01:00
const bool stick_in_lower_left = sp_man . r < - STICK_ON_OFF_LIMIT & & sp_man . z < 0.1f ;
const bool arm_switch_to_disarm_transition = arm_switch_is_button = = 0 & &
2016-12-05 10:09:50 +01:00
_last_sp_man_arm_switch = = manual_control_setpoint_s : : SWITCH_POS_ON & &
sp_man . arm_switch = = manual_control_setpoint_s : : SWITCH_POS_OFF ;
2016-12-05 12:51:40 +01:00
if ( in_armed_state & &
2018-04-12 01:09:56 -04:00
status . rc_input_mode ! = vehicle_status_s : : RC_IN_MODE_OFF & &
( status . is_rotary_wing | | ( ! status . is_rotary_wing & & land_detector . landed ) ) & &
( stick_in_lower_left | | arm_button_pressed | | arm_switch_to_disarm_transition ) ) {
2016-12-05 12:51:40 +01:00
if ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_MANUAL & &
2018-04-12 01:09:56 -04:00
internal_state . main_state ! = commander_state_s : : MAIN_STATE_ACRO & &
internal_state . main_state ! = commander_state_s : : MAIN_STATE_STAB & &
internal_state . main_state ! = commander_state_s : : MAIN_STATE_RATTITUDE & &
! land_detector . landed ) {
2016-12-05 12:51:40 +01:00
print_reject_arm ( " NOT DISARMING: Not in manual mode or landed yet. " ) ;
} else if ( ( stick_off_counter = = rc_arm_hyst & & stick_on_counter < rc_arm_hyst ) | | arm_switch_to_disarm_transition ) {
2018-04-12 01:09:56 -04:00
arming_ret = arming_state_transition ( & status , battery , safety , vehicle_status_s : : ARMING_STATE_STANDBY , & armed ,
true /* fRunPreArmChecks */ ,
& mavlink_log_pub , & status_flags , arm_requirements , hrt_elapsed_time ( & commander_boot_timestamp ) ) ;
2013-07-22 21:48:21 +04:00
}
2018-04-12 01:09:56 -04:00
2016-12-01 17:59:00 +01:00
stick_off_counter + + ;
2018-04-12 01:09:56 -04:00
/* do not reset the counter when holding the arm button longer than needed */
2016-12-05 10:09:50 +01:00
} else if ( ! ( arm_switch_is_button = = 1 & & sp_man . arm_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) ) {
2014-01-26 14:12:27 +01:00
stick_off_counter = 0 ;
}
2013-09-14 08:55:45 +02:00
2016-12-05 10:09:50 +01:00
/* ARM
* check if left stick is in lower right position or arm button is pushed or arm switch has transition from disarm to arm
* and we ' re in MANUAL mode */
2016-12-05 12:51:40 +01:00
const bool stick_in_lower_right = ( sp_man . r > STICK_ON_OFF_LIMIT & & sp_man . z < 0.1f ) ;
const bool arm_switch_to_arm_transition = arm_switch_is_button = = 0 & &
2016-12-05 10:09:50 +01:00
_last_sp_man_arm_switch = = manual_control_setpoint_s : : SWITCH_POS_OFF & &
sp_man . arm_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ;
2016-12-05 12:51:40 +01:00
if ( ! in_armed_state & &
2018-04-12 01:09:56 -04:00
status . rc_input_mode ! = vehicle_status_s : : RC_IN_MODE_OFF & &
( stick_in_lower_right | | arm_button_pressed | | arm_switch_to_arm_transition ) ) {
2016-12-05 10:09:50 +01:00
if ( ( stick_on_counter = = rc_arm_hyst & & stick_off_counter < rc_arm_hyst ) | | arm_switch_to_arm_transition ) {
2013-09-14 08:55:45 +02:00
2014-06-26 12:14:49 +02:00
/* we check outside of the transition function here because the requirement
* for being in manual mode only applies to manual arming actions .
* the system can be armed in auto if armed via the GCS .
*/
2015-09-27 19:49:01 -04:00
2016-02-26 15:41:03 +00:00
if ( ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_MANUAL )
2018-04-12 01:09:56 -04:00
& & ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_ACRO )
& & ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_STAB )
& & ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_ALTCTL )
& & ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_POSCTL )
& & ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_RATTITUDE )
) {
2016-02-25 14:12:08 +01:00
print_reject_arm ( " NOT ARMING: Switch to a manual mode first. " ) ;
2014-10-23 16:17:20 +02:00
2016-02-25 17:00:39 +00:00
} else if ( ! status_flags . condition_home_position_valid & &
2018-04-12 01:09:56 -04:00
geofence_action = = geofence_result_s : : GF_ACTION_RTL ) {
2015-09-27 19:49:01 -04:00
print_reject_arm ( " NOT ARMING: Geofence RTL requires valid home " ) ;
2015-09-04 19:57:44 +02:00
} else if ( status . arming_state = = vehicle_status_s : : ARMING_STATE_STANDBY ) {
2018-04-12 01:09:56 -04:00
arming_ret = arming_state_transition ( & status , battery , safety , vehicle_status_s : : ARMING_STATE_ARMED , & armed ,
true /* fRunPreArmChecks */ ,
& mavlink_log_pub , & status_flags , arm_requirements , hrt_elapsed_time ( & commander_boot_timestamp ) ) ;
2014-10-23 16:17:20 +02:00
2017-10-16 16:51:14 +02:00
if ( arming_ret ! = TRANSITION_CHANGED ) {
2016-03-29 22:42:57 +02:00
usleep ( 100000 ) ;
2016-05-13 11:39:40 +02:00
print_reject_arm ( " NOT ARMING: Preflight checks failed " ) ;
2014-05-27 21:56:32 +02:00
}
2013-07-28 23:12:16 +04:00
}
}
2018-04-12 01:09:56 -04:00
2016-12-01 17:59:00 +01:00
stick_on_counter + + ;
2018-04-12 01:09:56 -04:00
/* do not reset the counter when holding the arm button longer than needed */
2016-12-05 10:09:50 +01:00
} else if ( ! ( arm_switch_is_button = = 1 & & sp_man . arm_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) ) {
2014-01-26 14:12:27 +01:00
stick_on_counter = 0 ;
}
2013-02-16 13:40:09 -08:00
2016-12-05 10:09:50 +01:00
_last_sp_man_arm_switch = sp_man . arm_switch ;
2017-10-16 16:51:14 +02:00
if ( arming_ret = = TRANSITION_DENIED ) {
2014-07-20 14:28:05 +02:00
/*
* the arming transition can be denied to a number of reasons :
* - pre - flight check failed ( sensors not ok or not calibrated )
* - safety not disabled
* - system not in manual mode
*/
2014-06-30 16:58:05 +02:00
tune_negative ( true ) ;
2014-01-26 14:12:27 +01:00
}
2014-01-26 11:52:33 +01:00
2014-01-26 14:12:27 +01:00
/* evaluate the main state machine according to mode switches */
2016-03-06 14:56:25 +01:00
bool first_rc_eval = ( _last_sp_man . timestamp = = 0 ) & & ( sp_man . timestamp > 0 ) ;
2018-03-15 01:15:35 -04:00
transition_result_t main_res = set_main_state ( status , & status_changed ) ;
2013-07-28 23:12:16 +04:00
2017-02-16 14:32:07 +01:00
/* store last position lock state */
_last_condition_global_position_valid = status_flags . condition_global_position_valid ;
2014-02-11 00:24:40 +01:00
/* play tune on mode change only if armed, blink LED always */
2016-03-06 14:56:25 +01:00
if ( main_res = = TRANSITION_CHANGED | | first_rc_eval ) {
2014-02-11 00:24:40 +01:00
tune_positive ( armed . armed ) ;
2014-05-27 21:56:32 +02:00
main_state_changed = true ;
2012-08-04 15:12:36 -07:00
2014-05-11 18:10:02 +02:00
} else if ( main_res = = TRANSITION_DENIED ) {
2014-01-26 14:12:27 +01:00
/* DENIED here indicates bug in the commander */
2017-06-15 07:15:03 +02:00
mavlink_log_critical ( & mavlink_log_pub , " Switching to this mode is currently not possible " ) ;
2014-01-26 14:12:27 +01:00
}
2012-08-08 18:47:46 +02:00
2015-12-18 21:21:51 -07:00
/* check throttle kill switch */
if ( sp_man . kill_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
/* set lockdown flag */
2016-12-15 10:38:59 -08:00
if ( ! armed . manual_lockdown ) {
2016-03-15 18:25:02 +00:00
mavlink_log_emergency ( & mavlink_log_pub , " MANUAL KILL SWITCH ENGAGED " ) ;
2018-04-06 11:00:11 +02:00
status_changed = true ;
armed . manual_lockdown = true ;
2016-03-06 12:48:28 +01:00
}
2018-04-12 01:09:56 -04:00
2016-01-17 13:44:18 +01:00
} else if ( sp_man . kill_switch = = manual_control_setpoint_s : : SWITCH_POS_OFF ) {
2016-12-15 10:38:59 -08:00
if ( armed . manual_lockdown ) {
2016-03-15 18:25:02 +00:00
mavlink_log_emergency ( & mavlink_log_pub , " MANUAL KILL SWITCH OFF " ) ;
2018-04-06 11:00:11 +02:00
status_changed = true ;
armed . manual_lockdown = false ;
2016-03-06 12:48:28 +01:00
}
2015-12-18 21:21:51 -07:00
}
2018-04-12 01:09:56 -04:00
2016-01-17 13:44:18 +01:00
/* no else case: do not change lockdown flag in unconfigured case */
2018-04-12 01:09:56 -04:00
2014-01-26 14:12:27 +01:00
} else {
2016-02-26 11:01:12 +00:00
if ( ! status_flags . rc_input_blocked & & ! status . rc_signal_lost ) {
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " MANUAL CONTROL LOST (at t=%llums) " , hrt_absolute_time ( ) / 1000 ) ;
2014-01-26 14:12:27 +01:00
status . rc_signal_lost = true ;
2016-02-26 11:01:12 +00:00
rc_signal_lost_timestamp = sp_man . timestamp ;
2014-01-26 14:12:27 +01:00
status_changed = true ;
2012-08-08 18:47:46 +02:00
}
2013-12-14 11:03:02 +01:00
}
2018-03-23 14:13:09 +01:00
// data link checks which update the status
data_link_checks ( highlatencydatalink_loss_timeout , highlatencydatalink_regain_timeout , datalink_loss_timeout , datalink_regain_timeout , & status_changed ) ;
2014-06-06 23:08:11 +02:00
2018-02-18 18:35:43 -05:00
// engine failure detection
// TODO: move out of commander
2016-02-24 18:08:56 +00:00
orb_check ( actuator_controls_sub , & updated ) ;
2014-10-23 16:17:20 +02:00
2016-02-24 18:08:56 +00:00
if ( updated ) {
/* Check engine failure
* only for fixed wing for now
*/
2016-02-25 17:00:39 +00:00
if ( ! status_flags . circuit_breaker_engaged_enginefailure_check & &
2018-02-18 18:35:43 -05:00
! status . is_rotary_wing & & ! status . is_vtol & & armed . armed ) {
actuator_controls_s actuator_controls = { } ;
orb_copy ( ORB_ID_VEHICLE_ATTITUDE_CONTROLS , actuator_controls_sub , & actuator_controls ) ;
const float throttle = actuator_controls . control [ actuator_controls_s : : INDEX_THROTTLE ] ;
const float current2throttle = battery . current_a / throttle ;
if ( ( ( throttle > ef_throttle_thres ) & & ( current2throttle < ef_current2throttle_thres ) )
2018-04-12 01:09:56 -04:00
| | status . engine_failure ) {
2018-02-18 18:35:43 -05:00
const float elapsed = hrt_elapsed_time ( & timestamp_engine_healthy ) / 1e6 f ;
/* potential failure, measure time */
if ( ( timestamp_engine_healthy > 0 ) & & ( elapsed > ef_time_thres )
2018-04-12 01:09:56 -04:00
& & ! status . engine_failure ) {
2018-02-18 18:35:43 -05:00
status . engine_failure = true ;
status_changed = true ;
PX4_ERR ( " Engine Failure " ) ;
}
2016-02-24 18:08:56 +00:00
}
} else {
/* no failure reset flag */
timestamp_engine_healthy = hrt_absolute_time ( ) ;
if ( status . engine_failure ) {
status . engine_failure = false ;
status_changed = true ;
}
2014-09-05 08:59:00 +02:00
}
}
2017-12-31 19:58:20 +01:00
/* Reset main state to loiter or auto-mission after takeoff is completed.
* Sometimes , the mission result topic is outdated and the mission is still signaled
* as finished even though we only just started with the takeoff . Therefore , we also
* check the timestamp of the mission_result topic . */
if ( internal_state . main_state = = commander_state_s : : MAIN_STATE_AUTO_TAKEOFF
2018-04-12 01:09:56 -04:00
& & ( _mission_result_sub . get ( ) . timestamp > internal_state . timestamp )
& & _mission_result_sub . get ( ) . finished ) {
2016-05-10 13:57:05 +02:00
2017-12-26 16:48:34 -05:00
const bool mission_available = ( _mission_result_sub . get ( ) . timestamp > commander_boot_timestamp )
2018-04-12 01:09:56 -04:00
& & ( _mission_result_sub . get ( ) . instance_count > 0 ) & & _mission_result_sub . get ( ) . valid ;
2015-12-17 00:11:50 +01:00
2017-12-31 19:58:20 +01:00
if ( ( takeoff_complete_act = = 1 ) & & mission_available ) {
2018-03-27 15:35:55 -04:00
main_state_transition ( status , commander_state_s : : MAIN_STATE_AUTO_MISSION , status_flags , & internal_state ) ;
2017-12-31 19:58:20 +01:00
} else {
2018-03-27 15:35:55 -04:00
main_state_transition ( status , commander_state_s : : MAIN_STATE_AUTO_LOITER , status_flags , & internal_state ) ;
2015-12-17 00:11:50 +01:00
}
}
2014-09-05 08:59:00 +02:00
2017-02-04 21:05:28 +01:00
/* check if we are disarmed and there is a better mode to wait in */
if ( ! armed . armed ) {
/* if there is no radio control but GPS lock the user might want to fly using
* just a tablet . Since the RC will force its mode switch setting on connecting
* we can as well just wait in a hold mode which enables tablet control .
*/
if ( status . rc_signal_lost & & ( internal_state . main_state = = commander_state_s : : MAIN_STATE_MANUAL )
2018-04-12 01:09:56 -04:00
& & status_flags . condition_home_position_valid ) {
2018-03-27 15:16:19 -04:00
2018-03-27 15:35:55 -04:00
main_state_transition ( status , commander_state_s : : MAIN_STATE_AUTO_LOITER , status_flags , & internal_state ) ;
2017-02-04 21:05:28 +01:00
}
}
2013-09-22 14:58:06 +02:00
/* handle commands last, as the system needs to be updated to handle them */
orb_check ( cmd_sub , & updated ) ;
if ( updated ) {
2017-07-27 17:08:22 -07:00
struct vehicle_command_s cmd ;
2013-09-22 14:58:06 +02:00
/* got command */
orb_copy ( ORB_ID ( vehicle_command ) , cmd_sub , & cmd ) ;
/* handle it */
2018-03-15 01:15:35 -04:00
if ( handle_command ( & status , cmd , & armed , & _home , & home_pub , & command_ack_pub , & status_changed ) ) {
2013-12-29 22:38:22 +04:00
status_changed = true ;
2014-05-11 13:36:51 +02:00
}
2013-07-31 20:58:27 +04:00
}
2013-06-25 13:15:38 +02:00
2016-06-06 11:19:26 +02:00
/* Check for failure combinations which lead to flight termination */
2016-06-06 13:55:18 +02:00
if ( armed . armed & &
! status_flags . circuit_breaker_flight_termination_disabled ) {
2016-06-06 11:19:26 +02:00
/* At this point the data link and the gps system have been checked
* If we are not in a manual ( RC stick controlled mode )
* and both failed we want to terminate the flight */
if ( internal_state . main_state ! = commander_state_s : : MAIN_STATE_MANUAL & &
internal_state . main_state ! = commander_state_s : : MAIN_STATE_ACRO & &
internal_state . main_state ! = commander_state_s : : MAIN_STATE_RATTITUDE & &
internal_state . main_state ! = commander_state_s : : MAIN_STATE_STAB & &
internal_state . main_state ! = commander_state_s : : MAIN_STATE_ALTCTL & &
internal_state . main_state ! = commander_state_s : : MAIN_STATE_POSCTL & &
2018-02-18 17:24:01 -05:00
status . data_link_lost ) {
2017-12-20 17:56:41 -05:00
2016-06-06 11:19:26 +02:00
armed . force_failsafe = true ;
status_changed = true ;
static bool flight_termination_printed = false ;
if ( ! flight_termination_printed ) {
2016-09-20 12:56:08 +02:00
mavlink_log_critical ( & mavlink_log_pub , " DL and GPS lost: flight termination " ) ;
2016-06-06 11:19:26 +02:00
flight_termination_printed = true ;
}
if ( counter % ( 1000000 / COMMANDER_MONITORING_INTERVAL ) = = 0 ) {
mavlink_log_critical ( & mavlink_log_pub , " DL and GPS lost: flight termination " ) ;
}
}
/* At this point the rc signal and the gps system have been checked
* If we are in manual ( controlled with RC ) :
* if both failed we want to terminate the flight */
if ( ( internal_state . main_state = = commander_state_s : : MAIN_STATE_ACRO | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_RATTITUDE | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_MANUAL | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_STAB | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_ALTCTL | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_POSCTL ) & &
2018-02-18 17:24:01 -05:00
status . rc_signal_lost ) {
2017-12-20 17:55:26 -05:00
2016-06-06 11:19:26 +02:00
armed . force_failsafe = true ;
status_changed = true ;
static bool flight_termination_printed = false ;
if ( ! flight_termination_printed ) {
warnx ( " Flight termination because of RC signal loss and GPS failure " ) ;
flight_termination_printed = true ;
}
if ( counter % ( 1000000 / COMMANDER_MONITORING_INTERVAL ) = = 0 ) {
mavlink_log_critical ( & mavlink_log_pub , " RC and GPS lost: flight termination " ) ;
}
}
}
2014-08-22 21:40:58 +02:00
2015-06-11 12:22:47 +02:00
/* Get current timestamp */
2015-01-16 15:51:57 +01:00
const hrt_abstime now = hrt_absolute_time ( ) ;
2013-08-17 12:37:41 +02:00
2018-03-25 13:44:09 -04:00
// automatically set or update home position
2017-12-18 22:11:12 -05:00
if ( ! _home . manual_home ) {
2018-03-15 01:15:35 -04:00
const vehicle_local_position_s & local_position = _local_position_sub . get ( ) ;
2017-12-18 22:11:12 -05:00
if ( armed . armed ) {
if ( ( ! was_armed | | ( was_landed & & ! land_detector . landed ) ) & &
2018-04-12 01:09:56 -04:00
( now > commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL ) ) {
2015-01-16 16:43:11 +01:00
2017-12-18 22:11:12 -05:00
/* update home position on arming if at least 500 ms from commander start spent to avoid setting home on in-air restart */
2018-03-15 01:15:35 -04:00
set_home_position ( home_pub , _home , false ) ;
2017-12-18 22:11:12 -05:00
}
2018-04-12 01:09:56 -04:00
2017-12-18 22:11:12 -05:00
} else {
if ( status_flags . condition_home_position_valid ) {
if ( land_detector . landed & & local_position . xy_valid & & local_position . z_valid ) {
/* distance from home */
float home_dist_xy = - 1.0f ;
float home_dist_z = - 1.0f ;
2018-03-25 13:44:09 -04:00
mavlink_wpm_distance_to_point_local ( _home . x , _home . y , _home . z ,
2018-03-15 01:15:35 -04:00
local_position . x , local_position . y , local_position . z ,
& home_dist_xy , & home_dist_z ) ;
2017-12-18 22:11:12 -05:00
2018-03-25 13:44:09 -04:00
if ( ( home_dist_xy > local_position . eph * 2 ) | | ( home_dist_z > local_position . epv * 2 ) ) {
2017-12-18 22:11:12 -05:00
/* update when disarmed, landed and moved away from current home position */
2018-03-15 01:15:35 -04:00
set_home_position ( home_pub , _home , false ) ;
2017-12-18 22:11:12 -05:00
}
}
2018-04-12 01:09:56 -04:00
2017-12-18 22:11:12 -05:00
} else {
/* First time home position update - but only if disarmed */
2018-03-15 01:15:35 -04:00
set_home_position ( home_pub , _home , false ) ;
2017-12-18 22:11:12 -05:00
}
}
2017-12-19 01:03:31 +01:00
2017-12-18 22:11:12 -05:00
/* Set home position altitude to EKF origin height if home is not set and the EKF has a global origin.
* This allows home atitude to be used in the calculation of height above takeoff location when GPS
* use has commenced after takeoff . */
if ( ! _home . valid_alt & & local_position . z_global ) {
2018-03-15 01:15:35 -04:00
set_home_position ( home_pub , _home , true ) ;
2017-12-06 07:34:30 +11:00
2017-12-18 22:11:12 -05:00
}
2017-12-06 07:34:30 +11:00
}
2017-10-16 16:51:14 +02:00
// check for arming state change
if ( was_armed ! = armed . armed ) {
2014-01-25 23:37:26 +01:00
status_changed = true ;
2017-10-16 16:53:52 +02:00
if ( ! armed . armed ) { // increase the flight uuid upon disarming
+ + flight_uuid ;
// no need for param notification: the only user is mavlink which reads the param upon request
param_set_no_notification ( _param_flight_uuid , & flight_uuid ) ;
}
2014-01-25 23:37:26 +01:00
}
2014-05-11 13:36:51 +02:00
2017-10-16 16:51:14 +02:00
was_armed = armed . armed ;
2014-06-16 17:34:21 +02:00
/* now set navigation state according to failsafe and main state */
2016-02-26 15:41:03 +00:00
bool nav_state_changed = set_nav_state ( & status ,
2018-04-12 01:09:56 -04:00
& armed ,
& internal_state ,
& mavlink_log_pub ,
( link_loss_actions_t ) datalink_loss_act ,
_mission_result_sub . get ( ) . finished ,
_mission_result_sub . get ( ) . stay_in_failsafe ,
status_flags ,
land_detector . landed ,
( link_loss_actions_t ) rc_loss_act ,
offboard_loss_act ,
offboard_loss_rc_act ,
posctl_nav_loss_act ) ;
if ( status . failsafe ! = failsafe_old ) {
2013-10-07 22:16:57 +02:00
status_changed = true ;
2015-01-16 16:46:16 +01:00
2014-11-10 21:38:46 +10:00
if ( status . failsafe ) {
2017-04-09 12:22:50 +02:00
mavlink_log_info ( & mavlink_log_pub , " Failsafe mode enabled " ) ;
2015-01-16 16:46:16 +01:00
2014-11-10 21:38:46 +10:00
} else {
2017-04-09 12:22:50 +02:00
mavlink_log_info ( & mavlink_log_pub , " Failsafe mode disabled " ) ;
2014-11-10 21:38:46 +10:00
}
2015-01-16 16:46:16 +01:00
2014-06-17 13:19:50 +02:00
failsafe_old = status . failsafe ;
}
2015-06-08 15:19:41 +02:00
// TODO handle mode changes by commands
if ( main_state_changed | | nav_state_changed ) {
2014-06-17 13:19:50 +02:00
status_changed = true ;
2015-06-08 15:19:41 +02:00
main_state_changed = false ;
2013-07-31 20:58:27 +04:00
}
2013-03-26 10:44:49 -07:00
2018-01-17 10:06:58 -05:00
/* publish states (armed, control_mode, vehicle_status, commander_state, vehicle_status_flags) at 1 Hz or immediately when changed */
if ( hrt_elapsed_time ( & control_mode . timestamp ) > = 1000000 | | status_changed ) {
2014-01-27 20:49:17 +01:00
set_control_mode ( ) ;
2015-01-16 15:51:57 +01:00
control_mode . timestamp = now ;
2014-01-27 20:49:17 +01:00
orb_publish ( ORB_ID ( vehicle_control_mode ) , control_mode_pub , & control_mode ) ;
2015-01-16 15:51:57 +01:00
status . timestamp = now ;
2013-07-28 23:12:16 +04:00
orb_publish ( ORB_ID ( vehicle_status ) , status_pub , & status ) ;
2014-01-27 20:49:17 +01:00
2015-01-16 15:51:57 +01:00
armed . timestamp = now ;
2015-07-22 12:42:50 +02:00
/* set prearmed state if safety is off, or safety is not present and 5 seconds passed */
if ( safety . safety_switch_available ) {
/* safety is off, go into prearmed */
armed . prearmed = safety . safety_off ;
2018-04-12 01:09:56 -04:00
2015-07-22 12:42:50 +02:00
} else {
/* safety is not present, go into prearmed
* ( all output drivers should be started / unlocked last in the boot process
* when the rest of the system is fully initialized )
*/
armed . prearmed = ( hrt_elapsed_time ( & commander_boot_timestamp ) > 5 * 1000 * 1000 ) ;
}
2018-04-12 01:09:56 -04:00
2013-08-18 12:42:24 +02:00
orb_publish ( ORB_ID ( actuator_armed ) , armed_pub , & armed ) ;
2017-12-20 20:04:30 -05:00
/* publish internal state for logging purposes */
if ( commander_state_pub ! = nullptr ) {
orb_publish ( ORB_ID ( commander_state ) , commander_state_pub , & internal_state ) ;
} else {
commander_state_pub = orb_advertise ( ORB_ID ( commander_state ) , & internal_state ) ;
}
/* publish vehicle_status_flags */
2018-01-27 16:23:40 -05:00
status_flags . timestamp = hrt_absolute_time ( ) ;
if ( vehicle_status_flags_pub ! = nullptr ) {
orb_publish ( ORB_ID ( vehicle_status_flags ) , vehicle_status_flags_pub , & status_flags ) ;
2018-04-12 01:09:56 -04:00
2018-01-27 16:23:40 -05:00
} else {
vehicle_status_flags_pub = orb_advertise ( ORB_ID ( vehicle_status_flags ) , & status_flags ) ;
}
2012-08-16 15:49:56 +02:00
}
2013-07-31 20:58:27 +04:00
/* play arming and battery warning tunes */
2014-10-23 16:17:20 +02:00
if ( ! arm_tune_played & & armed . armed & & ( ! safety . safety_switch_available | | ( safety . safety_switch_available
& & safety . safety_off ) ) ) {
2013-07-31 20:58:27 +04:00
/* play tune when armed */
2014-02-11 00:24:40 +01:00
set_tune ( TONE_ARMING_WARNING_TUNE ) ;
2014-02-11 18:24:20 +01:00
arm_tune_played = true ;
2013-07-28 23:12:16 +04:00
2016-04-27 14:37:55 +02:00
} else if ( ! status_flags . usb_connected & &
( status . hil_state ! = vehicle_status_s : : HIL_STATE_ON ) & &
2016-02-24 18:08:56 +00:00
( battery . warning = = battery_status_s : : BATTERY_WARNING_CRITICAL ) ) {
2013-07-31 20:58:27 +04:00
/* play tune on battery critical */
2014-02-11 00:24:40 +01:00
set_tune ( TONE_BATTERY_WARNING_FAST_TUNE ) ;
2013-07-28 23:12:16 +04:00
2015-05-30 19:06:05 -07:00
} else if ( ( status . hil_state ! = vehicle_status_s : : HIL_STATE_ON ) & &
2016-02-24 18:08:56 +00:00
( battery . warning = = battery_status_s : : BATTERY_WARNING_LOW ) ) {
2016-12-15 10:38:59 -08:00
/* play tune on battery warning */
2014-02-11 09:13:51 +01:00
set_tune ( TONE_BATTERY_WARNING_SLOW_TUNE ) ;
2013-07-28 23:12:16 +04:00
2016-12-15 10:38:59 -08:00
} else if ( status . failsafe ) {
tune_failsafe ( true ) ;
2018-04-12 01:09:56 -04:00
2014-02-11 18:24:20 +01:00
} else {
2014-02-11 00:24:40 +01:00
set_tune ( TONE_STOP_TUNE ) ;
2013-06-25 13:15:38 +02:00
}
2016-02-12 21:39:50 -08:00
2013-06-25 13:15:38 +02:00
/* reset arm_tune_played when disarmed */
2014-02-11 18:24:20 +01:00
if ( ! armed . armed | | ( safety . safety_switch_available & & ! safety . safety_off ) ) {
2015-01-15 11:09:31 +01:00
//Notify the user that it is safe to approach the vehicle
2015-01-16 16:46:16 +01:00
if ( arm_tune_played ) {
2015-01-15 11:09:31 +01:00
tune_neutral ( true ) ;
}
2013-06-25 13:15:38 +02:00
arm_tune_played = false ;
}
2016-02-12 21:39:50 -08:00
2015-11-10 19:33:14 +05:30
/* play sensor failure tunes if we already waited for hotplug sensors to come up and failed */
2018-03-29 23:14:34 -04:00
status_flags . condition_system_hotplug_timeout = ( hrt_elapsed_time ( & commander_boot_timestamp ) > HOTPLUG_SENS_TIMEOUT ) ;
2016-02-12 21:39:50 -08:00
2018-04-12 01:09:56 -04:00
if ( ! sensor_fail_tune_played & & ( ! status_flags . condition_system_sensors_initialized
& & status_flags . condition_system_hotplug_timeout ) ) {
2015-11-10 19:33:14 +05:30
set_tune_override ( TONE_GPS_WARNING_TUNE ) ;
sensor_fail_tune_played = true ;
status_changed = true ;
}
2016-02-12 21:39:50 -08:00
2012-08-04 15:12:36 -07:00
counter + + ;
2013-08-16 18:05:59 +02:00
2013-09-19 19:58:41 +02:00
int blink_state = blink_msg_state ( ) ;
2013-10-21 20:07:47 +02:00
2013-09-19 19:58:41 +02:00
if ( blink_state > 0 ) {
/* blinking LED message, don't touch LEDs */
if ( blink_state = = 2 ) {
/* blinking LED message completed, restore normal state */
2016-02-26 18:14:03 -08:00
control_status_leds ( & status , & armed , true , & battery , & cpuload ) ;
2013-09-19 19:58:41 +02:00
}
2013-10-21 20:07:47 +02:00
2013-09-19 19:58:41 +02:00
} else {
/* normal state */
2016-02-26 18:14:03 -08:00
control_status_leds ( & status , & armed , status_changed , & battery , & cpuload ) ;
2013-09-19 19:58:41 +02:00
}
status_changed = false ;
2013-08-16 18:05:59 +02:00
2016-09-29 11:30:34 +02:00
if ( ! armed . armed ) {
/* Reset the flag if disarmed. */
have_taken_off_since_arming = false ;
}
2017-12-11 13:51:28 -05:00
arm_auth_update ( now , params_updated | | param_init_forced ) ;
2017-05-08 18:33:58 -07:00
2012-08-04 15:12:36 -07:00
usleep ( COMMANDER_MONITORING_INTERVAL ) ;
}
2017-12-20 15:39:20 -05:00
thread_should_exit = true ;
2012-08-04 15:12:36 -07:00
/* wait for threads to complete */
2017-12-20 15:39:20 -05:00
int ret = pthread_join ( commander_low_prio_thread , nullptr ) ;
2013-09-14 08:55:45 +02:00
2013-09-08 20:05:15 +02:00
if ( ret ) {
2013-10-21 20:07:47 +02:00
warn ( " join failed: %d " , ret ) ;
2013-09-08 20:05:15 +02:00
}
2017-02-24 10:16:54 +01:00
rgbled_set_color_and_mode ( led_control_s : : COLOR_WHITE , led_control_s : : MODE_OFF ) ;
2012-08-04 15:12:36 -07:00
/* close fds */
led_deinit ( ) ;
buzzer_deinit ( ) ;
2015-07-01 11:05:45 -07:00
px4_close ( sp_man_sub ) ;
px4_close ( offboard_control_mode_sub ) ;
px4_close ( safety_sub ) ;
px4_close ( cmd_sub ) ;
px4_close ( subsys_sub ) ;
px4_close ( param_changed_sub ) ;
px4_close ( battery_sub ) ;
2016-02-26 10:21:33 +00:00
px4_close ( land_detector_sub ) ;
2017-12-22 08:57:06 +11:00
px4_close ( estimator_status_sub ) ;
2012-08-24 00:01:23 +02:00
2012-08-20 23:52:13 +02:00
thread_running = false ;
2012-08-04 15:12:36 -07:00
}
2013-03-25 14:53:54 -07:00
2015-04-27 13:29:36 +02:00
void
get_circuit_breaker_params ( )
{
2016-02-25 17:00:39 +00:00
status_flags . circuit_breaker_engaged_power_check = circuit_breaker_enabled ( " CBRK_SUPPLY_CHK " , CBRK_SUPPLY_CHK_KEY ) ;
2016-06-14 15:09:07 -04:00
status_flags . circuit_breaker_engaged_usb_check = circuit_breaker_enabled ( " CBRK_USB_CHK " , CBRK_USB_CHK_KEY ) ;
2016-02-25 17:00:39 +00:00
status_flags . circuit_breaker_engaged_airspd_check = circuit_breaker_enabled ( " CBRK_AIRSPD_CHK " , CBRK_AIRSPD_CHK_KEY ) ;
status_flags . circuit_breaker_engaged_enginefailure_check = circuit_breaker_enabled ( " CBRK_ENGINEFAIL " , CBRK_ENGINEFAIL_KEY ) ;
status_flags . circuit_breaker_engaged_gpsfailure_check = circuit_breaker_enabled ( " CBRK_GPSFAIL " , CBRK_GPSFAIL_KEY ) ;
2016-06-06 13:55:18 +02:00
status_flags . circuit_breaker_flight_termination_disabled = circuit_breaker_enabled ( " CBRK_FLIGHTTERM " , CBRK_FLIGHTTERM_KEY ) ;
2017-03-08 11:03:27 +11:00
status_flags . circuit_breaker_engaged_posfailure_check = circuit_breaker_enabled ( " CBRK_VELPOSERR " , CBRK_VELPOSERR_KEY ) ;
2015-04-27 13:29:36 +02:00
}
2013-08-19 09:53:00 +02:00
void
2018-03-27 15:16:19 -04:00
Commander : : check_valid ( const hrt_abstime & timestamp , const hrt_abstime & timeout , const bool valid_in , bool * valid_out , bool * changed )
2013-08-19 09:53:00 +02:00
{
hrt_abstime t = hrt_absolute_time ( ) ;
bool valid_new = ( t < timestamp + timeout & & t > timeout & & valid_in ) ;
if ( * valid_out ! = valid_new ) {
* valid_out = valid_new ;
* changed = true ;
}
}
2016-05-06 11:10:16 +02:00
void
2016-09-09 14:17:44 +02:00
control_status_leds ( vehicle_status_s * status_local , const actuator_armed_s * actuator_armed ,
2018-04-12 01:09:56 -04:00
bool changed , battery_status_s * battery_local , const cpuload_s * cpuload_local )
2013-07-31 20:58:27 +04:00
{
2016-09-09 14:17:44 +02:00
static hrt_abstime overload_start = 0 ;
bool overload = ( cpuload_local - > load > 0.80f ) | | ( cpuload_local - > ram_usage > 0.98f ) ;
if ( overload_start = = 0 & & overload ) {
overload_start = hrt_absolute_time ( ) ;
2018-04-12 01:09:56 -04:00
2016-09-09 14:17:44 +02:00
} else if ( ! overload ) {
overload_start = 0 ;
}
2016-08-29 23:35:56 +02:00
2013-09-19 19:58:41 +02:00
/* driving rgbled */
2016-09-09 14:17:44 +02:00
if ( changed | | last_overload ! = overload ) {
2017-02-24 10:16:54 +01:00
uint8_t led_mode = led_control_s : : MODE_OFF ;
2017-03-30 16:59:03 +08:00
uint8_t led_color = led_control_s : : COLOR_WHITE ;
2013-09-19 19:58:41 +02:00
bool set_normal_color = false ;
2016-02-12 21:39:50 -08:00
2016-09-09 14:17:44 +02:00
int overload_warn_delay = ( status_local - > arming_state = = vehicle_status_s : : ARMING_STATE_ARMED ) ? 1000 : 250000 ;
2013-09-19 19:58:41 +02:00
/* set mode */
2016-09-09 14:17:44 +02:00
if ( overload & & ( ( hrt_absolute_time ( ) - overload_start ) > overload_warn_delay ) ) {
2017-02-24 10:16:54 +01:00
led_mode = led_control_s : : MODE_BLINK_FAST ;
led_color = led_control_s : : COLOR_PURPLE ;
2016-08-29 23:35:56 +02:00
} else if ( status_local - > arming_state = = vehicle_status_s : : ARMING_STATE_ARMED ) {
2017-03-30 16:59:03 +08:00
led_mode = led_control_s : : MODE_ON ;
2013-09-19 19:58:41 +02:00
set_normal_color = true ;
2018-03-29 23:14:34 -04:00
} else if ( ! status_flags . condition_system_sensors_initialized & & status_flags . condition_system_hotplug_timeout ) {
2017-02-24 10:16:54 +01:00
led_mode = led_control_s : : MODE_BLINK_FAST ;
led_color = led_control_s : : COLOR_RED ;
2013-09-19 19:58:41 +02:00
2015-01-28 07:58:42 +01:00
} else if ( status_local - > arming_state = = vehicle_status_s : : ARMING_STATE_STANDBY ) {
2017-02-24 10:16:54 +01:00
led_mode = led_control_s : : MODE_BREATHE ;
2013-09-19 19:58:41 +02:00
set_normal_color = true ;
2016-02-12 21:39:50 -08:00
2018-03-29 23:14:34 -04:00
} else if ( ! status_flags . condition_system_sensors_initialized & & ! status_flags . condition_system_hotplug_timeout ) {
2017-02-24 10:16:54 +01:00
led_mode = led_control_s : : MODE_BREATHE ;
2015-11-10 19:33:14 +05:30
set_normal_color = true ;
2017-03-30 16:59:03 +08:00
} else if ( status_local - > arming_state = = vehicle_status_s : : ARMING_STATE_INIT ) {
2017-02-24 10:16:54 +01:00
// if in init status it should not be in the error state
led_mode = led_control_s : : MODE_OFF ;
2017-03-30 16:59:03 +08:00
2013-09-19 19:58:41 +02:00
} else { // STANDBY_ERROR and other states
2017-02-24 10:16:54 +01:00
led_mode = led_control_s : : MODE_BLINK_NORMAL ;
led_color = led_control_s : : COLOR_RED ;
2013-09-19 19:58:41 +02:00
}
if ( set_normal_color ) {
/* set color */
2016-02-26 15:41:03 +00:00
if ( status . failsafe ) {
2017-02-24 10:16:54 +01:00
led_color = led_control_s : : COLOR_PURPLE ;
2016-05-06 11:11:29 +02:00
} else if ( battery_local - > warning = = battery_status_s : : BATTERY_WARNING_LOW ) {
2017-02-24 10:16:54 +01:00
led_color = led_control_s : : COLOR_AMBER ;
2018-04-12 01:09:56 -04:00
2016-05-06 11:11:29 +02:00
} else if ( battery_local - > warning = = battery_status_s : : BATTERY_WARNING_CRITICAL ) {
2017-02-24 10:16:54 +01:00
led_color = led_control_s : : COLOR_RED ;
2018-04-12 01:09:56 -04:00
2013-09-19 19:58:41 +02:00
} else {
2016-02-25 17:00:39 +00:00
if ( status_flags . condition_home_position_valid & & status_flags . condition_global_position_valid ) {
2017-02-24 10:16:54 +01:00
led_color = led_control_s : : COLOR_GREEN ;
2013-09-19 19:58:41 +02:00
} else {
2017-02-24 10:16:54 +01:00
led_color = led_control_s : : COLOR_BLUE ;
2013-09-19 19:58:41 +02:00
}
}
}
2018-04-12 01:09:56 -04:00
2017-02-24 10:16:54 +01:00
if ( led_mode ! = led_control_s : : MODE_OFF ) {
rgbled_set_color_and_mode ( led_color , led_mode ) ;
}
2013-09-19 19:58:41 +02:00
}
2016-09-09 14:17:44 +02:00
last_overload = overload ;
2017-09-20 13:47:45 +08:00
# if !defined(CONFIG_ARCH_LEDS) && defined(BOARD_HAS_CONTROL_STATUS_LEDS)
2013-08-27 23:08:00 +02:00
2013-08-16 18:05:59 +02:00
/* this runs at around 20Hz, full cycle is 16 ticks = 10/16Hz */
2013-11-01 09:05:28 +01:00
if ( actuator_armed - > armed ) {
2016-12-15 10:38:59 -08:00
if ( status . failsafe ) {
led_off ( LED_BLUE ) ;
2018-04-12 01:09:56 -04:00
2016-12-15 10:38:59 -08:00
if ( leds_counter % 5 = = 0 ) {
led_toggle ( LED_GREEN ) ;
}
2018-04-12 01:09:56 -04:00
2016-12-15 10:38:59 -08:00
} else {
led_off ( LED_GREEN ) ;
2017-02-03 11:39:50 +01:00
2016-12-15 10:38:59 -08:00
/* armed, solid */
led_on ( LED_BLUE ) ;
}
2013-08-16 18:05:59 +02:00
2013-11-01 09:05:28 +01:00
} else if ( actuator_armed - > ready_to_arm ) {
2016-12-15 10:38:59 -08:00
led_off ( LED_BLUE ) ;
2018-04-12 01:09:56 -04:00
2013-08-16 18:05:59 +02:00
/* ready to arm, blink at 1Hz */
2014-05-11 13:36:51 +02:00
if ( leds_counter % 20 = = 0 ) {
2016-12-15 10:38:59 -08:00
led_toggle ( LED_GREEN ) ;
2014-05-11 13:36:51 +02:00
}
2013-08-27 23:08:00 +02:00
2013-08-16 18:05:59 +02:00
} else {
2016-12-15 10:38:59 -08:00
led_off ( LED_BLUE ) ;
2018-04-12 01:09:56 -04:00
2013-08-16 18:05:59 +02:00
/* not ready to arm, blink at 10Hz */
2014-05-11 13:36:51 +02:00
if ( leds_counter % 2 = = 0 ) {
2016-12-15 10:38:59 -08:00
led_toggle ( LED_GREEN ) ;
2014-05-11 13:36:51 +02:00
}
2013-08-16 18:05:59 +02:00
}
2013-08-27 23:08:00 +02:00
2013-08-16 18:05:59 +02:00
# endif
2016-08-29 23:35:56 +02:00
/* give system warnings on error LED */
if ( overload ) {
2014-05-11 13:36:51 +02:00
if ( leds_counter % 2 = = 0 ) {
2013-08-16 18:05:59 +02:00
led_toggle ( LED_AMBER ) ;
2014-05-11 13:36:51 +02:00
}
2013-08-27 23:08:00 +02:00
2013-08-16 18:05:59 +02:00
} else {
led_off ( LED_AMBER ) ;
2013-07-31 20:58:27 +04:00
}
leds_counter + + ;
}
2017-11-30 12:12:08 +00:00
transition_result_t
2018-03-15 01:15:35 -04:00
Commander : : set_main_state ( const vehicle_status_s & status_local , bool * changed )
2017-11-30 12:12:08 +00:00
{
if ( safety . override_available & & safety . override_enabled ) {
return set_main_state_override_on ( status_local , changed ) ;
2018-04-12 01:09:56 -04:00
2017-11-30 12:12:08 +00:00
} else {
2018-03-15 01:15:35 -04:00
return set_main_state_rc ( status_local , changed ) ;
2017-11-30 12:12:08 +00:00
}
}
transition_result_t
2018-03-15 01:15:35 -04:00
Commander : : set_main_state_override_on ( const vehicle_status_s & status_local , bool * changed )
2017-11-30 12:12:08 +00:00
{
2018-03-27 15:35:55 -04:00
transition_result_t res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2017-11-30 12:12:08 +00:00
* changed = ( res = = TRANSITION_CHANGED ) ;
return res ;
}
2013-07-28 23:12:16 +04:00
transition_result_t
2018-03-15 01:15:35 -04:00
Commander : : set_main_state_rc ( const vehicle_status_s & status_local , bool * changed )
2013-07-28 23:12:16 +04:00
{
2014-01-27 20:49:17 +01:00
/* set main state according to RC switches */
2013-07-28 23:12:16 +04:00
transition_result_t res = TRANSITION_DENIED ;
2017-02-03 11:39:50 +01:00
// Note: even if status_flags.offboard_control_set_by_command is set
2017-01-18 02:56:34 -08:00
// we want to allow rc mode change to take precidence. This is a safety
// feature, just in case offboard control goes crazy.
2014-07-16 09:38:57 +02:00
2015-10-07 16:35:51 +02:00
/* manual setpoint has not updated, do not re-evaluate it */
2017-02-16 14:32:07 +01:00
if ( ! ( ! _last_condition_global_position_valid & &
2018-04-12 01:09:56 -04:00
status_flags . condition_global_position_valid )
& & ( ( ( _last_sp_man . timestamp ! = 0 ) & & ( _last_sp_man . timestamp = = sp_man . timestamp ) ) | |
2016-05-09 23:01:06 +02:00
( ( _last_sp_man . offboard_switch = = sp_man . offboard_switch ) & &
( _last_sp_man . return_switch = = sp_man . return_switch ) & &
( _last_sp_man . mode_switch = = sp_man . mode_switch ) & &
( _last_sp_man . acro_switch = = sp_man . acro_switch ) & &
( _last_sp_man . rattitude_switch = = sp_man . rattitude_switch ) & &
( _last_sp_man . posctl_switch = = sp_man . posctl_switch ) & &
( _last_sp_man . loiter_switch = = sp_man . loiter_switch ) & &
2017-02-07 18:11:36 +01:00
( _last_sp_man . mode_slot = = sp_man . mode_slot ) & &
( _last_sp_man . stab_switch = = sp_man . stab_switch ) & &
( _last_sp_man . man_switch = = sp_man . man_switch ) ) ) ) {
2015-09-27 19:49:01 -04:00
2017-03-11 22:33:33 +01:00
// store the last manual control setpoint set by the pilot in a manual state
// if the system now later enters an autonomous state the pilot can move
// the sticks to break out of the autonomous state
if ( ! warning_action_on
2018-04-12 01:09:56 -04:00
& & ( internal_state . main_state = = commander_state_s : : MAIN_STATE_MANUAL | |
2017-03-11 22:33:33 +01:00
internal_state . main_state = = commander_state_s : : MAIN_STATE_ALTCTL | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_POSCTL | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_ACRO | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_RATTITUDE | |
internal_state . main_state = = commander_state_s : : MAIN_STATE_STAB ) ) {
2016-05-05 16:55:04 +02:00
2016-05-09 23:01:06 +02:00
_last_sp_man . timestamp = sp_man . timestamp ;
_last_sp_man . x = sp_man . x ;
_last_sp_man . y = sp_man . y ;
_last_sp_man . z = sp_man . z ;
_last_sp_man . r = sp_man . r ;
2016-05-05 16:55:04 +02:00
}
2015-10-07 16:35:51 +02:00
/* no timestamp change or no switch change -> nothing changed */
return TRANSITION_NOT_CHANGED ;
}
2016-05-09 23:01:06 +02:00
_last_sp_man = sp_man ;
2015-10-07 16:35:51 +02:00
2017-03-08 11:03:27 +11:00
// reset the position and velocity validity calculation to give the best change of being able to select
// the desired mode
2018-03-15 01:15:35 -04:00
reset_posvel_validity ( changed ) ;
2017-03-08 11:03:27 +11:00
2014-01-29 21:21:16 +01:00
/* offboard switch overrides main switch */
2016-05-09 23:01:06 +02:00
if ( sp_man . offboard_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_OFFBOARD , status_flags , & internal_state ) ;
2014-10-23 16:17:20 +02:00
2014-01-29 21:21:16 +01:00
if ( res = = TRANSITION_DENIED ) {
2018-03-27 15:16:19 -04:00
print_reject_mode ( " OFFBOARD " ) ;
2015-04-19 16:20:07 +02:00
/* mode rejected, continue to evaluate the main system mode */
2013-07-28 23:12:16 +04:00
2014-01-29 21:21:16 +01:00
} else {
2015-04-19 16:20:07 +02:00
/* changed successfully or already in this state */
2014-01-29 21:21:16 +01:00
return res ;
}
}
2013-07-28 23:12:16 +04:00
2015-04-19 16:20:07 +02:00
/* RTL switch overrides main switch */
2016-05-09 23:01:06 +02:00
if ( sp_man . return_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_AUTO_RTL , status_flags , & internal_state ) ;
2015-04-19 16:20:07 +02:00
if ( res = = TRANSITION_DENIED ) {
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO RTL " ) ;
2015-04-19 16:20:07 +02:00
/* fallback to LOITER if home position not set */
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_AUTO_LOITER , status_flags , & internal_state ) ;
2015-04-20 22:00:36 +02:00
}
2015-04-19 16:20:07 +02:00
2015-04-20 22:00:36 +02:00
if ( res ! = TRANSITION_DENIED ) {
/* changed successfully or already in this state */
2014-01-29 21:21:16 +01:00
return res ;
}
2015-04-20 22:00:36 +02:00
/* if we get here mode was rejected, continue to evaluate the main system mode */
2014-01-29 21:21:16 +01:00
}
2013-07-28 23:12:16 +04:00
2017-04-16 16:10:31 +02:00
/* Loiter switch overrides main switch */
if ( sp_man . loiter_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_AUTO_LOITER , status_flags , & internal_state ) ;
2017-04-16 16:10:31 +02:00
if ( res = = TRANSITION_DENIED ) {
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO HOLD " ) ;
2017-04-16 16:10:31 +02:00
} else {
return res ;
}
}
2016-03-04 11:47:33 +01:00
/* we know something has changed - check if we are in mode slot operation */
2016-05-09 23:01:06 +02:00
if ( sp_man . mode_slot ! = manual_control_setpoint_s : : MODE_SLOT_NONE ) {
2016-03-04 11:47:33 +01:00
2016-05-09 23:01:06 +02:00
if ( sp_man . mode_slot > = sizeof ( _flight_mode_slots ) / sizeof ( _flight_mode_slots [ 0 ] ) ) {
warnx ( " m slot overflow " ) ;
2016-03-04 11:47:33 +01:00
return TRANSITION_DENIED ;
}
2016-05-09 23:01:06 +02:00
int new_mode = _flight_mode_slots [ sp_man . mode_slot ] ;
2016-03-04 11:47:33 +01:00
if ( new_mode < 0 ) {
/* slot is unused */
res = TRANSITION_NOT_CHANGED ;
2016-03-06 12:34:31 +01:00
2016-03-04 11:47:33 +01:00
} else {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-03-06 12:34:31 +01:00
2016-04-26 09:11:35 +02:00
/* ensure that the mode selection does not get stuck here */
int maxcount = 5 ;
2016-03-06 12:34:31 +01:00
/* enable the use of break */
2016-04-18 18:29:07 +02:00
/* fallback strategies, give the user the closest mode to what he wanted */
2016-04-26 09:11:35 +02:00
while ( res = = TRANSITION_DENIED & & maxcount > 0 ) {
maxcount - - ;
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
if ( new_mode = = commander_state_s : : MAIN_STATE_AUTO_MISSION ) {
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
/* fall back to loiter */
new_mode = commander_state_s : : MAIN_STATE_AUTO_LOITER ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO MISSION " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-18 18:29:07 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
2016-03-06 12:34:31 +01:00
}
2016-04-18 18:29:07 +02:00
}
2016-03-06 12:34:31 +01:00
2016-04-26 09:11:35 +02:00
if ( new_mode = = commander_state_s : : MAIN_STATE_AUTO_RTL ) {
/* fall back to position control */
new_mode = commander_state_s : : MAIN_STATE_AUTO_LOITER ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO RTL " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-26 09:11:35 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
}
}
if ( new_mode = = commander_state_s : : MAIN_STATE_AUTO_LAND ) {
/* fall back to position control */
new_mode = commander_state_s : : MAIN_STATE_AUTO_LOITER ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO LAND " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-26 09:11:35 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
}
}
if ( new_mode = = commander_state_s : : MAIN_STATE_AUTO_TAKEOFF ) {
/* fall back to position control */
new_mode = commander_state_s : : MAIN_STATE_AUTO_LOITER ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO TAKEOFF " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-26 09:11:35 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
}
}
if ( new_mode = = commander_state_s : : MAIN_STATE_AUTO_FOLLOW_TARGET ) {
/* fall back to position control */
new_mode = commander_state_s : : MAIN_STATE_AUTO_LOITER ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO FOLLOW " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-26 09:11:35 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
}
}
2016-04-18 18:29:07 +02:00
if ( new_mode = = commander_state_s : : MAIN_STATE_AUTO_LOITER ) {
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
/* fall back to position control */
new_mode = commander_state_s : : MAIN_STATE_POSCTL ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO HOLD " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-18 18:29:07 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
2016-03-06 12:34:31 +01:00
}
2016-04-18 18:29:07 +02:00
}
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
if ( new_mode = = commander_state_s : : MAIN_STATE_POSCTL ) {
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
/* fall back to altitude control */
new_mode = commander_state_s : : MAIN_STATE_ALTCTL ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " POSITION CONTROL " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-18 18:29:07 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
2016-03-06 12:34:31 +01:00
}
2016-04-18 18:29:07 +02:00
}
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
if ( new_mode = = commander_state_s : : MAIN_STATE_ALTCTL ) {
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
/* fall back to stabilized */
new_mode = commander_state_s : : MAIN_STATE_STAB ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " ALTITUDE CONTROL " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-18 18:29:07 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
2016-03-06 12:34:31 +01:00
}
2016-04-18 18:29:07 +02:00
}
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
if ( new_mode = = commander_state_s : : MAIN_STATE_STAB ) {
2016-03-06 12:34:31 +01:00
2016-04-18 18:29:07 +02:00
/* fall back to manual */
new_mode = commander_state_s : : MAIN_STATE_MANUAL ;
2018-03-27 15:16:19 -04:00
print_reject_mode ( " STABILIZED " ) ;
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , new_mode , status_flags , & internal_state ) ;
2016-04-18 18:29:07 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ;
2016-03-06 12:34:31 +01:00
}
}
2016-04-18 18:29:07 +02:00
}
2016-03-04 11:47:33 +01:00
}
2016-03-15 18:25:02 +00:00
2016-03-04 11:47:33 +01:00
return res ;
}
2015-04-19 16:20:07 +02:00
/* offboard and RTL switches off or denied, check main mode switch */
2016-05-09 23:01:06 +02:00
switch ( sp_man . mode_switch ) {
2015-01-28 07:58:42 +01:00
case manual_control_setpoint_s : : SWITCH_POS_NONE :
2014-04-06 20:04:18 +04:00
res = TRANSITION_NOT_CHANGED ;
break ;
2015-01-28 07:58:42 +01:00
case manual_control_setpoint_s : : SWITCH_POS_OFF : // MANUAL
2017-02-07 18:11:36 +01:00
if ( sp_man . stab_switch = = manual_control_setpoint_s : : SWITCH_POS_NONE & &
2018-04-12 01:09:56 -04:00
sp_man . man_switch = = manual_control_setpoint_s : : SWITCH_POS_NONE ) {
2017-02-07 18:11:36 +01:00
/*
* Legacy mode :
* Acro switch being used as stabilized switch in FW .
*/
if ( sp_man . acro_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
/* manual mode is stabilized already for multirotors, so switch to acro
* for any non - manual mode
*/
if ( status . is_rotary_wing & & ! status . is_vtol ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_ACRO , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
} else if ( ! status . is_rotary_wing ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_STAB , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
} else {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
}
} else if ( sp_man . rattitude_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
/* Similar to acro transitions for multirotors. FW aircraft don't need a
* rattitude mode . */
if ( status . is_rotary_wing ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_RATTITUDE , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
} else {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_STAB , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
}
} else {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
}
2015-05-17 12:58:44 +02:00
2017-02-07 18:11:36 +01:00
} else {
/* New mode:
* - Acro is Acro
* - Manual is not default anymore when the manaul switch is assigned
2015-05-17 12:58:44 +02:00
*/
2017-02-07 18:11:36 +01:00
if ( sp_man . man_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
} else if ( sp_man . acro_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_ACRO , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
} else if ( sp_man . rattitude_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_RATTITUDE , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
} else if ( sp_man . stab_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_STAB , status_flags , & internal_state ) ;
2017-02-07 18:11:36 +01:00
} else if ( sp_man . man_switch = = manual_control_setpoint_s : : SWITCH_POS_NONE ) {
// default to MANUAL when no manual switch is set
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2014-05-20 00:03:00 +02:00
2015-10-20 20:38:42 -04:00
} else {
2017-02-07 18:11:36 +01:00
// default to STAB when the manual switch is assigned (but off)
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_STAB , status_flags , & internal_state ) ;
2015-10-20 20:38:42 -04:00
}
2014-01-31 22:44:05 +01:00
}
2014-10-23 16:17:20 +02:00
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break ;
2015-01-28 07:58:42 +01:00
case manual_control_setpoint_s : : SWITCH_POS_MIDDLE : // ASSIST
2016-05-09 23:01:06 +02:00
if ( sp_man . posctl_switch = = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_POSCTL , status_flags , & internal_state ) ;
2013-07-28 23:12:16 +04:00
2014-04-03 20:23:34 +04:00
if ( res ! = TRANSITION_DENIED ) {
2013-07-28 23:12:16 +04:00
break ; // changed successfully or already in this state
2014-04-03 20:23:34 +04:00
}
2013-07-28 23:12:16 +04:00
2018-03-27 15:16:19 -04:00
print_reject_mode ( " POSITION CONTROL " ) ;
2013-07-28 23:12:16 +04:00
}
2014-10-23 16:17:20 +02:00
// fallback to ALTCTL
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_ALTCTL , status_flags , & internal_state ) ;
2013-07-28 23:12:16 +04:00
2014-04-03 20:23:34 +04:00
if ( res ! = TRANSITION_DENIED ) {
2013-07-28 23:12:16 +04:00
break ; // changed successfully or already in this mode
2014-04-03 20:23:34 +04:00
}
2013-07-28 23:12:16 +04:00
2016-05-09 23:01:06 +02:00
if ( sp_man . posctl_switch ! = manual_control_setpoint_s : : SWITCH_POS_ON ) {
2018-03-27 15:16:19 -04:00
print_reject_mode ( " ALTITUDE CONTROL " ) ;
2014-04-03 20:23:34 +04:00
}
2013-07-31 20:58:27 +04:00
2014-06-25 17:56:11 +02:00
// fallback to MANUAL
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break ;
2015-01-28 07:58:42 +01:00
case manual_control_setpoint_s : : SWITCH_POS_ON : // AUTO
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_AUTO_MISSION , status_flags , & internal_state ) ;
2014-06-25 17:56:11 +02:00
2017-04-16 16:10:31 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ; // changed successfully or already in this state
}
2014-06-25 17:56:11 +02:00
2018-03-27 15:16:19 -04:00
print_reject_mode ( " AUTO MISSION " ) ;
2014-07-06 21:37:26 +02:00
2017-04-16 16:10:31 +02:00
// fallback to LOITER if home position not set
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_AUTO_LOITER , status_flags , & internal_state ) ;
2014-07-06 21:37:26 +02:00
2017-04-16 16:10:31 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ; // changed successfully or already in this state
2014-04-03 20:23:34 +04:00
}
2013-07-28 23:12:16 +04:00
2014-10-23 16:17:20 +02:00
// fallback to POSCTL
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_POSCTL , status_flags , & internal_state ) ;
2014-06-25 17:56:11 +02:00
2014-10-23 16:17:20 +02:00
if ( res ! = TRANSITION_DENIED ) {
break ; // changed successfully or already in this state
}
2014-06-25 17:56:11 +02:00
// fallback to ALTCTL
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_ALTCTL , status_flags , & internal_state ) ;
2013-07-28 23:12:16 +04:00
2014-04-03 20:23:34 +04:00
if ( res ! = TRANSITION_DENIED ) {
2013-07-28 23:12:16 +04:00
break ; // changed successfully or already in this state
2014-04-03 20:23:34 +04:00
}
2013-07-28 23:12:16 +04:00
2014-06-25 17:56:11 +02:00
// fallback to MANUAL
2018-03-27 15:35:55 -04:00
res = main_state_transition ( status_local , commander_state_s : : MAIN_STATE_MANUAL , status_flags , & internal_state ) ;
2013-07-28 23:12:16 +04:00
// TRANSITION_DENIED is not possible here
break ;
default :
break ;
}
return res ;
}
2017-03-08 11:03:27 +11:00
void
2018-03-15 01:15:35 -04:00
Commander : : reset_posvel_validity ( bool * changed )
2017-03-08 11:03:27 +11:00
{
// reset all the check probation times back to the minimum value
2018-03-15 01:15:35 -04:00
_gpos_probation_time_us = POSVEL_PROBATION_MIN ;
_lpos_probation_time_us = POSVEL_PROBATION_MIN ;
_lvel_probation_time_us = POSVEL_PROBATION_MIN ;
const vehicle_local_position_s & local_position = _local_position_sub . get ( ) ;
const vehicle_global_position_s & global_position = _global_position_sub . get ( ) ;
2017-03-08 11:03:27 +11:00
// recheck validity
2018-03-15 01:15:35 -04:00
check_posvel_validity ( true , global_position . eph , _eph_threshold . get ( ) , global_position . timestamp , & _last_gpos_fail_time_us , & _gpos_probation_time_us , & status_flags . condition_global_position_valid , changed ) ;
check_posvel_validity ( local_position . xy_valid , local_position . eph , _eph_threshold . get ( ) , local_position . timestamp , & _last_lpos_fail_time_us , & _lpos_probation_time_us , & status_flags . condition_local_position_valid , changed ) ;
check_posvel_validity ( local_position . v_xy_valid , local_position . evh , _evh_threshold . get ( ) , local_position . timestamp , & _last_lvel_fail_time_us , & _lvel_probation_time_us , & status_flags . condition_local_velocity_valid , changed ) ;
2017-03-08 11:03:27 +11:00
}
2018-01-28 11:22:51 -05:00
bool
2018-03-15 01:15:35 -04:00
Commander : : check_posvel_validity ( const bool data_valid , const float data_accuracy , const float required_accuracy , const hrt_abstime & data_timestamp_us , hrt_abstime * last_fail_time_us , hrt_abstime * probation_time_us , bool * valid_state , bool * validity_changed )
2017-04-22 09:07:28 +10:00
{
2018-01-28 11:22:51 -05:00
const bool was_valid = * valid_state ;
bool valid = was_valid ;
2017-04-22 09:07:28 +10:00
2018-01-28 11:22:51 -05:00
// constrain probation times
if ( land_detector . landed ) {
* probation_time_us = POSVEL_PROBATION_MIN ;
2017-04-22 09:07:28 +10:00
}
2018-03-15 01:15:35 -04:00
const bool data_stale = ( ( hrt_elapsed_time ( & data_timestamp_us ) > _failsafe_pos_delay . get ( ) * sec_to_usec ) | | ( data_timestamp_us = = 0 ) ) ;
2018-01-28 11:22:51 -05:00
const float req_accuracy = ( was_valid ? required_accuracy * 2.5f : required_accuracy ) ;
2017-04-22 09:07:28 +10:00
2018-01-28 11:22:51 -05:00
const bool level_check_pass = data_valid & & ! data_stale & & ( data_accuracy < req_accuracy ) ;
2017-04-22 09:07:28 +10:00
2018-01-28 11:22:51 -05:00
// Check accuracy with hysteresis in both test level and time
if ( level_check_pass ) {
if ( was_valid ) {
// still valid, continue to decrease probation time
const int64_t probation_time_new = * probation_time_us - hrt_elapsed_time ( last_fail_time_us ) ;
* probation_time_us = math : : constrain ( probation_time_new , POSVEL_PROBATION_MIN , POSVEL_PROBATION_MAX ) ;
2018-04-12 01:09:56 -04:00
2018-01-28 11:22:51 -05:00
} else {
// check if probation period has elapsed
if ( hrt_elapsed_time ( last_fail_time_us ) > * probation_time_us ) {
valid = true ;
}
}
2018-04-12 01:09:56 -04:00
2017-04-22 09:07:28 +10:00
} else {
2018-01-28 11:22:51 -05:00
// level check failed
if ( was_valid ) {
// FAILURE! no longer valid
valid = false ;
2018-04-12 01:09:56 -04:00
2018-01-28 11:22:51 -05:00
} else {
// failed again, increase probation time
2018-03-15 01:15:35 -04:00
const int64_t probation_time_new = * probation_time_us + hrt_elapsed_time ( last_fail_time_us ) * _failsafe_pos_gain . get ( ) ;
2018-01-28 11:22:51 -05:00
* probation_time_us = math : : constrain ( probation_time_new , POSVEL_PROBATION_MIN , POSVEL_PROBATION_MAX ) ;
2017-04-22 09:07:28 +10:00
}
2018-01-28 11:22:51 -05:00
* last_fail_time_us = hrt_absolute_time ( ) ;
2017-04-22 09:07:28 +10:00
}
2018-01-28 11:22:51 -05:00
if ( was_valid ! = valid ) {
* validity_changed = true ;
* valid_state = valid ;
}
return valid ;
2017-04-22 09:07:28 +10:00
}
2014-01-27 20:49:17 +01:00
void
set_control_mode ( )
{
2014-05-27 21:56:32 +02:00
/* set vehicle_control_mode according to set_navigation_state */
2014-01-27 20:49:17 +01:00
control_mode . flag_armed = armed . armed ;
2014-12-23 21:50:16 +01:00
control_mode . flag_external_manual_override_ok = ( ! status . is_rotary_wing & & ! status . is_vtol ) ;
2016-01-20 22:04:31 -08:00
control_mode . flag_system_hil_enabled = status . hil_state = = vehicle_status_s : : HIL_STATE_ON ;
2014-02-17 16:50:00 +04:00
control_mode . flag_control_offboard_enabled = false ;
2014-01-27 20:49:17 +01:00
2014-06-16 17:34:21 +02:00
switch ( status . nav_state ) {
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_MANUAL :
2014-05-27 21:56:32 +02:00
control_mode . flag_control_manual_enabled = true ;
control_mode . flag_control_auto_enabled = false ;
2015-08-19 17:54:57 +02:00
control_mode . flag_control_rates_enabled = stabilization_required ( ) ;
control_mode . flag_control_attitude_enabled = stabilization_required ( ) ;
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2014-05-27 21:56:32 +02:00
control_mode . flag_control_altitude_enabled = false ;
control_mode . flag_control_climb_rate_enabled = false ;
control_mode . flag_control_position_enabled = false ;
control_mode . flag_control_velocity_enabled = false ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2014-05-27 21:56:32 +02:00
control_mode . flag_control_termination_enabled = false ;
break ;
2014-12-04 14:23:19 +01:00
2015-05-17 12:58:44 +02:00
case vehicle_status_s : : NAVIGATION_STATE_STAB :
control_mode . flag_control_manual_enabled = true ;
control_mode . flag_control_auto_enabled = false ;
control_mode . flag_control_rates_enabled = true ;
control_mode . flag_control_attitude_enabled = true ;
2017-02-15 23:44:25 -05:00
control_mode . flag_control_rattitude_enabled = false ;
2015-05-17 12:58:44 +02:00
control_mode . flag_control_altitude_enabled = false ;
control_mode . flag_control_climb_rate_enabled = false ;
control_mode . flag_control_position_enabled = false ;
control_mode . flag_control_velocity_enabled = false ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2015-05-17 12:58:44 +02:00
control_mode . flag_control_termination_enabled = false ;
break ;
2015-10-20 20:38:42 -04:00
case vehicle_status_s : : NAVIGATION_STATE_RATTITUDE :
control_mode . flag_control_manual_enabled = true ;
control_mode . flag_control_auto_enabled = false ;
control_mode . flag_control_rates_enabled = true ;
control_mode . flag_control_attitude_enabled = true ;
2016-04-21 21:25:59 -06:00
control_mode . flag_control_rattitude_enabled = true ;
2015-10-20 20:38:42 -04:00
control_mode . flag_control_altitude_enabled = false ;
control_mode . flag_control_climb_rate_enabled = false ;
control_mode . flag_control_position_enabled = false ;
control_mode . flag_control_velocity_enabled = false ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2015-10-20 20:38:42 -04:00
control_mode . flag_control_termination_enabled = false ;
break ;
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_ALTCTL :
2014-05-27 21:56:32 +02:00
control_mode . flag_control_manual_enabled = true ;
control_mode . flag_control_auto_enabled = false ;
control_mode . flag_control_rates_enabled = true ;
control_mode . flag_control_attitude_enabled = true ;
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2014-05-27 21:56:32 +02:00
control_mode . flag_control_altitude_enabled = true ;
control_mode . flag_control_climb_rate_enabled = true ;
control_mode . flag_control_position_enabled = false ;
control_mode . flag_control_velocity_enabled = false ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2014-05-27 21:56:32 +02:00
control_mode . flag_control_termination_enabled = false ;
break ;
2014-01-27 20:49:17 +01:00
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_POSCTL :
2014-05-27 21:56:32 +02:00
control_mode . flag_control_manual_enabled = true ;
control_mode . flag_control_auto_enabled = false ;
control_mode . flag_control_rates_enabled = true ;
control_mode . flag_control_attitude_enabled = true ;
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2014-05-27 21:56:32 +02:00
control_mode . flag_control_altitude_enabled = true ;
control_mode . flag_control_climb_rate_enabled = true ;
2015-08-13 09:00:15 +02:00
control_mode . flag_control_position_enabled = ! status . in_transition_mode ;
control_mode . flag_control_velocity_enabled = ! status . in_transition_mode ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2014-05-27 21:56:32 +02:00
control_mode . flag_control_termination_enabled = false ;
2014-01-27 20:49:17 +01:00
break ;
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_AUTO_RTL :
case vehicle_status_s : : NAVIGATION_STATE_AUTO_RCRECOVER :
2015-06-13 00:16:25 +02:00
/* override is not ok for the RTL and recovery mode */
control_mode . flag_external_manual_override_ok = false ;
2018-04-12 01:09:56 -04:00
/* fallthrough */
2016-02-18 06:57:01 -08:00
case vehicle_status_s : : NAVIGATION_STATE_AUTO_FOLLOW_TARGET :
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_AUTO_RTGS :
2016-03-13 15:39:35 +01:00
case vehicle_status_s : : NAVIGATION_STATE_AUTO_LAND :
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_AUTO_LANDENGFAIL :
2018-01-14 23:23:14 +05:30
case vehicle_status_s : : NAVIGATION_STATE_AUTO_PRECLAND :
2015-06-13 00:16:25 +02:00
case vehicle_status_s : : NAVIGATION_STATE_AUTO_MISSION :
case vehicle_status_s : : NAVIGATION_STATE_AUTO_LOITER :
2015-11-22 16:03:58 +01:00
case vehicle_status_s : : NAVIGATION_STATE_AUTO_TAKEOFF :
2014-05-27 21:56:32 +02:00
control_mode . flag_control_manual_enabled = false ;
control_mode . flag_control_auto_enabled = true ;
control_mode . flag_control_rates_enabled = true ;
control_mode . flag_control_attitude_enabled = true ;
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2014-05-27 21:56:32 +02:00
control_mode . flag_control_altitude_enabled = true ;
control_mode . flag_control_climb_rate_enabled = true ;
2016-01-14 14:25:22 +01:00
control_mode . flag_control_position_enabled = ! status . in_transition_mode ;
control_mode . flag_control_velocity_enabled = ! status . in_transition_mode ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2014-05-27 21:56:32 +02:00
control_mode . flag_control_termination_enabled = false ;
2014-01-27 20:49:17 +01:00
break ;
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_AUTO_LANDGPSFAIL :
2014-08-22 00:40:45 +02:00
control_mode . flag_control_manual_enabled = false ;
control_mode . flag_control_auto_enabled = false ;
control_mode . flag_control_rates_enabled = true ;
control_mode . flag_control_attitude_enabled = true ;
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2014-08-22 00:40:45 +02:00
control_mode . flag_control_altitude_enabled = false ;
control_mode . flag_control_climb_rate_enabled = true ;
control_mode . flag_control_position_enabled = false ;
control_mode . flag_control_velocity_enabled = false ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2014-08-22 00:40:45 +02:00
control_mode . flag_control_termination_enabled = false ;
break ;
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_ACRO :
2014-11-13 09:43:51 +10:00
control_mode . flag_control_manual_enabled = true ;
control_mode . flag_control_auto_enabled = false ;
control_mode . flag_control_rates_enabled = true ;
control_mode . flag_control_attitude_enabled = false ;
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2014-11-13 09:43:51 +10:00
control_mode . flag_control_altitude_enabled = false ;
control_mode . flag_control_climb_rate_enabled = false ;
control_mode . flag_control_position_enabled = false ;
control_mode . flag_control_velocity_enabled = false ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2014-11-13 09:43:51 +10:00
control_mode . flag_control_termination_enabled = false ;
2016-02-25 17:00:39 +00:00
break ;
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_DESCEND :
2014-11-13 09:43:51 +10:00
/* TODO: check if this makes sense */
control_mode . flag_control_manual_enabled = false ;
control_mode . flag_control_auto_enabled = true ;
control_mode . flag_control_rates_enabled = true ;
control_mode . flag_control_attitude_enabled = true ;
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2014-11-13 09:43:51 +10:00
control_mode . flag_control_position_enabled = false ;
control_mode . flag_control_velocity_enabled = false ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2014-11-13 09:43:51 +10:00
control_mode . flag_control_altitude_enabled = false ;
control_mode . flag_control_climb_rate_enabled = true ;
control_mode . flag_control_termination_enabled = false ;
break ;
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_TERMINATION :
2014-01-27 20:49:17 +01:00
/* disable all controllers on termination */
control_mode . flag_control_manual_enabled = false ;
control_mode . flag_control_auto_enabled = false ;
control_mode . flag_control_rates_enabled = false ;
control_mode . flag_control_attitude_enabled = false ;
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2014-01-27 20:49:17 +01:00
control_mode . flag_control_position_enabled = false ;
control_mode . flag_control_velocity_enabled = false ;
2016-03-09 12:47:08 -08:00
control_mode . flag_control_acceleration_enabled = false ;
2014-01-27 20:49:17 +01:00
control_mode . flag_control_altitude_enabled = false ;
control_mode . flag_control_climb_rate_enabled = false ;
control_mode . flag_control_termination_enabled = true ;
break ;
2015-01-28 07:58:42 +01:00
case vehicle_status_s : : NAVIGATION_STATE_OFFBOARD :
2014-11-13 09:43:51 +10:00
control_mode . flag_control_manual_enabled = false ;
control_mode . flag_control_auto_enabled = false ;
control_mode . flag_control_offboard_enabled = true ;
2015-02-13 23:19:43 +01:00
/*
* The control flags depend on what is ignored according to the offboard control mode topic
* Inner loop flags ( e . g . attitude ) also depend on outer loop ignore flags ( e . g . position )
*/
control_mode . flag_control_rates_enabled = ! offboard_control_mode . ignore_bodyrate | |
2018-04-12 01:09:56 -04:00
! offboard_control_mode . ignore_attitude | |
! offboard_control_mode . ignore_position | |
! offboard_control_mode . ignore_velocity | |
! offboard_control_mode . ignore_acceleration_force ;
2015-02-13 23:19:43 +01:00
control_mode . flag_control_attitude_enabled = ! offboard_control_mode . ignore_attitude | |
2018-04-12 01:09:56 -04:00
! offboard_control_mode . ignore_position | |
! offboard_control_mode . ignore_velocity | |
! offboard_control_mode . ignore_acceleration_force ;
2015-02-13 23:19:43 +01:00
2016-02-26 13:40:42 +00:00
control_mode . flag_control_rattitude_enabled = false ;
2016-02-26 18:14:03 -08:00
control_mode . flag_control_acceleration_enabled = ! offboard_control_mode . ignore_acceleration_force & &
2018-04-12 01:09:56 -04:00
! status . in_transition_mode ;
2016-04-20 12:13:20 -07:00
2015-08-07 16:43:16 +02:00
control_mode . flag_control_velocity_enabled = ( ! offboard_control_mode . ignore_velocity | |
2018-04-12 01:09:56 -04:00
! offboard_control_mode . ignore_position ) & & ! status . in_transition_mode & &
! control_mode . flag_control_acceleration_enabled ;
2015-02-13 23:19:43 +01:00
2016-04-07 15:09:21 -07:00
control_mode . flag_control_climb_rate_enabled = ( ! offboard_control_mode . ignore_velocity | |
2018-04-12 01:09:56 -04:00
! offboard_control_mode . ignore_position ) & & ! control_mode . flag_control_acceleration_enabled ;
2015-02-13 23:19:43 +01:00
2016-02-26 18:14:03 -08:00
control_mode . flag_control_position_enabled = ! offboard_control_mode . ignore_position & & ! status . in_transition_mode & &
2018-04-12 01:09:56 -04:00
! control_mode . flag_control_acceleration_enabled ;
2015-02-13 23:19:43 +01:00
2016-04-07 15:09:21 -07:00
control_mode . flag_control_altitude_enabled = ( ! offboard_control_mode . ignore_velocity | |
2018-04-12 01:09:56 -04:00
! offboard_control_mode . ignore_position ) & & ! control_mode . flag_control_acceleration_enabled ;
2015-01-16 16:46:16 +01:00
2014-11-13 09:43:51 +10:00
break ;
2014-01-27 20:49:17 +01:00
default :
break ;
}
}
2015-08-19 17:54:57 +02:00
bool
stabilization_required ( )
{
return ( status . is_rotary_wing | | // is a rotary wing, or
status . vtol_fw_permanent_stab | | // is a VTOL in fixed wing mode and stabilisation is on, or
( vtol_status . vtol_in_trans_mode & & // is currently a VTOL transitioning AND
2018-04-12 01:09:56 -04:00
! status . is_rotary_wing ) ) ; // is a fixed wing, ie: transitioning back to rotary wing mode
2015-08-19 17:54:57 +02:00
}
2013-07-31 20:58:27 +04:00
void
2018-03-27 15:16:19 -04:00
print_reject_mode ( const char * msg )
2013-07-31 20:58:27 +04:00
{
hrt_abstime t = hrt_absolute_time ( ) ;
if ( t - last_print_mode_reject_time > PRINT_MODE_REJECT_INTERVAL ) {
last_print_mode_reject_time = t ;
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " REJECT %s " , msg ) ;
2014-02-01 13:21:51 +01:00
2014-02-11 00:24:40 +01:00
/* only buzz if armed, because else we're driving people nuts indoors
they really need to look at the leds as well . */
tune_negative ( armed . armed ) ;
2013-07-31 20:58:27 +04:00
}
}
2013-08-16 09:23:39 +02:00
void
print_reject_arm ( const char * msg )
{
hrt_abstime t = hrt_absolute_time ( ) ;
if ( t - last_print_mode_reject_time > PRINT_MODE_REJECT_INTERVAL ) {
last_print_mode_reject_time = t ;
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , msg ) ;
2014-02-11 00:24:40 +01:00
tune_negative ( true ) ;
2013-08-16 09:23:39 +02:00
}
}
2018-03-27 15:16:19 -04:00
void answer_command ( const vehicle_command_s & cmd , unsigned result , orb_advert_t & command_ack_pub )
2013-08-22 15:57:17 +02:00
{
switch ( result ) {
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED :
2016-09-28 14:50:02 +02:00
tune_positive ( true ) ;
2013-08-27 23:08:00 +02:00
break ;
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED :
2014-02-11 00:24:40 +01:00
tune_negative ( true ) ;
2013-08-27 23:08:00 +02:00
break ;
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_RESULT_FAILED :
2014-02-11 00:24:40 +01:00
tune_negative ( true ) ;
2013-08-27 23:08:00 +02:00
break ;
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED :
2014-02-11 00:24:40 +01:00
tune_negative ( true ) ;
2013-08-27 23:08:00 +02:00
break ;
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_RESULT_UNSUPPORTED :
2014-02-11 00:24:40 +01:00
tune_negative ( true ) ;
2013-08-27 23:08:00 +02:00
break ;
default :
break ;
2013-08-22 15:57:17 +02:00
}
2015-12-12 13:01:49 +01:00
/* publish ACK */
2017-07-27 17:08:22 -07:00
vehicle_command_ack_s command_ack = {
. timestamp = 0 ,
2017-08-18 16:52:46 -07:00
. result_param2 = 0 ,
2017-07-27 17:08:22 -07:00
. command = cmd . command ,
2017-08-18 16:52:46 -07:00
. result = ( uint8_t ) result ,
2017-09-07 10:17:15 -04:00
. from_external = false ,
2017-08-18 16:52:46 -07:00
. result_param1 = 0 ,
. target_system = cmd . source_system ,
. target_component = cmd . source_component
2017-07-27 17:08:22 -07:00
} ;
2015-12-12 13:01:49 +01:00
if ( command_ack_pub ! = nullptr ) {
orb_publish ( ORB_ID ( vehicle_command_ack ) , command_ack_pub , & command_ack ) ;
} else {
2018-04-12 01:09:56 -04:00
command_ack_pub = orb_advertise_queue ( ORB_ID ( vehicle_command_ack ) , & command_ack ,
vehicle_command_ack_s : : ORB_QUEUE_LENGTH ) ;
2015-12-12 13:01:49 +01:00
}
2013-08-22 15:57:17 +02:00
}
2013-03-26 10:44:49 -07:00
void * commander_low_prio_loop ( void * arg )
2013-03-25 14:53:54 -07:00
{
/* Set thread name */
2016-01-07 15:09:38 -08:00
px4_prctl ( PR_SET_NAME , " commander_low_prio " , px4_getpid ( ) ) ;
2013-03-25 14:53:54 -07:00
2013-08-17 18:39:46 +02:00
/* Subscribe to command topic */
int cmd_sub = orb_subscribe ( ORB_ID ( vehicle_command ) ) ;
2015-12-12 13:01:49 +01:00
/* command ack */
orb_advert_t command_ack_pub = nullptr ;
2013-08-17 18:39:46 +02:00
/* wakeup source(s) */
2015-04-24 01:24:31 -07:00
px4_pollfd_struct_t fds [ 1 ] ;
2013-08-17 18:39:46 +02:00
/* use the gyro to pace output - XXX BROKEN if we are using the L3GD20 */
fds [ 0 ] . fd = cmd_sub ;
fds [ 0 ] . events = POLLIN ;
2013-08-15 09:52:22 +02:00
2013-03-25 14:53:54 -07:00
while ( ! thread_should_exit ) {
2015-03-28 13:06:05 -07:00
/* wait for up to 1000ms for data */
2015-04-24 01:24:31 -07:00
int pret = px4_poll ( & fds [ 0 ] , ( sizeof ( fds ) / sizeof ( fds [ 0 ] ) ) , 1000 ) ;
2013-03-25 14:53:54 -07:00
2017-03-24 16:53:37 +01:00
if ( pret < 0 ) {
/* this is undesirable but not much we can do - might want to flag unhappy status */
2016-02-05 00:54:19 +01:00
warn ( " commander: poll error %d, %d " , pret , errno ) ;
2013-08-17 18:39:46 +02:00
continue ;
2018-04-12 01:09:56 -04:00
2017-03-24 16:53:37 +01:00
} else if ( pret ! = 0 ) {
2017-07-27 17:08:22 -07:00
struct vehicle_command_s cmd ;
2013-08-07 20:21:49 +02:00
2015-03-28 13:06:05 -07:00
/* if we reach here, we have a valid command */
orb_copy ( ORB_ID ( vehicle_command ) , cmd_sub , & cmd ) ;
2013-03-25 14:53:54 -07:00
2016-02-17 16:50:13 +01:00
/* ignore commands the high-prio loop or the navigator handles */
2015-05-26 22:55:14 -07:00
if ( cmd . command = = vehicle_command_s : : VEHICLE_CMD_DO_SET_MODE | |
cmd . command = = vehicle_command_s : : VEHICLE_CMD_COMPONENT_ARM_DISARM | |
cmd . command = = vehicle_command_s : : VEHICLE_CMD_NAV_TAKEOFF | |
2016-02-17 16:50:13 +01:00
cmd . command = = vehicle_command_s : : VEHICLE_CMD_DO_SET_SERVO | |
cmd . command = = vehicle_command_s : : VEHICLE_CMD_DO_CHANGE_SPEED ) {
2016-08-22 01:03:58 -04:00
2015-03-28 13:06:05 -07:00
continue ;
}
2013-03-25 14:53:54 -07:00
2015-03-28 13:06:05 -07:00
/* only handle low-priority commands here */
switch ( cmd . command ) {
2013-08-07 20:21:49 +02:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_PREFLIGHT_REBOOT_SHUTDOWN :
2018-03-27 15:53:56 -04:00
if ( is_safe ( safety , armed ) ) {
2015-03-28 13:06:05 -07:00
if ( ( ( int ) ( cmd . param1 ) ) = = 1 ) {
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2015-03-28 13:06:05 -07:00
usleep ( 100000 ) ;
/* reboot */
2017-04-18 14:06:30 +02:00
px4_shutdown_request ( true , false ) ;
2013-08-22 15:57:17 +02:00
2017-09-23 10:35:36 -04:00
} else if ( ( ( int ) ( cmd . param1 ) ) = = 2 ) {
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
usleep ( 100000 ) ;
/* shutdown */
px4_shutdown_request ( false , false ) ;
2015-03-28 13:06:05 -07:00
} else if ( ( ( int ) ( cmd . param1 ) ) = = 3 ) {
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2015-03-28 13:06:05 -07:00
usleep ( 100000 ) ;
/* reboot to bootloader */
2017-04-18 14:06:30 +02:00
px4_shutdown_request ( true , true ) ;
2013-08-27 23:08:00 +02:00
2015-03-28 13:06:05 -07:00
} else {
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED , command_ack_pub ) ;
2015-03-28 13:06:05 -07:00
}
2013-08-27 23:08:00 +02:00
2013-08-17 18:39:46 +02:00
} else {
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED , command_ack_pub ) ;
2013-08-17 18:39:46 +02:00
}
2013-03-25 14:53:54 -07:00
2015-03-28 13:06:05 -07:00
break ;
2013-08-27 23:08:00 +02:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_PREFLIGHT_CALIBRATION : {
2013-03-25 14:53:54 -07:00
2016-09-20 10:30:18 +02:00
int calib_ret = PX4_ERROR ;
2013-03-25 14:53:54 -07:00
2015-03-28 13:06:05 -07:00
/* try to go to INIT/PREFLIGHT arming state */
2018-03-27 16:27:47 -04:00
if ( TRANSITION_DENIED = = arming_state_transition ( & status , battery , safety , vehicle_status_s : : ARMING_STATE_INIT , & armed ,
2018-04-12 01:09:56 -04:00
false /* fRunPreArmChecks */ , & mavlink_log_pub , & status_flags ,
arm_requirements , hrt_elapsed_time ( & commander_boot_timestamp ) ) ) {
2017-04-17 00:18:39 -04:00
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED , command_ack_pub ) ;
2015-03-28 13:06:05 -07:00
break ;
2018-04-12 01:09:56 -04:00
2015-05-21 17:25:37 +02:00
} else {
2016-02-25 17:00:39 +00:00
status_flags . condition_calibration_enabled = true ;
2015-03-28 13:06:05 -07:00
}
2013-03-25 14:53:54 -07:00
2015-03-28 13:06:05 -07:00
if ( ( int ) ( cmd . param1 ) = = 1 ) {
/* gyro calibration */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2016-03-15 18:25:02 +00:00
calib_ret = do_gyro_calibration ( & mavlink_log_pub ) ;
2013-03-25 14:53:54 -07:00
2017-02-17 14:20:00 +01:00
} else if ( ( int ) ( cmd . param1 ) = = vehicle_command_s : : PREFLIGHT_CALIBRATION_TEMPERATURE_CALIBRATION | |
2018-04-12 01:09:56 -04:00
( int ) ( cmd . param5 ) = = vehicle_command_s : : PREFLIGHT_CALIBRATION_TEMPERATURE_CALIBRATION | |
( int ) ( cmd . param7 ) = = vehicle_command_s : : PREFLIGHT_CALIBRATION_TEMPERATURE_CALIBRATION ) {
2017-01-19 16:01:01 +01:00
/* temperature calibration: handled in events module */
break ;
2015-03-28 13:06:05 -07:00
} else if ( ( int ) ( cmd . param2 ) = = 1 ) {
/* magnetometer calibration */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2016-03-15 18:25:02 +00:00
calib_ret = do_mag_calibration ( & mavlink_log_pub ) ;
2013-08-22 15:57:17 +02:00
2015-03-28 13:06:05 -07:00
} else if ( ( int ) ( cmd . param3 ) = = 1 ) {
/* zero-altitude pressure calibration */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_DENIED , command_ack_pub ) ;
2013-08-22 15:57:17 +02:00
2015-03-28 13:06:05 -07:00
} else if ( ( int ) ( cmd . param4 ) = = 1 ) {
/* RC calibration */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2015-03-28 13:06:05 -07:00
/* disable RC control input completely */
2016-02-26 11:01:12 +00:00
status_flags . rc_input_blocked = true ;
2015-03-28 13:06:05 -07:00
calib_ret = OK ;
2016-03-15 18:25:02 +00:00
mavlink_log_info ( & mavlink_log_pub , " CAL: Disabling RC IN " ) ;
2015-03-28 13:06:05 -07:00
} else if ( ( int ) ( cmd . param4 ) = = 2 ) {
/* RC trim calibration */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2016-03-15 18:25:02 +00:00
calib_ret = do_trim_calibration ( & mavlink_log_pub ) ;
2015-03-28 13:06:05 -07:00
} else if ( ( int ) ( cmd . param5 ) = = 1 ) {
/* accelerometer calibration */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2016-03-15 18:25:02 +00:00
calib_ret = do_accel_calibration ( & mavlink_log_pub ) ;
2018-04-12 01:09:56 -04:00
2015-05-19 14:20:00 +02:00
} else if ( ( int ) ( cmd . param5 ) = = 2 ) {
// board offset calibration
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2016-03-15 18:25:02 +00:00
calib_ret = do_level_calibration ( & mavlink_log_pub ) ;
2018-04-12 01:09:56 -04:00
2017-02-22 12:11:10 +01:00
} else if ( ( int ) ( cmd . param6 ) = = 1 | | ( int ) ( cmd . param6 ) = = 2 ) {
// TODO: param6 == 1 is deprecated, but we still accept it for a while (feb 2017)
2015-03-28 13:06:05 -07:00
/* airspeed calibration */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2016-03-15 18:25:02 +00:00
calib_ret = do_airspeed_calibration ( & mavlink_log_pub ) ;
2015-03-28 13:06:05 -07:00
2015-04-28 14:54:58 +02:00
} else if ( ( int ) ( cmd . param7 ) = = 1 ) {
/* do esc calibration */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2016-03-15 18:25:02 +00:00
calib_ret = do_esc_calibration ( & mavlink_log_pub , & armed ) ;
2016-02-12 21:39:50 -08:00
2015-03-28 13:06:05 -07:00
} else if ( ( int ) ( cmd . param4 ) = = 0 ) {
/* RC calibration ended - have we been in one worth confirming? */
2016-02-26 11:01:12 +00:00
if ( status_flags . rc_input_blocked ) {
2015-03-28 13:06:05 -07:00
/* enable RC control input */
2016-02-26 11:01:12 +00:00
status_flags . rc_input_blocked = false ;
2016-03-15 18:25:02 +00:00
mavlink_log_info ( & mavlink_log_pub , " CAL: Re-enabling RC IN " ) ;
2015-03-28 13:06:05 -07:00
}
2018-04-12 01:09:56 -04:00
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2015-04-28 14:54:58 +02:00
/* this always succeeds */
calib_ret = OK ;
2018-04-12 01:09:56 -04:00
2017-01-11 14:39:21 +01:00
} else {
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_UNSUPPORTED , command_ack_pub ) ;
2014-02-01 13:21:51 +01:00
}
2016-02-25 17:00:39 +00:00
status_flags . condition_calibration_enabled = false ;
2015-05-21 17:25:37 +02:00
2015-03-28 13:06:05 -07:00
if ( calib_ret = = OK ) {
tune_positive ( true ) ;
2014-02-01 13:21:51 +01:00
2018-03-29 23:14:34 -04:00
Commander : : preflight_check ( false ) ;
2016-02-24 08:00:33 +00:00
2018-04-12 01:09:56 -04:00
arming_state_transition ( & status , battery , safety , vehicle_status_s : : ARMING_STATE_STANDBY , & armed ,
false /* fRunPreArmChecks */ ,
& mavlink_log_pub , & status_flags , arm_requirements , hrt_elapsed_time ( & commander_boot_timestamp ) ) ;
2015-03-08 14:51:23 +01:00
2015-04-25 12:37:43 -07:00
} else {
tune_negative ( true ) ;
}
2014-05-11 13:36:51 +02:00
2015-03-28 13:06:05 -07:00
break ;
2014-05-11 13:36:51 +02:00
}
2013-03-25 14:53:54 -07:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_PREFLIGHT_STORAGE : {
2015-04-19 23:07:32 +02:00
2015-03-28 13:06:05 -07:00
if ( ( ( int ) ( cmd . param1 ) ) = = 0 ) {
int ret = param_load_default ( ) ;
2013-07-28 23:12:16 +04:00
2015-03-28 13:06:05 -07:00
if ( ret = = OK ) {
2016-03-15 18:25:02 +00:00
mavlink_log_info ( & mavlink_log_pub , " settings loaded " ) ;
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2013-07-28 23:12:16 +04:00
2015-03-28 13:06:05 -07:00
} else {
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " settings load ERROR " ) ;
2013-09-14 08:55:45 +02:00
2015-03-28 13:06:05 -07:00
/* convenience as many parts of NuttX use negative errno */
if ( ret < 0 ) {
ret = - ret ;
}
2013-08-17 18:39:46 +02:00
2015-03-28 13:06:05 -07:00
if ( ret < 1000 ) {
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " ERROR: %s " , strerror ( ret ) ) ;
2015-03-28 13:06:05 -07:00
}
2013-09-14 08:55:45 +02:00
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_FAILED , command_ack_pub ) ;
2014-05-11 13:36:51 +02:00
}
2013-09-05 13:24:21 +02:00
2015-03-28 13:06:05 -07:00
} else if ( ( ( int ) ( cmd . param1 ) ) = = 1 ) {
2015-04-25 12:53:58 +02:00
2016-04-05 12:34:40 +02:00
# ifdef __PX4_QURT
2016-08-22 01:03:58 -04:00
// TODO FIXME: on snapdragon the save happens too early when the params
2016-04-05 12:34:40 +02:00
// are not set yet. We therefore need to wait some time first.
usleep ( 1000000 ) ;
# endif
2015-03-28 13:06:05 -07:00
int ret = param_save_default ( ) ;
2013-09-14 08:55:45 +02:00
2015-03-28 13:06:05 -07:00
if ( ret = = OK ) {
2015-05-14 17:33:07 +02:00
/* do not spam MAVLink, but provide the answer / green led mechanism */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2013-08-17 18:39:46 +02:00
2015-03-28 13:06:05 -07:00
} else {
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " settings save error " ) ;
2013-09-14 08:55:45 +02:00
2015-03-28 13:06:05 -07:00
/* convenience as many parts of NuttX use negative errno */
if ( ret < 0 ) {
ret = - ret ;
}
2013-08-17 18:39:46 +02:00
2015-03-28 13:06:05 -07:00
if ( ret < 1000 ) {
2016-03-15 18:25:02 +00:00
mavlink_log_critical ( & mavlink_log_pub , " ERROR: %s " , strerror ( ret ) ) ;
2015-03-28 13:06:05 -07:00
}
2013-09-14 08:55:45 +02:00
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_FAILED , command_ack_pub ) ;
2015-08-08 00:08:14 +02:00
}
2018-04-12 01:09:56 -04:00
2015-08-08 00:08:14 +02:00
} else if ( ( ( int ) ( cmd . param1 ) ) = = 2 ) {
/* reset parameters and save empty file */
param_reset_all ( ) ;
2017-03-24 17:03:54 +01:00
/* do not spam MAVLink, but provide the answer / green led mechanism */
mavlink_log_critical ( & mavlink_log_pub , " onboard parameters reset " ) ;
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2013-08-27 23:08:00 +02:00
}
2015-03-28 13:06:05 -07:00
break ;
2013-08-17 18:39:46 +02:00
}
2013-08-27 23:08:00 +02:00
2015-05-26 22:55:14 -07:00
case vehicle_command_s : : VEHICLE_CMD_START_RX_PAIR :
2016-12-23 16:08:26 +01:00
/* just ack, implementation handled in the IO driver */
2017-06-23 13:48:54 -07:00
answer_command ( cmd , vehicle_command_s : : VEHICLE_CMD_RESULT_ACCEPTED , command_ack_pub ) ;
2013-08-27 23:08:00 +02:00
break ;
2013-08-17 18:39:46 +02:00
2015-03-28 13:06:05 -07:00
default :
/* don't answer on unsupported commands, it will be done in main loop */
break ;
2015-03-23 10:52:32 -07:00
}
2013-08-17 18:39:46 +02:00
}
2013-03-25 14:53:54 -07:00
}
2015-07-01 11:05:45 -07:00
px4_close ( cmd_sub ) ;
2013-09-01 10:29:30 +02:00
2017-01-28 20:21:58 -05:00
return nullptr ;
2013-03-25 14:53:54 -07:00
}
2017-01-27 19:13:18 +01:00
2017-12-20 15:39:20 -05:00
int Commander : : custom_command ( int argc , char * argv [ ] )
{
return print_usage ( " unknown command " ) ;
}
int Commander : : print_usage ( const char * reason )
{
if ( reason ) {
PX4_WARN ( " %s \n " , reason ) ;
}
return 0 ;
}
int Commander : : task_spawn ( int argc , char * argv [ ] )
{
_task_id = px4_task_spawn_cmd ( " commander " ,
SCHED_DEFAULT ,
SCHED_PRIORITY_DEFAULT + 40 ,
2018-02-01 22:42:59 -05:00
3250 ,
2017-12-20 15:39:20 -05:00
( px4_main_t ) & run_trampoline ,
( char * const * ) argv ) ;
if ( _task_id < 0 ) {
_task_id = - 1 ;
return - errno ;
}
return 0 ;
}
Commander * Commander : : instantiate ( int argc , char * argv [ ] )
{
Commander * instance = new Commander ( ) ;
2017-12-27 19:31:40 +01:00
// XXX remove this once this is a class member
status = { } ;
2017-12-20 15:39:20 -05:00
if ( instance ) {
if ( argc > = 2 & & ! strcmp ( argv [ 1 ] , " --hil " ) ) {
instance - > enable_hil ( ) ;
}
}
return instance ;
}
void Commander : : enable_hil ( )
{
2018-01-17 10:26:31 -05:00
status . hil_state = vehicle_status_s : : HIL_STATE_ON ;
2017-12-26 16:57:52 -05:00
}
void Commander : : mission_init ( )
{
/* init mission state, do it here to allow navigator to use stored mission even if mavlink failed to start */
mission_s mission = { } ;
2018-04-12 01:09:56 -04:00
2017-12-26 16:57:52 -05:00
if ( dm_read ( DM_KEY_MISSION_STATE , 0 , & mission , sizeof ( mission_s ) ) = = sizeof ( mission_s ) ) {
if ( mission . dataman_id = = DM_KEY_WAYPOINTS_OFFBOARD_0 | | mission . dataman_id = = DM_KEY_WAYPOINTS_OFFBOARD_1 ) {
if ( mission . count > 0 ) {
PX4_INFO ( " Mission #%d loaded, %u WPs, curr: %d " , mission . dataman_id , mission . count , mission . current_seq ) ;
}
} else {
PX4_ERR ( " reading mission state failed " ) ;
/* initialize mission state in dataman */
mission . timestamp = hrt_absolute_time ( ) ;
mission . dataman_id = DM_KEY_WAYPOINTS_OFFBOARD_0 ;
dm_write ( DM_KEY_MISSION_STATE , 0 , DM_PERSIST_POWER_ON_RESET , & mission , sizeof ( mission_s ) ) ;
}
orb_advert_t mission_pub = orb_advertise ( ORB_ID ( mission ) , & mission ) ;
orb_unadvertise ( mission_pub ) ;
}
}
2018-03-23 14:13:09 +01:00
2018-03-29 23:14:34 -04:00
bool Commander : : preflight_check ( bool report )
{
const bool checkGNSS = ( arm_requirements & ARM_REQ_GPS_BIT ) ;
2018-04-12 01:09:56 -04:00
bool success = Preflight : : preflightCheck ( & mavlink_log_pub , status , status_flags , checkGNSS , report , false ,
hrt_elapsed_time ( & commander_boot_timestamp ) ) ;
2018-03-29 23:14:34 -04:00
status_flags . condition_system_sensors_initialized = success ;
return success ;
}
2018-04-12 01:09:56 -04:00
void Commander : : poll_telemetry_status ( )
2018-03-23 14:13:09 +01:00
{
bool updated = false ;
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
for ( int i = 0 ; i < ORB_MULTI_MAX_INSTANCES ; i + + ) {
2018-04-05 15:06:26 +02:00
if ( _telemetry [ i ] . subscriber < 0 ) {
_telemetry [ i ] . subscriber = orb_subscribe_multi ( ORB_ID ( telemetry_status ) , i ) ;
2018-03-23 14:13:09 +01:00
}
2018-04-05 15:06:26 +02:00
orb_check ( _telemetry [ i ] . subscriber , & updated ) ;
2018-03-23 14:13:09 +01:00
if ( updated ) {
telemetry_status_s telemetry = { } ;
2018-04-05 15:06:26 +02:00
orb_copy ( ORB_ID ( telemetry_status ) , _telemetry [ i ] . subscriber , & telemetry ) ;
2018-03-23 14:13:09 +01:00
/* perform system checks when new telemetry link connected */
if ( /* we first connect a link or re-connect a link after loosing it or haven't yet reported anything */
2018-04-12 01:09:56 -04:00
( _telemetry [ i ] . last_heartbeat = = 0 | | ( hrt_elapsed_time ( & _telemetry [ i ] . last_heartbeat ) > 3 * 1000 * 1000 )
| | ! _telemetry [ i ] . preflight_checks_reported ) & &
/* and this link has a communication partner */
( telemetry . heartbeat_time > 0 ) & &
/* and it is still connected */
( hrt_elapsed_time ( & telemetry . heartbeat_time ) < 2 * 1000 * 1000 ) & &
/* and the system is not already armed (and potentially flying) */
! armed . armed ) {
2018-03-23 14:13:09 +01:00
/* flag the checks as reported for this link when we actually report them */
2018-04-12 01:09:56 -04:00
_telemetry [ i ] . preflight_checks_reported = status_flags . condition_system_hotplug_timeout ;
preflight_check ( true ) ;
2018-03-23 14:13:09 +01:00
// Provide feedback on mission state
2018-04-12 01:09:56 -04:00
const mission_result_s & mission_result = _mission_result_sub . get ( ) ;
if ( ( mission_result . timestamp > commander_boot_timestamp ) & & status_flags . condition_system_hotplug_timeout & &
( mission_result . instance_count > 0 ) & & ! mission_result . valid ) {
2018-03-23 14:13:09 +01:00
mavlink_log_critical ( & mavlink_log_pub , " Planned mission fails check. Please upload again. " ) ;
}
}
/* set (and don't reset) telemetry via USB as active once a MAVLink connection is up */
if ( telemetry . type = = telemetry_status_s : : TELEMETRY_STATUS_RADIO_TYPE_USB ) {
2018-04-12 01:09:56 -04:00
status_flags . usb_connected = true ;
2018-03-23 14:13:09 +01:00
}
/* set latency type of the telemetry connection */
if ( telemetry . type = = telemetry_status_s : : TELEMETRY_STATUS_RADIO_TYPE_IRIDIUM ) {
2018-04-05 15:06:26 +02:00
_telemetry [ i ] . high_latency = true ;
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
} else {
2018-04-05 15:06:26 +02:00
_telemetry [ i ] . high_latency = false ;
2018-03-23 14:13:09 +01:00
}
2018-04-05 15:06:26 +02:00
if ( telemetry . heartbeat_time > 0 & & ( _telemetry [ i ] . last_heartbeat < telemetry . heartbeat_time ) ) {
_telemetry [ i ] . last_heartbeat = telemetry . heartbeat_time ;
2018-03-23 14:13:09 +01:00
}
}
}
}
void Commander : : data_link_checks ( int32_t highlatencydatalink_loss_timeout , int32_t highlatencydatalink_regain_timeout ,
2018-04-12 01:09:56 -04:00
int32_t datalink_loss_timeout , int32_t datalink_regain_timeout , bool * status_changed )
2018-03-23 14:13:09 +01:00
{
/* data links check */
bool have_link = false ;
bool high_latency_link_exists = false ;
bool have_low_latency_link = false ;
int32_t dl_loss_timeout_local = 0 ;
int32_t dl_regain_timeout_local = 0 ;
for ( int i = 0 ; i < ORB_MULTI_MAX_INSTANCES ; i + + ) {
2018-04-05 15:06:26 +02:00
if ( _telemetry [ i ] . high_latency ) {
2018-03-23 14:13:09 +01:00
high_latency_link_exists = true ;
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
if ( status . high_latency_data_link_active ) {
dl_loss_timeout_local = highlatencydatalink_loss_timeout ;
dl_regain_timeout_local = highlatencydatalink_regain_timeout ;
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
} else {
// if the high latency link is inactive we do not want to accidentally detect it as an active link
dl_loss_timeout_local = INT32_MIN ;
dl_regain_timeout_local = INT32_MAX ;
}
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
} else {
dl_loss_timeout_local = datalink_loss_timeout ;
dl_regain_timeout_local = datalink_regain_timeout ;
}
2018-04-05 15:06:26 +02:00
if ( _telemetry [ i ] . last_heartbeat ! = 0 & &
2018-04-12 01:09:56 -04:00
hrt_elapsed_time ( & _telemetry [ i ] . last_heartbeat ) < dl_loss_timeout_local * 1e6 ) {
2018-03-23 14:13:09 +01:00
/* handle the case where data link was gained first time or regained,
* accept datalink as healthy only after datalink_regain_timeout seconds
* */
2018-04-05 15:06:26 +02:00
if ( _telemetry [ i ] . lost & &
2018-04-12 01:09:56 -04:00
hrt_elapsed_time ( & _telemetry [ i ] . last_dl_loss ) > dl_regain_timeout_local * 1e6 ) {
2018-03-23 14:13:09 +01:00
/* report a regain */
2018-04-05 15:06:26 +02:00
if ( _telemetry [ i ] . last_dl_loss > 0 ) {
2018-03-23 14:13:09 +01:00
mavlink_and_console_log_info ( & mavlink_log_pub , " data link #%i regained " , i ) ;
2018-04-12 01:09:56 -04:00
2018-04-05 15:06:26 +02:00
} else if ( _telemetry [ i ] . last_dl_loss = = 0 ) {
2018-03-23 14:13:09 +01:00
/* new link */
}
/* got link again or new */
* status_changed = true ;
2018-04-05 15:06:26 +02:00
_telemetry [ i ] . lost = false ;
2018-03-23 14:13:09 +01:00
have_link = true ;
2018-04-12 01:09:56 -04:00
2018-04-05 15:06:26 +02:00
if ( ! _telemetry [ i ] . high_latency ) {
2018-03-23 14:13:09 +01:00
have_low_latency_link = true ;
}
2018-04-05 15:06:26 +02:00
} else if ( ! _telemetry [ i ] . lost ) {
2018-03-23 14:13:09 +01:00
/* telemetry was healthy also in last iteration
* we don ' t have to check a timeout */
have_link = true ;
2018-04-12 01:09:56 -04:00
2018-04-05 15:06:26 +02:00
if ( ! _telemetry [ i ] . high_latency ) {
2018-03-23 14:13:09 +01:00
have_low_latency_link = true ;
}
}
} else {
2018-04-05 15:06:26 +02:00
if ( ! _telemetry [ i ] . lost ) {
2018-03-23 14:13:09 +01:00
/* only reset the timestamp to a different time on state change */
2018-04-05 15:06:26 +02:00
_telemetry [ i ] . last_dl_loss = hrt_absolute_time ( ) ;
2018-03-23 14:13:09 +01:00
mavlink_and_console_log_info ( & mavlink_log_pub , " data link #%i lost " , i ) ;
2018-04-05 15:06:26 +02:00
_telemetry [ i ] . lost = true ;
2018-03-23 14:13:09 +01:00
}
}
}
if ( have_link ) {
/* handle the case where data link was regained */
if ( status . data_link_lost ) {
status . data_link_lost = false ;
* status_changed = true ;
}
if ( status . high_latency_data_link_active & & have_low_latency_link ) {
// regained a low latency telemetry link, deactivate the high latency link
// to avoid transmitting unnecessary data over that link
status . high_latency_data_link_active = false ;
* status_changed = true ;
mavlink_log_critical ( & mavlink_log_pub , " LOW LATENCY DATA LINKS REGAINED, DEACTIVATING HIGH LATENCY LINK " ) ;
vehicle_command_s vehicle_cmd ;
2018-04-11 15:19:47 +02:00
vehicle_cmd . timestamp = hrt_absolute_time ( ) ;
2018-03-23 14:13:09 +01:00
vehicle_cmd . command = vehicle_command_s : : VEHICLE_CMD_CONTROL_HIGH_LATENCY ;
vehicle_cmd . param1 = 0.0f ;
vehicle_cmd . from_external = false ;
vehicle_cmd . target_system = status . system_id ;
vehicle_cmd . target_component = 0 ;
if ( _vehicle_cmd_pub ! = nullptr ) {
orb_publish ( ORB_ID ( vehicle_command ) , _vehicle_cmd_pub , & vehicle_cmd ) ;
} else {
_vehicle_cmd_pub = orb_advertise ( ORB_ID ( vehicle_command ) , & vehicle_cmd ) ;
}
}
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
} else {
if ( high_latency_link_exists & & ! status . high_latency_data_link_active & & armed . armed ) {
// low latency telemetry lost and high latency link existing
status . high_latency_data_link_active = true ;
* status_changed = true ;
vehicle_command_s vehicle_cmd ;
2018-04-11 15:19:47 +02:00
vehicle_cmd . timestamp = hrt_absolute_time ( ) ;
2018-03-23 14:13:09 +01:00
vehicle_cmd . command = vehicle_command_s : : VEHICLE_CMD_CONTROL_HIGH_LATENCY ;
vehicle_cmd . param1 = 1.0f ;
vehicle_cmd . from_external = false ;
vehicle_cmd . target_system = status . system_id ;
vehicle_cmd . target_component = 0 ;
2018-03-29 11:05:13 +02:00
// set heartbeat to current time for high latency so that the first message can be transmitted
for ( int i = 0 ; i < ORB_MULTI_MAX_INSTANCES ; i + + ) {
2018-04-05 15:06:26 +02:00
if ( _telemetry [ i ] . high_latency ) {
_telemetry [ i ] . last_heartbeat = hrt_absolute_time ( ) ;
2018-03-29 11:05:13 +02:00
}
}
2018-03-23 14:13:09 +01:00
if ( _vehicle_cmd_pub ! = nullptr ) {
orb_publish ( ORB_ID ( vehicle_command ) , _vehicle_cmd_pub , & vehicle_cmd ) ;
} else {
_vehicle_cmd_pub = orb_advertise ( ORB_ID ( vehicle_command ) , & vehicle_cmd ) ;
}
if ( ! status . data_link_lost ) {
mavlink_log_critical ( & mavlink_log_pub , " ALL LOW LATENCY DATA LINKS LOST, ACTIVATING HIGH LATENCY LINK " ) ;
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
} else {
mavlink_log_critical ( & mavlink_log_pub , " ACTIVATING AVAILABLE HIGH LATENCY LINK " ) ;
}
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
} else if ( ! status . data_link_lost ) {
if ( armed . armed ) {
mavlink_log_critical ( & mavlink_log_pub , " ALL DATA LINKS LOST " ) ;
}
2018-04-12 01:09:56 -04:00
2018-03-23 14:13:09 +01:00
status . data_link_lost = true ;
status . data_link_lost_counter + + ;
* status_changed = true ;
}
}
}