2013-11-27 22:18:14 -04:00
/*
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2015-08-11 03:28:42 -03:00
# include "AP_Arming.h"
# include <AP_Notify/AP_Notify.h>
2018-04-19 17:10:39 -03:00
# include <SRV_Channel/SRV_Channel.h>
2015-09-08 00:54:25 -03:00
# include <GCS_MAVLink/GCS.h>
2013-11-27 22:18:14 -04:00
2016-08-17 05:15:38 -03:00
# define AP_ARMING_COMPASS_MAGFIELD_EXPECTED 530
2015-10-16 00:09:39 -03:00
# define AP_ARMING_COMPASS_MAGFIELD_MIN 185 // 0.35 * 530 milligauss
# define AP_ARMING_COMPASS_MAGFIELD_MAX 875 // 1.65 * 530 milligauss
2015-10-16 00:13:53 -03:00
# define AP_ARMING_BOARD_VOLTAGE_MIN 4.3f
# define AP_ARMING_BOARD_VOLTAGE_MAX 5.8f
2015-12-21 17:51:12 -04:00
# define AP_ARMING_ACCEL_ERROR_THRESHOLD 0.75f
2017-09-18 00:14:52 -03:00
# define AP_ARMING_AHRS_GPS_ERROR_MAX 10 // accept up to 10m difference between AHRS and GPS
2015-10-16 00:13:53 -03:00
2018-09-08 00:30:21 -03:00
# if APM_BUILD_TYPE(APM_BUILD_ArduPlane)
# define ARMING_RUDDER_DEFAULT ARMING_RUDDER_ARMONLY
# else
# define ARMING_RUDDER_DEFAULT ARMING_RUDDER_ARMDISARM
# endif
2013-11-27 22:18:14 -04:00
extern const AP_HAL : : HAL & hal ;
2015-10-25 14:03:46 -03:00
const AP_Param : : GroupInfo AP_Arming : : var_info [ ] = {
2016-12-28 01:41:21 -04:00
2013-11-27 22:18:14 -04:00
// @Param: REQUIRE
// @DisplayName: Require Arming Motors
2018-04-11 18:27:59 -03:00
// @Description: Arming disabled until some requirements are met. If 0, there are no requirements (arm immediately). If 1, require rudder stick or GCS arming before arming motors and sends the minimum throttle PWM value to the throttle channel when disarmed. If 2, require rudder stick or GCS arming and send 0 PWM to throttle channel when disarmed. See the ARMING_CHECK_* parameters to see what checks are done before arming. Note, if setting this parameter to 0 a reboot is required to arm the plane. Also note, even with this parameter at 0, if ARMING_CHECK parameter is not also zero the plane may fail to arm throttle at boot due to a pre-arm check failure.
2014-01-09 15:34:58 -04:00
// @Values: 0:Disabled,1:THR_MIN PWM when disarmed,2:0 PWM when disarmed
2013-11-27 22:18:14 -04:00
// @User: Advanced
2017-02-07 19:47:01 -04:00
AP_GROUPINFO_FLAGS_FRAME ( " REQUIRE " , 0 , AP_Arming , require , 1 ,
AP_PARAM_NO_SHIFT ,
AP_PARAM_FRAME_PLANE | AP_PARAM_FRAME_ROVER ) ,
2013-11-27 22:18:14 -04:00
// @Param: CHECK
// @DisplayName: Arm Checks to Peform (bitmask)
2017-05-16 07:23:21 -03:00
// @Description: Checks prior to arming motor. This is a bitmask of checks that will be performed before allowing arming. The default is no checks, allowing arming at any time. You can select whatever checks you prefer by adding together the values of each check type to set this parameter. For example, to only allow arming when you have GPS lock and no RC failsafe you would set ARMING_CHECK to 72. For most users it is recommended that you set this to 1 to enable all checks.
2018-08-11 13:37:17 -03:00
// @Values: 0:None,1:All,2:Barometer,4:Compass,8:GPS Lock,16:INS(INertial Sensors - accels & gyros),32:Parameters(unused),64:RC Channels,128:Board voltage,256:Battery Level,1024:LoggingAvailable,2048:Hardware safety switch,4096:GPS configuration,8192:System
// @Values{Plane}: 0:None,1:All,2:Barometer,4:Compass,8:GPS Lock,16:INS(INertial Sensors - accels & gyros),32:Parameters(unused),64:RC Channels,128:Board voltage,256:Battery Level,512:Airspeed,1024:LoggingAvailable,2048:Hardware safety switch,4096:GPS configuration,8192:System
// @Bitmask: 0:All,1:Barometer,2:Compass,3:GPS lock,4:INS,5:Parameters,6:RC Channels,7:Board voltage,8:Battery Level,10:Logging Available,11:Hardware safety switch,12:GPS Configuration,13:System
// @Bitmask{Plane}: 0:All,1:Barometer,2:Compass,3:GPS lock,4:INS,5:Parameters,6:RC Channels,7:Board voltage,8:Battery Level,9:Airspeed,10:Logging Available,11:Hardware safety switch,12:GPS Configuration,13:System
2015-10-15 03:26:00 -03:00
// @User: Standard
2015-01-19 20:27:13 -04:00
AP_GROUPINFO ( " CHECK " , 2 , AP_Arming , checks_to_perform , ARMING_CHECK_ALL ) ,
2013-11-27 22:18:14 -04:00
2015-12-21 17:51:12 -04:00
// @Param: ACCTHRESH
// @DisplayName: Accelerometer error threshold
// @Description: Accelerometer error threshold used to determine inconsistent accelerometers. Compares this error range to other accelerometers to detect a hardware or calibration error. Lower value means tighter check and harder to pass arming check. Not all accelerometers are created equal.
// @Units: m/s/s
// @Range: 0.25 3.0
// @User: Advanced
AP_GROUPINFO ( " ACCTHRESH " , 3 , AP_Arming , accel_error_threshold , AP_ARMING_ACCEL_ERROR_THRESHOLD ) ,
2017-07-26 07:20:02 -03:00
// @Param: VOLT_MIN
// @DisplayName: Arming voltage minimum on the first battery
2017-10-29 20:13:49 -03:00
// @Description: The minimum voltage of the first battery required to arm, 0 disables the check
2017-05-02 10:40:34 -03:00
// @Units: V
2016-02-09 19:31:12 -04:00
// @Increment: 0.1
// @User: Standard
2017-07-26 07:20:02 -03:00
AP_GROUPINFO ( " VOLT_MIN " , 4 , AP_Arming , _min_voltage [ 0 ] , 0 ) ,
2016-02-09 19:31:12 -04:00
2017-07-26 07:20:02 -03:00
// @Param: VOLT2_MIN
// @DisplayName: Arming voltage minimum on the second battery
2017-10-29 20:13:49 -03:00
// @Description: The minimum voltage of the second battery required to arm, 0 disables the check
2017-05-02 10:40:34 -03:00
// @Units: V
2016-02-09 19:31:12 -04:00
// @Increment: 0.1
// @User: Standard
2017-07-26 07:20:02 -03:00
AP_GROUPINFO ( " VOLT2_MIN " , 5 , AP_Arming , _min_voltage [ 1 ] , 0 ) ,
2016-02-09 19:31:12 -04:00
2018-09-08 00:30:21 -03:00
// @Param: RUDDER
// @DisplayName: Arming with Rudder enable/disable
// @Description: Allow arm/disarm by rudder input. When enabled arming can be done with right rudder, disarming with left rudder. Rudder arming only works in manual throttle modes with throttle at zero +- deadzone (RCx_DZ)
// @Values: 0:Disabled,1:ArmingOnly,2:ArmOrDisarm
// @User: Advanced
AP_GROUPINFO_FRAME ( " RUDDER " , 6 , AP_Arming , _rudder_arming , ARMING_RUDDER_DEFAULT , AP_PARAM_FRAME_PLANE |
AP_PARAM_FRAME_ROVER |
AP_PARAM_FRAME_COPTER |
AP_PARAM_FRAME_TRICOPTER |
AP_PARAM_FRAME_HELI ) ,
2013-11-27 22:18:14 -04:00
AP_GROUPEND
} ;
2018-06-23 20:01:42 -03:00
AP_Arming : : AP_Arming ( )
2013-11-27 22:18:14 -04:00
{
AP_Param : : setup_object_defaults ( this , var_info ) ;
}
2016-08-17 05:15:38 -03:00
uint16_t AP_Arming : : compass_magfield_expected ( ) const
{
return AP_ARMING_COMPASS_MAGFIELD_EXPECTED ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : is_armed ( )
2016-12-28 01:41:21 -04:00
{
2018-06-20 04:32:50 -03:00
return ( ArmingRequired ) require . get ( ) = = NO | | armed ;
2013-12-11 02:02:25 -04:00
}
2013-11-27 22:18:14 -04:00
2015-10-12 02:29:27 -03:00
uint16_t AP_Arming : : get_enabled_checks ( )
2013-12-11 02:02:25 -04:00
{
2013-11-27 22:18:14 -04:00
return checks_to_perform ;
}
2017-08-01 00:09:27 -03:00
bool AP_Arming : : check_enabled ( const enum AP_Arming : : ArmingChecks check ) const
{
if ( checks_to_perform & ARMING_CHECK_ALL ) {
return true ;
}
if ( checks_to_perform & ARMING_CHECK_NONE ) {
return false ;
}
return ( checks_to_perform & check ) ;
}
MAV_SEVERITY AP_Arming : : check_severity ( const enum AP_Arming : : ArmingChecks check ) const
{
// A check value of ARMING_CHECK_NONE means that the check is always run
if ( check_enabled ( check ) | | check = = ARMING_CHECK_NONE ) {
return MAV_SEVERITY_CRITICAL ;
}
return MAV_SEVERITY_DEBUG ; // technically should be NOTICE, but will annoy users at that level
}
void AP_Arming : : check_failed ( const enum AP_Arming : : ArmingChecks check , bool report , const char * fmt , . . . ) const
{
if ( ! report ) {
return ;
}
char taggedfmt [ MAVLINK_MSG_STATUSTEXT_FIELD_TEXT_LEN + 1 ] ;
hal . util - > snprintf ( ( char * ) taggedfmt , sizeof ( taggedfmt ) - 1 , " PreArm: %s " , fmt ) ;
MAV_SEVERITY severity = check_severity ( check ) ;
va_list arg_list ;
va_start ( arg_list , fmt ) ;
gcs ( ) . send_textv ( severity , taggedfmt , arg_list ) ;
va_end ( arg_list ) ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : barometer_checks ( bool report )
2013-12-11 02:02:25 -04:00
{
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_BARO ) ) {
2018-03-05 16:35:06 -04:00
if ( ! AP : : baro ( ) . all_healthy ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_BARO , report , " Barometer not healthy " ) ;
2013-11-27 22:18:14 -04:00
return false ;
}
}
return true ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : airspeed_checks ( bool report )
2015-01-19 20:27:13 -04:00
{
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_AIRSPEED ) ) {
2018-06-25 00:42:39 -03:00
const AP_Airspeed * airspeed = AP_Airspeed : : get_singleton ( ) ;
2016-10-30 02:24:21 -03:00
if ( airspeed = = nullptr ) {
2015-01-19 20:27:13 -04:00
// not an airspeed capable vehicle
return true ;
}
2017-11-03 05:26:02 -03:00
for ( uint8_t i = 0 ; i < AIRSPEED_MAX_SENSORS ; i + + ) {
if ( airspeed - > enabled ( i ) & & airspeed - > use ( i ) & & ! airspeed - > healthy ( i ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_AIRSPEED , report , " Airspeed[%s] not healthy " , i ) ;
2017-11-03 05:26:02 -03:00
return false ;
2015-01-19 20:27:13 -04:00
}
}
}
return true ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : logging_checks ( bool report )
2015-02-06 03:38:53 -04:00
{
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_LOGGING ) ) {
2016-11-05 19:05:36 -03:00
if ( DataFlash_Class : : instance ( ) - > logging_failed ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_LOGGING , report , " Logging failed " ) ;
2016-11-05 20:23:14 -03:00
return false ;
2016-11-05 19:05:36 -03:00
}
if ( ! DataFlash_Class : : instance ( ) - > CardInserted ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_LOGGING , report , " No SD card " ) ;
2015-02-06 03:38:53 -04:00
return false ;
}
}
return true ;
}
2017-07-27 01:16:38 -03:00
bool AP_Arming : : ins_accels_consistent ( const AP_InertialSensor & ins )
{
2018-06-15 20:06:53 -03:00
const uint8_t accel_count = ins . get_accel_count ( ) ;
if ( accel_count < = 1 ) {
2017-07-27 01:16:38 -03:00
return true ;
}
const Vector3f & prime_accel_vec = ins . get_accel ( ) ;
2018-06-15 19:46:31 -03:00
const uint32_t now = AP_HAL : : millis ( ) ;
2018-06-15 20:06:53 -03:00
for ( uint8_t i = 0 ; i < accel_count ; i + + ) {
2017-07-27 01:16:38 -03:00
if ( ! ins . use_accel ( i ) ) {
continue ;
}
// get next accel vector
const Vector3f & accel_vec = ins . get_accel ( i ) ;
Vector3f vec_diff = accel_vec - prime_accel_vec ;
// allow for user-defined difference, typically 0.75 m/s/s. Has to pass in last 10 seconds
float threshold = accel_error_threshold ;
if ( i > = 2 ) {
/*
we allow for a higher threshold for IMU3 as it
runs at a different temperature to IMU1 / IMU2 ,
and is not used for accel data in the EKF
*/
threshold * = 3 ;
}
// EKF is less sensitive to Z-axis error
vec_diff . z * = 0.5f ;
if ( vec_diff . length ( ) < = threshold ) {
2018-06-15 19:46:31 -03:00
last_accel_pass_ms [ i ] = now ;
2017-07-27 01:16:38 -03:00
}
2018-06-15 19:46:31 -03:00
if ( now - last_accel_pass_ms [ i ] > 10000 ) {
2017-07-27 01:16:38 -03:00
return false ;
}
}
return true ;
}
2017-07-27 01:25:06 -03:00
bool AP_Arming : : ins_gyros_consistent ( const AP_InertialSensor & ins )
{
2018-06-15 20:06:53 -03:00
const uint8_t gyro_count = ins . get_gyro_count ( ) ;
if ( gyro_count < = 1 ) {
2017-07-27 01:25:06 -03:00
return true ;
}
const Vector3f & prime_gyro_vec = ins . get_gyro ( ) ;
2018-06-15 19:46:31 -03:00
const uint32_t now = AP_HAL : : millis ( ) ;
2018-06-15 20:06:53 -03:00
for ( uint8_t i = 0 ; i < gyro_count ; i + + ) {
2017-07-27 01:25:06 -03:00
if ( ! ins . use_gyro ( i ) ) {
continue ;
}
// get next gyro vector
const Vector3f & gyro_vec = ins . get_gyro ( i ) ;
Vector3f vec_diff = gyro_vec - prime_gyro_vec ;
// allow for up to 5 degrees/s difference. Pass if it has
// been OK in last 10 seconds
if ( vec_diff . length ( ) < = radians ( 5 ) ) {
2018-06-15 19:46:31 -03:00
last_gyro_pass_ms [ i ] = now ;
2017-07-27 01:25:06 -03:00
}
2018-06-15 19:46:31 -03:00
if ( now - last_gyro_pass_ms [ i ] > 10000 ) {
2017-07-27 01:25:06 -03:00
return false ;
}
}
return true ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : ins_checks ( bool report )
2015-01-19 20:27:13 -04:00
{
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_INS ) ) {
2018-03-10 05:35:13 -04:00
const AP_InertialSensor & ins = AP : : ins ( ) ;
2015-10-12 02:29:27 -03:00
if ( ! ins . get_gyro_health_all ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_INS , report , " Gyros not healthy " ) ;
2015-01-20 04:47:15 -04:00
return false ;
}
2015-09-17 09:33:41 -03:00
if ( ! ins . gyro_calibrated_ok_all ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_INS , report , " Gyros not calibrated " ) ;
2015-01-20 04:47:15 -04:00
return false ;
}
2015-10-12 02:29:27 -03:00
if ( ! ins . get_accel_health_all ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_INS , report , " Accels not healthy " ) ;
2015-01-19 20:27:13 -04:00
return false ;
}
2015-05-12 03:19:29 -03:00
if ( ! ins . accel_calibrated_ok_all ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_INS , report , " 3D Accel calibration needed " ) ;
2015-01-31 22:31:59 -04:00
return false ;
}
2015-12-29 00:33:40 -04:00
//check if accelerometers have calibrated and require reboot
if ( ins . accel_cal_requires_reboot ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_INS , report , " Accels calibrated requires reboot " ) ;
2015-12-29 00:33:40 -04:00
return false ;
}
2015-10-14 12:44:35 -03:00
2015-01-19 20:27:13 -04:00
// check all accelerometers point in roughly same direction
2017-07-27 01:16:38 -03:00
if ( ! ins_accels_consistent ( ins ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_INS , report , " Accels inconsistent " ) ;
2017-07-27 01:16:38 -03:00
return false ;
2015-01-19 20:27:13 -04:00
}
// check all gyros are giving consistent readings
2017-07-27 01:25:06 -03:00
if ( ! ins_gyros_consistent ( ins ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_INS , report , " Gyros inconsistent " ) ;
2017-07-27 01:25:06 -03:00
return false ;
2015-01-19 20:27:13 -04:00
}
}
return true ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : compass_checks ( bool report )
2013-12-11 02:02:25 -04:00
{
if ( ( checks_to_perform ) & ARMING_CHECK_ALL | |
( checks_to_perform ) & ARMING_CHECK_COMPASS ) {
2013-11-27 22:18:14 -04:00
2018-06-25 00:42:39 -03:00
Compass & _compass = AP : : compass ( ) ;
2018-06-21 22:07:34 -03:00
// avoid Compass::use_for_yaw(void) as it implicitly calls healthy() which can
// incorrectly skip the remaining checks, pass the primary instance directly
if ( ! _compass . use_for_yaw ( _compass . get_primary ( ) ) ) {
2015-01-19 20:33:39 -04:00
// compass use is disabled
return true ;
}
2014-07-10 10:47:59 -03:00
if ( ! _compass . healthy ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_COMPASS , report , " Compass not healthy " ) ;
2013-11-27 22:18:14 -04:00
return false ;
}
// check compass learning is on or offsets have been set
2014-07-10 10:47:59 -03:00
if ( ! _compass . learn_offsets_enabled ( ) & & ! _compass . configured ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_COMPASS , report , " Compass not calibrated " ) ;
2013-11-27 22:18:14 -04:00
return false ;
}
2015-01-19 20:27:13 -04:00
2015-08-27 23:44:33 -03:00
//check if compass is calibrating
2015-10-12 02:29:27 -03:00
if ( _compass . is_calibrating ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_COMPASS , report , " Compass calibration running " ) ;
2015-08-27 23:44:33 -03:00
return false ;
}
//check if compass has calibrated and requires reboot
2015-10-12 02:29:27 -03:00
if ( _compass . compass_cal_requires_reboot ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_COMPASS , report , " Compass calibrated requires reboot " ) ;
2015-08-27 23:44:33 -03:00
return false ;
}
2015-01-19 20:27:13 -04:00
// check for unreasonable compass offsets
2015-09-28 16:56:17 -03:00
Vector3f offsets = _compass . get_offsets ( ) ;
2017-04-03 19:38:36 -03:00
if ( offsets . length ( ) > _compass . get_offsets_max ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_COMPASS , report , " Compass offsets too high " ) ;
2015-01-19 20:27:13 -04:00
return false ;
}
// check for unreasonable mag field length
2015-09-28 16:56:17 -03:00
float mag_field = _compass . get_field ( ) . length ( ) ;
2015-10-16 00:09:39 -03:00
if ( mag_field > AP_ARMING_COMPASS_MAGFIELD_MAX | | mag_field < AP_ARMING_COMPASS_MAGFIELD_MIN ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_COMPASS , report , " Check mag field " ) ;
2015-01-19 20:27:13 -04:00
return false ;
}
2015-10-16 00:09:39 -03:00
// check all compasses point in roughly same direction
if ( ! _compass . consistent ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_COMPASS , report , " Compasses inconsistent " ) ;
2015-10-16 00:09:39 -03:00
return false ;
}
2013-11-27 22:18:14 -04:00
}
return true ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : gps_checks ( bool report )
2013-12-11 02:02:25 -04:00
{
2017-10-25 00:59:05 -03:00
const AP_GPS & gps = AP : : gps ( ) ;
2016-02-02 03:45:41 -04:00
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | | ( checks_to_perform & ARMING_CHECK_GPS ) ) {
2013-11-27 22:18:14 -04:00
//GPS OK?
2018-03-15 22:06:04 -03:00
if ( ! AP : : ahrs ( ) . home_is_set ( ) | |
2015-03-12 23:03:04 -03:00
gps . status ( ) < AP_GPS : : GPS_OK_FIX_3D ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_GPS , report , " Bad GPS Position " ) ;
2013-11-27 22:18:14 -04:00
return false ;
2015-10-12 02:29:27 -03:00
}
2017-07-08 20:07:24 -03:00
//GPS update rate acceptable
if ( ! gps . is_healthy ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_GPS , report , " GPS is not healthy " ) ;
2017-07-08 20:07:24 -03:00
return false ;
}
2017-03-08 20:47:57 -04:00
2017-08-29 17:33:33 -03:00
// check GPSs are within 50m of each other and that blending is healthy
2017-03-08 20:47:57 -04:00
float distance_m ;
if ( ! gps . all_consistent ( distance_m ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_GPS , report , " GPS positions differ by %4.1fm " ,
( double ) distance_m ) ;
2017-03-08 20:47:57 -04:00
return false ;
}
2017-03-10 04:12:46 -04:00
if ( ! gps . blend_health_check ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_GPS , report , " GPS blending unhealthy " ) ;
2017-03-08 20:47:57 -04:00
return false ;
}
2017-09-18 00:14:52 -03:00
// check AHRS and GPS are within 10m of each other
2017-10-25 00:59:05 -03:00
Location gps_loc = gps . location ( ) ;
2017-09-18 00:14:52 -03:00
Location ahrs_loc ;
2018-06-25 00:42:39 -03:00
if ( AP : : ahrs ( ) . get_position ( ahrs_loc ) ) {
2018-05-11 01:03:06 -03:00
const float distance = location_diff ( gps_loc , ahrs_loc ) . length ( ) ;
2017-09-18 00:14:52 -03:00
if ( distance > AP_ARMING_AHRS_GPS_ERROR_MAX ) {
2018-08-25 20:26:48 -03:00
check_failed ( ARMING_CHECK_GPS , report , " GPS and AHRS differ by %4.1fm " , ( double ) distance ) ;
2017-09-18 00:14:52 -03:00
return false ;
}
}
2017-03-08 20:47:57 -04:00
}
2017-08-29 17:33:33 -03:00
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | | ( checks_to_perform & ARMING_CHECK_GPS_CONFIG ) ) {
uint8_t first_unconfigured = gps . first_unconfigured_gps ( ) ;
if ( first_unconfigured ! = AP_GPS : : GPS_ALL_CONFIGURED ) {
2018-08-25 20:26:48 -03:00
check_failed ( ARMING_CHECK_GPS_CONFIG ,
report ,
" GPS %d failing configuration checks " ,
first_unconfigured + 1 ) ;
2017-08-29 17:33:33 -03:00
if ( report ) {
gps . broadcast_first_configuration_failure_reason ( ) ;
}
return false ;
}
}
2013-11-27 22:18:14 -04:00
return true ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : battery_checks ( bool report )
2013-12-11 02:02:25 -04:00
{
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_BATTERY ) ) {
2013-11-27 22:18:14 -04:00
2018-06-25 00:42:39 -03:00
const AP_BattMonitor & _battery = AP : : battery ( ) ;
2013-11-27 22:18:14 -04:00
if ( AP_Notify : : flags . failsafe_battery ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_BATTERY , report , " Battery failsafe on " ) ;
2013-11-27 22:18:14 -04:00
return false ;
}
2017-07-26 07:56:31 -03:00
for ( uint8_t i = 0 ; i < _battery . num_instances ( ) ; i + + ) {
2016-02-09 19:31:12 -04:00
if ( ( _min_voltage [ i ] > 0.0f ) & & ( _battery . voltage ( i ) < _min_voltage [ i ] ) ) {
2018-08-25 20:26:48 -03:00
check_failed ( ARMING_CHECK_BATTERY , report , " Battery %d voltage %.1f below minimum %.1f " ,
2016-03-14 13:04:52 -03:00
i + 1 ,
( double ) _battery . voltage ( i ) ,
2017-08-01 00:09:27 -03:00
( double ) _min_voltage [ i ] ) ;
2016-02-09 19:31:12 -04:00
return false ;
}
}
}
2013-11-27 22:18:14 -04:00
return true ;
}
2014-01-23 06:39:55 -04:00
bool AP_Arming : : hardware_safety_check ( bool report )
2013-12-11 02:02:25 -04:00
{
2015-12-21 02:34:00 -04:00
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_SWITCH ) ) {
// check if safety switch has been pushed
if ( hal . util - > safety_switch_state ( ) = = AP_HAL : : Util : : SAFETY_DISARMED ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_SWITCH , report , " Hardware safety switch " ) ;
2015-12-21 02:34:00 -04:00
return false ;
}
2013-11-27 22:18:14 -04:00
}
return true ;
}
2017-09-04 01:16:12 -03:00
bool AP_Arming : : rc_calibration_checks ( bool report )
{
2018-04-19 16:59:35 -03:00
bool check_passed = true ;
2018-07-22 18:05:23 -03:00
const uint8_t num_channels = RC_Channels : : get_valid_channel_count ( ) ;
2018-04-19 16:59:35 -03:00
for ( uint8_t i = 0 ; i < NUM_RC_CHANNELS ; i + + ) {
2018-04-26 08:59:17 -03:00
const RC_Channel * ch = rc ( ) . channel ( i ) ;
2018-04-19 16:59:35 -03:00
if ( ch = = nullptr ) {
continue ;
}
2018-07-22 18:05:23 -03:00
if ( i > = num_channels & & ! ( ch - > has_override ( ) ) ) {
continue ;
}
2018-04-19 16:59:35 -03:00
const uint16_t trim = ch - > get_radio_trim ( ) ;
if ( ch - > get_radio_min ( ) > trim ) {
2018-08-25 20:26:48 -03:00
check_failed ( ARMING_CHECK_RC , report , " RC%d minimum is greater than trim " , i + 1 ) ;
2018-04-19 16:59:35 -03:00
check_passed = false ;
}
if ( ch - > get_radio_max ( ) < trim ) {
2018-08-25 20:26:48 -03:00
check_failed ( ARMING_CHECK_RC , report , " RC%d maximum is less than trim " , i + 1 ) ;
2018-04-19 16:59:35 -03:00
check_passed = false ;
}
}
return check_passed ;
2017-09-04 01:16:12 -03:00
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : manual_transmitter_checks ( bool report )
2013-12-11 02:02:25 -04:00
{
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_RC ) ) {
2013-11-27 22:18:14 -04:00
if ( AP_Notify : : flags . failsafe_radio ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_RC , report , " Radio failsafe on " ) ;
2013-11-27 22:18:14 -04:00
return false ;
}
2017-09-04 01:16:12 -03:00
if ( ! rc_calibration_checks ( report ) ) {
return false ;
}
2013-11-27 22:18:14 -04:00
}
return true ;
}
2018-04-19 17:10:39 -03:00
bool AP_Arming : : servo_checks ( bool report ) const
{
bool check_passed = true ;
for ( uint8_t i = 0 ; i < NUM_SERVO_CHANNELS ; i + + ) {
const SRV_Channel * ch = SRV_Channels : : srv_channel ( i ) ;
if ( ch = = nullptr | | ch - > get_function ( ) = = SRV_Channel : : k_none ) {
continue ;
}
const uint16_t trim = ch - > get_trim ( ) ;
if ( ch - > get_output_min ( ) > trim ) {
2018-08-25 20:26:48 -03:00
check_failed ( ARMING_CHECK_NONE , report , " SERVO%d minimum is greater than trim " , i + 1 ) ;
2018-04-19 17:10:39 -03:00
check_passed = false ;
}
if ( ch - > get_output_max ( ) < trim ) {
2018-08-25 20:26:48 -03:00
check_failed ( ARMING_CHECK_NONE , report , " SERVO%d maximum is less than trim " , i + 1 ) ;
2018-04-19 17:10:39 -03:00
check_passed = false ;
}
}
return check_passed ;
}
2015-10-16 00:13:53 -03:00
bool AP_Arming : : board_voltage_checks ( bool report )
{
2017-07-15 04:38:37 -03:00
# if HAL_HAVE_BOARD_VOLTAGE
2015-10-16 00:13:53 -03:00
// check board voltage
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | | ( checks_to_perform & ARMING_CHECK_VOLTAGE ) ) {
2017-07-15 04:38:37 -03:00
if ( ( ( hal . analogin - > board_voltage ( ) < AP_ARMING_BOARD_VOLTAGE_MIN ) | | ( hal . analogin - > board_voltage ( ) > AP_ARMING_BOARD_VOLTAGE_MAX ) ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_VOLTAGE , report , " Check board voltage " ) ;
2015-10-16 00:13:53 -03:00
return false ;
}
}
2017-07-15 04:38:37 -03:00
# endif
2015-10-16 00:13:53 -03:00
return true ;
}
2018-06-29 20:23:08 -03:00
/*
check base system operations
*/
bool AP_Arming : : system_checks ( bool report )
{
2018-06-30 06:11:34 -03:00
if ( check_enabled ( ARMING_CHECK_SYSTEM ) ) {
2018-06-29 20:23:08 -03:00
if ( ! hal . storage - > healthy ( ) ) {
check_failed ( ARMING_CHECK_SYSTEM , report , " Param storage failed " ) ;
2018-08-11 13:37:17 -03:00
return false ;
2018-06-29 20:23:08 -03:00
}
}
return true ;
}
2015-10-12 02:29:27 -03:00
bool AP_Arming : : pre_arm_checks ( bool report )
2013-12-11 02:02:25 -04:00
{
2016-12-28 01:41:21 -04:00
# if !APM_BUILD_TYPE(APM_BUILD_ArduCopter)
2018-06-24 23:05:56 -03:00
if ( armed | | require = = NO ) {
2014-01-23 06:39:55 -04:00
// if we are already armed or don't need any arming checks
// then skip the checks
return true ;
}
2016-12-28 01:41:21 -04:00
# endif
2014-01-23 06:39:55 -04:00
2016-12-03 08:30:46 -04:00
return hardware_safety_check ( report )
& barometer_checks ( report )
& ins_checks ( report )
& compass_checks ( report )
& gps_checks ( report )
& battery_checks ( report )
& logging_checks ( report )
& manual_transmitter_checks ( report )
2018-04-19 17:10:39 -03:00
& servo_checks ( report )
2018-06-29 20:23:08 -03:00
& board_voltage_checks ( report )
& system_checks ( report ) ;
2013-11-27 22:18:14 -04:00
}
2018-06-24 23:05:56 -03:00
bool AP_Arming : : arm_checks ( ArmingMethod method )
2016-11-05 20:23:14 -03:00
{
2017-10-19 22:16:37 -03:00
// ensure the GPS drivers are ready on any final changes
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_GPS_CONFIG ) ) {
2017-10-25 00:59:05 -03:00
if ( ! AP : : gps ( ) . prepare_for_arming ( ) ) {
2017-10-19 22:16:37 -03:00
return false ;
}
}
2018-06-29 20:23:08 -03:00
2017-06-30 09:31:08 -03:00
// note that this will prepare DataFlash to start logging
// so should be the last check to be done before arming
2016-11-05 20:23:14 -03:00
if ( ( checks_to_perform & ARMING_CHECK_ALL ) | |
( checks_to_perform & ARMING_CHECK_LOGGING ) ) {
2017-06-30 09:31:08 -03:00
DataFlash_Class * df = DataFlash_Class : : instance ( ) ;
df - > PrepForArming ( ) ;
if ( ! df - > logging_started ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_LOGGING , true , " Logging not started " ) ;
2016-11-05 20:23:14 -03:00
return false ;
}
}
return true ;
}
2016-05-12 13:51:51 -03:00
//returns true if arming occurred successfully
2018-06-24 23:05:56 -03:00
bool AP_Arming : : arm ( AP_Arming : : ArmingMethod method , const bool do_arming_checks )
2013-12-11 02:02:25 -04:00
{
2016-12-28 01:41:21 -04:00
# if APM_BUILD_TYPE(APM_BUILD_ArduCopter)
// Copter should never use this function
return false ;
# else
2013-11-27 22:18:14 -04:00
if ( armed ) { //already armed
return false ;
}
//are arming checks disabled?
2016-09-27 05:08:41 -03:00
if ( ! do_arming_checks | | checks_to_perform = = ARMING_CHECK_NONE ) {
2013-11-27 22:18:14 -04:00
armed = true ;
2017-07-09 01:06:18 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Throttle armed " ) ;
2013-11-27 22:18:14 -04:00
return true ;
}
2016-11-05 20:23:14 -03:00
if ( pre_arm_checks ( true ) & & arm_checks ( method ) ) {
2013-11-27 22:18:14 -04:00
armed = true ;
2017-07-09 01:06:18 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Throttle armed " ) ;
2013-11-27 22:18:14 -04:00
//TODO: Log motor arming to the dataflash
//Can't do this from this class until there is a unified logging library
} else {
armed = false ;
}
return armed ;
2016-12-28 01:41:21 -04:00
# endif
2013-11-27 22:18:14 -04:00
}
//returns true if disarming occurred successfully
2013-12-11 02:02:25 -04:00
bool AP_Arming : : disarm ( )
{
2016-12-28 01:41:21 -04:00
# if APM_BUILD_TYPE(APM_BUILD_ArduCopter)
// Copter should never use this function
return false ;
# else
2015-10-12 02:29:27 -03:00
if ( ! armed ) { // already disarmed
2013-11-27 22:18:14 -04:00
return false ;
}
armed = false ;
2017-07-09 01:06:18 -03:00
gcs ( ) . send_text ( MAV_SEVERITY_INFO , " Throttle disarmed " ) ;
2013-11-27 22:18:14 -04:00
//TODO: Log motor disarming to the dataflash
//Can't do this from this class until there is a unified logging library.
return true ;
2016-12-28 01:41:21 -04:00
# endif
2013-11-27 22:18:14 -04:00
}
2013-12-11 02:02:25 -04:00
AP_Arming : : ArmingRequired AP_Arming : : arming_required ( )
{
return ( AP_Arming : : ArmingRequired ) require . get ( ) ;
2013-11-27 22:18:14 -04:00
}
2017-08-09 20:11:22 -03:00
// Copter and sub share the same RC input limits
2017-08-14 14:53:20 -03:00
// Copter checks that min and max have been configured by default, Sub does not
bool AP_Arming : : rc_checks_copter_sub ( const bool display_failure , const RC_Channel * channels [ 4 ] , const bool check_min_max ) const
2017-08-09 20:11:22 -03:00
{
// set rc-checks to success if RC checks are disabled
if ( ( checks_to_perform ! = ARMING_CHECK_ALL ) & & ! ( checks_to_perform & ARMING_CHECK_RC ) ) {
return true ;
}
bool ret = true ;
const char * channel_names [ ] = { " Roll " , " Pitch " , " Throttle " , " Yaw " } ;
for ( uint8_t i = 0 ; i < ARRAY_SIZE ( channel_names ) ; i + + ) {
const RC_Channel * channel = channels [ i ] ;
const char * channel_name = channel_names [ i ] ;
// check if radio has been calibrated
if ( channel - > get_radio_min ( ) > 1300 ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_RC , display_failure , " %s radio min too high " , channel_name ) ;
2017-08-09 20:11:22 -03:00
ret = false ;
}
if ( channel - > get_radio_max ( ) < 1700 ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_RC , display_failure , " %s radio max too low " , channel_name ) ;
2017-08-09 20:11:22 -03:00
ret = false ;
}
2017-08-09 20:14:31 -03:00
bool fail = true ;
2017-08-09 20:11:22 -03:00
if ( i = = 2 ) {
// skip checking trim for throttle as older code did not check it
2017-08-09 20:14:31 -03:00
fail = false ;
2017-08-09 20:11:22 -03:00
}
if ( channel - > get_radio_trim ( ) < channel - > get_radio_min ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_RC , display_failure , " %s radio trim below min " , channel_name ) ;
2017-08-09 20:14:31 -03:00
if ( fail ) {
ret = false ;
}
2017-08-09 20:11:22 -03:00
}
if ( channel - > get_radio_trim ( ) > channel - > get_radio_max ( ) ) {
2017-08-01 00:09:27 -03:00
check_failed ( ARMING_CHECK_RC , display_failure , " %s radio trim above max " , channel_name ) ;
2017-08-09 20:14:31 -03:00
if ( fail ) {
ret = false ;
}
2017-08-09 20:11:22 -03:00
}
}
return ret ;
}