2015-08-11 03:28:41 -03:00
# include "AC_Fence.h"
2019-02-14 02:40:09 -04:00
2022-07-19 08:32:28 -03:00
# if AP_FENCE_ENABLED
2022-03-04 12:42:09 -04:00
2022-03-04 16:25:54 -04:00
# include <AP_Vehicle/AP_Vehicle_Type.h>
# ifndef AC_FENCE_DUMMY_METHODS_ENABLED
2022-07-25 13:51:32 -03:00
# define AC_FENCE_DUMMY_METHODS_ENABLED (!(APM_BUILD_TYPE(APM_BUILD_Rover) | APM_BUILD_COPTER_OR_HELI | APM_BUILD_TYPE(APM_BUILD_ArduPlane) | APM_BUILD_TYPE(APM_BUILD_ArduSub) | (AP_FENCE_ENABLED == 1)))
2022-03-04 16:25:54 -04:00
# endif
# if !AC_FENCE_DUMMY_METHODS_ENABLED
2019-02-14 02:40:09 -04:00
# include <AP_AHRS/AP_AHRS.h>
# include <AP_HAL/AP_HAL.h>
2020-06-01 23:27:28 -03:00
# include <AP_Logger/AP_Logger.h>
2022-08-14 23:17:34 -03:00
# include <GCS_MAVLink/GCS.h>
2013-04-26 06:47:07 -03:00
extern const AP_HAL : : HAL & hal ;
2020-03-26 21:51:14 -03:00
# if APM_BUILD_TYPE(APM_BUILD_Rover)
2018-10-26 00:29:02 -03:00
# define AC_FENCE_TYPE_DEFAULT AC_FENCE_TYPE_CIRCLE | AC_FENCE_TYPE_POLYGON
2021-03-03 07:49:47 -04:00
# elif APM_BUILD_TYPE(APM_BUILD_ArduPlane)
# define AC_FENCE_TYPE_DEFAULT AC_FENCE_TYPE_POLYGON
2018-10-26 00:29:02 -03:00
# else
# define AC_FENCE_TYPE_DEFAULT AC_FENCE_TYPE_ALT_MAX | AC_FENCE_TYPE_CIRCLE | AC_FENCE_TYPE_POLYGON
# endif
2022-08-06 17:43:38 -03:00
// default boundaries
# define AC_FENCE_ALT_MAX_DEFAULT 100.0f // default max altitude is 100m
# define AC_FENCE_ALT_MIN_DEFAULT -10.0f // default maximum depth in meters
# define AC_FENCE_CIRCLE_RADIUS_DEFAULT 300.0f // default circular fence radius is 300m
# define AC_FENCE_ALT_MAX_BACKUP_DISTANCE 20.0f // after fence is broken we recreate the fence 20m further up
# define AC_FENCE_ALT_MIN_BACKUP_DISTANCE 20.0f // after fence is broken we recreate the fence 20m further down
# define AC_FENCE_MARGIN_DEFAULT 2.0f // default distance in meters that autopilot's should maintain from the fence to avoid a breach
# define AC_FENCE_MANUAL_RECOVERY_TIME_MIN 10000 // pilot has 10seconds to recover during which time the autopilot will not attempt to re-take control
# if APM_BUILD_TYPE(APM_BUILD_ArduPlane)
2023-08-18 15:30:22 -03:00
# define AC_FENCE_CIRCLE_RADIUS_BACKUP_DISTANCE 100.0 // after fence is broken we recreate the fence 100m further out
2022-08-06 17:43:38 -03:00
# else
# define AC_FENCE_CIRCLE_RADIUS_BACKUP_DISTANCE 20.0 // after fence is broken we recreate the fence 20m further out
# endif
2015-10-25 14:03:46 -03:00
const AP_Param : : GroupInfo AC_Fence : : var_info [ ] = {
2013-04-26 06:47:07 -03:00
// @Param: ENABLE
// @DisplayName: Fence enable/disable
// @Description: Allows you to enable (1) or disable (0) the fence functionality
// @Values: 0:Disabled,1:Enabled
// @User: Standard
2021-01-06 08:13:57 -04:00
AP_GROUPINFO ( " ENABLE " , 0 , AC_Fence , _enabled , 0 ) ,
2013-04-26 06:47:07 -03:00
// @Param: TYPE
// @DisplayName: Fence Type
// @Description: Enabled fence types held as bitmask
2023-07-22 03:40:57 -03:00
// @Bitmask{Rover}: 1:Circle Centered on Home,2:Inclusion/Exclusion Circles+Polygons
// @Bitmask{Copter, Plane, Sub}: 0:Max altitude,1:Circle Centered on Home,2:Inclusion/Exclusion Circles+Polygons,3:Min altitude
2013-04-26 06:47:07 -03:00
// @User: Standard
2018-10-26 00:29:02 -03:00
AP_GROUPINFO ( " TYPE " , 1 , AC_Fence , _enabled_fences , AC_FENCE_TYPE_DEFAULT ) ,
2013-04-26 06:47:07 -03:00
// @Param: ACTION
2013-11-26 09:18:05 -04:00
// @DisplayName: Fence Action
// @Description: What action should be taken when fence is breached
2021-01-30 22:34:40 -04:00
// @Values{Copter}: 0:Report Only,1:RTL or Land,2:Always Land,3:SmartRTL or RTL or Land,4:Brake or Land,5:SmartRTL or Land
2021-04-26 00:23:33 -03:00
// @Values{Rover}: 0:Report Only,1:RTL or Hold,2:Hold,3:SmartRTL or RTL or Hold,4:SmartRTL or Hold
2020-09-10 03:28:09 -03:00
// @Values{Plane}: 0:Report Only,1:RTL,6:Guided,7:GuidedThrottlePass
2019-01-24 06:00:42 -04:00
// @Values: 0:Report Only,1:RTL or Land
2013-04-26 06:47:07 -03:00
// @User: Standard
AP_GROUPINFO ( " ACTION " , 2 , AC_Fence , _action , AC_FENCE_ACTION_RTL_AND_LAND ) ,
2020-09-10 03:28:09 -03:00
// @Param{Copter, Plane, Sub}: ALT_MAX
2013-04-26 06:47:07 -03:00
// @DisplayName: Fence Maximum Altitude
// @Description: Maximum altitude allowed before geofence triggers
2017-05-02 10:38:01 -03:00
// @Units: m
2013-05-01 05:05:04 -03:00
// @Range: 10 1000
// @Increment: 1
2013-04-26 06:47:07 -03:00
// @User: Standard
2020-09-10 03:28:09 -03:00
AP_GROUPINFO_FRAME ( " ALT_MAX " , 3 , AC_Fence , _alt_max , AC_FENCE_ALT_MAX_DEFAULT , AP_PARAM_FRAME_COPTER | AP_PARAM_FRAME_SUB | AP_PARAM_FRAME_TRICOPTER | AP_PARAM_FRAME_HELI | AP_PARAM_FRAME_PLANE ) ,
2013-04-26 06:47:07 -03:00
// @Param: RADIUS
// @DisplayName: Circular Fence Radius
2013-05-01 05:05:04 -03:00
// @Description: Circle fence radius which when breached will cause an RTL
2017-05-02 10:38:01 -03:00
// @Units: m
2013-07-26 22:28:33 -03:00
// @Range: 30 10000
2013-04-26 06:47:07 -03:00
// @User: Standard
2013-05-01 05:05:04 -03:00
AP_GROUPINFO ( " RADIUS " , 4 , AC_Fence , _circle_radius , AC_FENCE_CIRCLE_RADIUS_DEFAULT ) ,
2013-08-15 04:05:38 -03:00
// @Param: MARGIN
// @DisplayName: Fence Margin
// @Description: Distance that autopilot's should maintain from the fence to avoid a breach
2017-05-02 10:38:01 -03:00
// @Units: m
2013-08-15 04:05:38 -03:00
// @Range: 1 10
// @User: Standard
AP_GROUPINFO ( " MARGIN " , 5 , AC_Fence , _margin , AC_FENCE_MARGIN_DEFAULT ) ,
2016-06-23 03:24:48 -03:00
// @Param: TOTAL
// @DisplayName: Fence polygon point total
// @Description: Number of polygon points saved in eeprom (do not update manually)
// @Range: 1 20
// @User: Standard
AP_GROUPINFO ( " TOTAL " , 6 , AC_Fence , _total , 0 ) ,
2020-09-10 03:28:09 -03:00
// @Param{Copter, Plane, Sub}: ALT_MIN
2017-02-03 00:18:25 -04:00
// @DisplayName: Fence Minimum Altitude
// @Description: Minimum altitude allowed before geofence triggers
2017-05-02 10:38:01 -03:00
// @Units: m
2017-02-03 00:18:25 -04:00
// @Range: -100 100
// @Increment: 1
// @User: Standard
2017-07-17 05:39:26 -03:00
AP_GROUPINFO_FRAME ( " ALT_MIN " , 7 , AC_Fence , _alt_min , AC_FENCE_ALT_MIN_DEFAULT , AP_PARAM_FRAME_COPTER | AP_PARAM_FRAME_SUB | AP_PARAM_FRAME_TRICOPTER | AP_PARAM_FRAME_HELI | AP_PARAM_FRAME_PLANE ) ,
2020-09-10 03:28:09 -03:00
// @Param{Plane}: RET_RALLY
// @DisplayName: Fence Return to Rally
2021-01-06 08:15:59 -04:00
// @Description: Should the vehicle return to fence return point or rally point
2020-09-10 03:28:09 -03:00
// @Values: 0:Fence Return Point,1:Nearest Rally Point
// @Range: 0 1
// @Increment: 1
// @User: Standard
AP_GROUPINFO_FRAME ( " RET_RALLY " , 8 , AC_Fence , _ret_rally , 0 , AP_PARAM_FRAME_PLANE ) ,
// @Param{Plane}: RET_ALT
// @DisplayName: Fence Return Altitude
// @Description: Altitude the vehicle will transit to when a fence breach occurs
// @Units: m
// @Range: 0 32767
// @Increment: 1
// @User: Standard
AP_GROUPINFO_FRAME ( " RET_ALT " , 9 , AC_Fence , _ret_altitude , 0.0f , AP_PARAM_FRAME_PLANE ) ,
2022-04-27 05:06:25 -03:00
// @Param{Plane}: AUTOENABLE
2020-09-10 03:28:09 -03:00
// @DisplayName: Fence Auto-Enable
2023-12-21 17:17:59 -04:00
// @Description: Auto-enable of fences. AutoEnableOnTakeoff enables all configured fences after autotakeoffs reach altitude. During autolandings the fences will be disabled. AutoEnableDisableFloorOnLanding enables all configured fences after autotakeoffs reach altitude. During autolandings only the Minimum Altitude fence will be disabled. AutoEnableOnlyWhenArmed enables all configured fences, but no fences are disabled during autolandings. However, fence breaches are ignored while executing prior breach recovery actions which may include autolandings.
2022-04-27 05:06:25 -03:00
// @Values: 0:AutoEnableOff,1:AutoEnableOnTakeoff,2:AutoEnableDisableFloorOnLanding,3:AutoEnableOnlyWhenArmed
2020-09-10 03:28:09 -03:00
// @Range: 0 3
// @Increment: 1
// @User: Standard
2021-03-03 07:49:47 -04:00
AP_GROUPINFO_FRAME ( " AUTOENABLE " , 10 , AC_Fence , _auto_enabled , static_cast < uint8_t > ( AutoEnable : : ALWAYS_DISABLED ) , AP_PARAM_FRAME_PLANE ) ,
2017-02-03 00:18:25 -04:00
2022-08-12 16:32:28 -03:00
// @Param{Plane}: OPTIONS
// @DisplayName: Fence options
2023-07-22 19:03:08 -03:00
// @Description: 0:Disable mode change following fence action until fence breach is cleared. When bit 1 is set the allowable flight areas is the union of all polygon and circle fence areas instead of the intersection, which means a fence breach occurs only if you are outside all of the fence areas.
// @Bitmask: 0:Disable mode change following fence action until fence breach is cleared, 1:Allow union of inclusion areas
2022-08-12 16:32:28 -03:00
// @User: Standard
AP_GROUPINFO_FRAME ( " OPTIONS " , 11 , AC_Fence , _options , static_cast < uint16_t > ( OPTIONS : : DISABLE_MODE_CHANGE ) , AP_PARAM_FRAME_PLANE ) ,
2013-04-26 06:47:07 -03:00
AP_GROUPEND
} ;
/// Default constructor.
2019-01-30 20:37:22 -04:00
AC_Fence : : AC_Fence ( )
2013-04-26 06:47:07 -03:00
{
2019-01-30 21:54:13 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
if ( _singleton ! = nullptr ) {
AP_HAL : : panic ( " Fence must be singleton " ) ;
}
# endif
_singleton = this ;
2013-04-26 06:47:07 -03:00
AP_Param : : setup_object_defaults ( this , var_info ) ;
}
2019-08-28 04:22:16 -03:00
/// enable the Fence code generally; a master switch for all fences
2017-07-20 13:42:28 -03:00
void AC_Fence : : enable ( bool value )
{
2020-06-01 23:27:28 -03:00
if ( _enabled & & ! value ) {
AP : : logger ( ) . Write_Event ( LogEvent : : FENCE_DISABLE ) ;
} else if ( ! _enabled & & value ) {
AP : : logger ( ) . Write_Event ( LogEvent : : FENCE_ENABLE ) ;
}
2022-07-05 00:08:55 -03:00
_enabled . set ( value ) ;
2017-07-20 13:42:28 -03:00
if ( ! value ) {
2020-09-10 03:28:09 -03:00
clear_breach ( AC_FENCE_TYPE_ALT_MIN | AC_FENCE_TYPE_ALT_MAX | AC_FENCE_TYPE_CIRCLE | AC_FENCE_TYPE_POLYGON ) ;
2021-01-10 23:08:51 -04:00
disable_floor ( ) ;
2020-09-10 03:28:09 -03:00
} else {
enable_floor ( ) ;
}
}
/// enable/disable fence floor only
void AC_Fence : : enable_floor ( )
{
if ( ! _floor_enabled ) {
// Floor is currently disabled, enable it
AP : : logger ( ) . Write_Event ( LogEvent : : FENCE_FLOOR_ENABLE ) ;
}
_floor_enabled = true ;
}
void AC_Fence : : disable_floor ( )
{
if ( _floor_enabled ) {
// Floor is currently enabled, disable it
AP : : logger ( ) . Write_Event ( LogEvent : : FENCE_FLOOR_DISABLE ) ;
2017-07-20 13:42:28 -03:00
}
2021-01-06 08:15:59 -04:00
_floor_enabled = false ;
2020-09-10 03:28:09 -03:00
clear_breach ( AC_FENCE_TYPE_ALT_MIN ) ;
}
2021-01-13 19:35:48 -04:00
/*
called when an auto - takeoff is complete
*/
void AC_Fence : : auto_enable_fence_after_takeoff ( void )
{
switch ( auto_enabled ( ) ) {
case AC_Fence : : AutoEnable : : ALWAYS_ENABLED :
case AC_Fence : : AutoEnable : : ENABLE_DISABLE_FLOOR_ONLY :
enable ( true ) ;
2021-03-03 08:25:09 -04:00
gcs ( ) . send_text ( MAV_SEVERITY_NOTICE , " Fence enabled (auto enabled) " ) ;
2021-01-13 19:35:48 -04:00
break ;
default :
// fence does not auto-enable in other takeoff conditions
break ;
}
}
/*
called when performing an auto landing
*/
void AC_Fence : : auto_disable_fence_for_landing ( void )
{
switch ( auto_enabled ( ) ) {
case AC_Fence : : AutoEnable : : ALWAYS_ENABLED :
enable ( false ) ;
gcs ( ) . send_text ( MAV_SEVERITY_NOTICE , " Fence disabled (auto disable) " ) ;
break ;
case AC_Fence : : AutoEnable : : ENABLE_DISABLE_FLOOR_ONLY :
disable_floor ( ) ;
gcs ( ) . send_text ( MAV_SEVERITY_NOTICE , " Fence floor disabled (auto disable) " ) ;
break ;
default :
// fence does not auto-disable in other landing conditions
break ;
}
}
2020-09-10 03:28:09 -03:00
bool AC_Fence : : present ( ) const
{
2021-01-06 08:15:59 -04:00
const auto enabled_fences = _enabled_fences . get ( ) ;
2020-12-18 05:08:56 -04:00
// A fence is present if any of the conditions are true.
// * tin can (circle) is enabled
// * min or max alt is enabled
// * polygon fences are enabled and any fence has been uploaded
2021-01-06 08:15:59 -04:00
if ( enabled_fences & AC_FENCE_TYPE_CIRCLE | |
enabled_fences & AC_FENCE_TYPE_ALT_MIN | |
enabled_fences & AC_FENCE_TYPE_ALT_MAX | |
( ( enabled_fences & AC_FENCE_TYPE_POLYGON ) & & _poly_loader . total_fence_count ( ) > 0 ) ) {
2020-12-18 05:08:56 -04:00
return true ;
2020-09-10 03:28:09 -03:00
}
2020-12-18 05:08:56 -04:00
return false ;
2017-07-20 13:42:28 -03:00
}
2013-04-26 06:47:07 -03:00
/// get_enabled_fences - returns bitmask of enabled fences
2013-05-01 05:05:04 -03:00
uint8_t AC_Fence : : get_enabled_fences ( ) const
2013-04-26 06:47:07 -03:00
{
2020-09-10 03:28:09 -03:00
if ( ! _enabled & & ! _auto_enabled ) {
2017-12-15 06:06:56 -04:00
return 0 ;
2013-04-26 06:47:07 -03:00
}
2017-12-15 06:06:56 -04:00
return _enabled_fences ;
2013-04-26 06:47:07 -03:00
}
2017-12-13 22:54:03 -04:00
// additional checks for the polygon fence:
bool AC_Fence : : pre_arm_check_polygon ( const char * & fail_msg ) const
{
if ( ! ( _enabled_fences & AC_FENCE_TYPE_POLYGON ) ) {
// not enabled; all good
return true ;
}
2019-08-28 04:22:16 -03:00
if ( ! _poly_loader . loaded ( ) ) {
fail_msg = " Fences invalid " ;
2017-12-13 22:54:03 -04:00
return false ;
}
2020-07-21 14:00:57 -03:00
if ( ! _poly_loader . check_inclusion_circle_margin ( _margin ) ) {
fail_msg = " Margin is less than inclusion circle radius " ;
return false ;
}
2017-12-13 22:54:03 -04:00
return true ;
}
2017-12-26 22:53:39 -04:00
// additional checks for the circle fence:
bool AC_Fence : : pre_arm_check_circle ( const char * & fail_msg ) const
{
if ( _circle_radius < 0 ) {
fail_msg = " Invalid FENCE_RADIUS value " ;
return false ;
}
2020-07-21 14:00:57 -03:00
if ( _circle_radius < _margin ) {
fail_msg = " FENCE_MARGIN is less than FENCE_RADIUS " ;
return false ;
}
2017-12-26 22:53:39 -04:00
return true ;
}
// additional checks for the alt fence:
bool AC_Fence : : pre_arm_check_alt ( const char * & fail_msg ) const
{
if ( _alt_max < 0.0f ) {
fail_msg = " Invalid FENCE_ALT_MAX value " ;
return false ;
}
2020-09-10 03:28:09 -03:00
if ( _alt_min < - 100.0f ) {
fail_msg = " Invalid FENCE_ALT_MIN value " ;
return false ;
}
2017-12-26 22:53:39 -04:00
return true ;
}
2017-12-13 22:54:03 -04:00
2013-04-26 06:47:07 -03:00
/// pre_arm_check - returns true if all pre-takeoff checks have completed successfully
2017-03-24 01:38:19 -03:00
bool AC_Fence : : pre_arm_check ( const char * & fail_msg ) const
2013-04-26 06:47:07 -03:00
{
2017-03-24 01:38:19 -03:00
fail_msg = nullptr ;
2021-05-18 12:20:49 -03:00
// if fences are enabled but none selected fail pre-arm check
if ( enabled ( ) & & ! present ( ) ) {
fail_msg = " Fences enabled, but none selected " ;
return false ;
}
2013-04-26 06:47:07 -03:00
// if not enabled or not fence set-up always return true
2020-09-10 03:28:09 -03:00
if ( ( ! _enabled & & ! _auto_enabled ) | | ! _enabled_fences ) {
2013-04-26 06:47:07 -03:00
return true ;
}
2017-12-07 19:25:52 -04:00
// if we have horizontal limits enabled, check we can get a
2019-01-30 20:37:22 -04:00
// relative position from the AHRS
2017-12-07 19:25:52 -04:00
if ( ( _enabled_fences & AC_FENCE_TYPE_CIRCLE ) | |
( _enabled_fences & AC_FENCE_TYPE_POLYGON ) ) {
Vector2f position ;
2019-03-05 23:04:58 -04:00
if ( ! AP : : ahrs ( ) . get_relative_position_NE_home ( position ) ) {
2020-07-03 20:29:45 -03:00
fail_msg = " Fence requires position " ;
2017-12-07 19:25:52 -04:00
return false ;
}
2013-04-26 06:47:07 -03:00
}
2017-12-13 22:54:03 -04:00
if ( ! pre_arm_check_polygon ( fail_msg ) ) {
return false ;
}
2017-12-26 22:53:39 -04:00
if ( ! pre_arm_check_circle ( fail_msg ) ) {
return false ;
}
if ( ! pre_arm_check_alt ( fail_msg ) ) {
return false ;
}
2019-08-28 04:22:16 -03:00
// check no limits are currently breached
if ( _breached_fences ) {
fail_msg = " vehicle outside fence " ;
return false ;
}
2017-08-24 06:48:17 -03:00
// validate FENCE_MARGIN parameter range
if ( _margin < 0.0f ) {
fail_msg = " Invalid FENCE_MARGIN value " ;
return false ;
}
if ( _alt_max < _alt_min ) {
fail_msg = " FENCE_ALT_MAX < FENCE_ALT_MIN " ;
return false ;
}
if ( _alt_max - _alt_min < = 2.0f * _margin ) {
fail_msg = " FENCE_MARGIN too big " ;
return false ;
}
2013-04-26 06:47:07 -03:00
// if we got this far everything must be ok
return true ;
}
2019-08-28 04:22:16 -03:00
/// returns true if we have freshly breached the maximum altitude
/// fence; also may set up a fallback fence which, if breached, will
/// cause the altitude fence to be freshly breached
2017-12-15 05:35:22 -04:00
bool AC_Fence : : check_fence_alt_max ( )
2017-12-07 20:53:18 -04:00
{
// altitude fence check
if ( ! ( _enabled_fences & AC_FENCE_TYPE_ALT_MAX ) ) {
// not enabled; no breach
return false ;
}
2019-01-30 20:37:22 -04:00
AP : : ahrs ( ) . get_relative_position_D_home ( _curr_alt ) ;
2017-12-15 05:35:22 -04:00
_curr_alt = - _curr_alt ; // translate Down to Up
2017-12-07 20:53:18 -04:00
// check if we are over the altitude fence
2020-09-10 03:28:09 -03:00
if ( _curr_alt > = _alt_max ) {
2017-12-07 20:53:18 -04:00
// record distance above breach
2017-12-15 05:35:22 -04:00
_alt_max_breach_distance = _curr_alt - _alt_max ;
2017-12-07 20:53:18 -04:00
// check for a new breach or a breach of the backup fence
if ( ! ( _breached_fences & AC_FENCE_TYPE_ALT_MAX ) | |
2017-12-15 05:35:22 -04:00
( ! is_zero ( _alt_max_backup ) & & _curr_alt > = _alt_max_backup ) ) {
2017-12-07 20:53:18 -04:00
// new breach
record_breach ( AC_FENCE_TYPE_ALT_MAX ) ;
// create a backup fence 20m higher up
2017-12-15 05:35:22 -04:00
_alt_max_backup = _curr_alt + AC_FENCE_ALT_MAX_BACKUP_DISTANCE ;
2021-01-06 08:15:59 -04:00
// new breach
2017-12-07 20:53:18 -04:00
return true ;
}
2021-01-06 08:15:59 -04:00
// old breach
2017-12-07 20:53:18 -04:00
return false ;
}
// not breached
2021-01-06 08:15:59 -04:00
// clear max alt breach if present
2017-12-07 20:53:18 -04:00
if ( ( _breached_fences & AC_FENCE_TYPE_ALT_MAX ) ! = 0 ) {
clear_breach ( AC_FENCE_TYPE_ALT_MAX ) ;
_alt_max_backup = 0.0f ;
_alt_max_breach_distance = 0.0f ;
}
return false ;
}
2020-09-10 03:28:09 -03:00
/// returns true if we have freshly breached the minimum altitude
/// fence; also may set up a fallback fence which, if breached, will
/// cause the altitude fence to be freshly breached
bool AC_Fence : : check_fence_alt_min ( )
{
// altitude fence check
if ( ! ( _enabled_fences & AC_FENCE_TYPE_ALT_MIN ) ) {
2021-01-06 08:15:59 -04:00
// not enabled; no breach
2020-09-10 03:28:09 -03:00
return false ;
}
AP : : ahrs ( ) . get_relative_position_D_home ( _curr_alt ) ;
_curr_alt = - _curr_alt ; // translate Down to Up
// check if we are under the altitude fence
2017-08-24 06:48:17 -03:00
if ( _curr_alt < = _alt_min ) {
2020-09-10 03:28:09 -03:00
// record distance below breach
_alt_min_breach_distance = _alt_min - _curr_alt ;
// check for a new breach or a breach of the backup fence
if ( ! ( _breached_fences & AC_FENCE_TYPE_ALT_MIN ) | |
2017-08-24 06:48:17 -03:00
( ! is_zero ( _alt_min_backup ) & & _curr_alt < = _alt_min_backup ) ) {
2020-09-10 03:28:09 -03:00
// new breach
record_breach ( AC_FENCE_TYPE_ALT_MIN ) ;
// create a backup fence 20m lower down
_alt_min_backup = _curr_alt - AC_FENCE_ALT_MIN_BACKUP_DISTANCE ;
// new breach
return true ;
}
// old breach
return false ;
}
// not breached
2021-01-06 08:15:59 -04:00
// clear min alt breach if present
2020-09-10 03:28:09 -03:00
if ( ( _breached_fences & AC_FENCE_TYPE_ALT_MIN ) ! = 0 ) {
clear_breach ( AC_FENCE_TYPE_ALT_MIN ) ;
_alt_min_backup = 0.0f ;
_alt_min_breach_distance = 0.0f ;
}
return false ;
}
2019-08-28 04:22:16 -03:00
// check_fence_polygon - returns true if the poly fence is freshly
// breached. That includes being inside exclusion zones and outside
// inclusions zones
2017-12-07 20:10:16 -04:00
bool AC_Fence : : check_fence_polygon ( )
2019-03-06 00:45:00 -04:00
{
const bool was_breached = _breached_fences & AC_FENCE_TYPE_POLYGON ;
2019-08-28 04:22:16 -03:00
const bool breached = ( ( _enabled_fences & AC_FENCE_TYPE_POLYGON ) & &
_poly_loader . breached ( ) ) ;
2019-03-06 00:45:00 -04:00
if ( breached ) {
if ( ! was_breached ) {
record_breach ( AC_FENCE_TYPE_POLYGON ) ;
return true ;
}
return false ;
}
if ( was_breached ) {
clear_breach ( AC_FENCE_TYPE_POLYGON ) ;
}
return false ;
}
2019-08-28 04:22:16 -03:00
/// check_fence_circle - returns true if the circle fence (defined via
/// parameters) has been freshly breached. May also set up a backup
/// fence outside the fence and return a fresh breach if that backup
2023-10-11 04:41:49 -03:00
/// fence is breached.
2017-12-07 20:18:29 -04:00
bool AC_Fence : : check_fence_circle ( )
{
if ( ! ( _enabled_fences & AC_FENCE_TYPE_CIRCLE ) ) {
// not enabled; no breach
return false ;
}
2017-12-13 23:46:48 -04:00
Vector2f home ;
2019-01-30 20:37:22 -04:00
if ( AP : : ahrs ( ) . get_relative_position_NE_home ( home ) ) {
2017-12-13 23:46:48 -04:00
// we (may) remain breached if we can't update home
_home_distance = home . length ( ) ;
}
2017-12-07 20:18:29 -04:00
// check if we are outside the fence
if ( _home_distance > = _circle_radius ) {
// record distance outside the fence
_circle_breach_distance = _home_distance - _circle_radius ;
// check for a new breach or a breach of the backup fence
if ( ! ( _breached_fences & AC_FENCE_TYPE_CIRCLE ) | |
( ! is_zero ( _circle_radius_backup ) & & _home_distance > = _circle_radius_backup ) ) {
// new breach
2023-08-18 15:30:22 -03:00
// create a backup fence 20m or 100m further out
2017-12-07 20:18:29 -04:00
record_breach ( AC_FENCE_TYPE_CIRCLE ) ;
_circle_radius_backup = _home_distance + AC_FENCE_CIRCLE_RADIUS_BACKUP_DISTANCE ;
return true ;
}
return false ;
}
// not currently breached
// clear circle breach if present
if ( _breached_fences & AC_FENCE_TYPE_CIRCLE ) {
clear_breach ( AC_FENCE_TYPE_CIRCLE ) ;
_circle_radius_backup = 0.0f ;
_circle_breach_distance = 0.0f ;
}
return false ;
}
2017-12-07 20:10:16 -04:00
2017-12-15 05:35:22 -04:00
/// check - returns bitmask of fence types breached (if any)
uint8_t AC_Fence : : check ( )
2013-04-26 06:47:07 -03:00
{
2017-12-15 06:06:56 -04:00
uint8_t ret = 0 ;
2013-04-26 06:47:07 -03:00
2022-09-10 18:03:02 -03:00
// clear any breach from a non-enabled fence
clear_breach ( ~ _enabled_fences ) ;
2013-04-26 06:47:07 -03:00
// return immediately if disabled
2020-09-10 03:28:09 -03:00
if ( ( ! _enabled & & ! _auto_enabled ) | | ! _enabled_fences ) {
2017-12-15 06:06:56 -04:00
return 0 ;
2013-04-26 06:47:07 -03:00
}
2014-04-26 23:08:37 -03:00
// check if pilot is attempting to recover manually
if ( _manual_recovery_start_ms ! = 0 ) {
// we ignore any fence breaches during the manual recovery period which is about 10 seconds
2015-11-19 23:05:31 -04:00
if ( ( AP_HAL : : millis ( ) - _manual_recovery_start_ms ) < AC_FENCE_MANUAL_RECOVERY_TIME_MIN ) {
2017-12-15 06:06:56 -04:00
return 0 ;
2014-04-26 23:08:37 -03:00
}
2017-12-15 06:06:56 -04:00
// recovery period has passed so reset manual recovery time
// and continue with fence breach checks
_manual_recovery_start_ms = 0 ;
2014-04-26 23:08:37 -03:00
}
2017-12-07 20:53:18 -04:00
// maximum altitude fence check
2017-12-15 05:35:22 -04:00
if ( check_fence_alt_max ( ) ) {
2017-12-07 20:53:18 -04:00
ret | = AC_FENCE_TYPE_ALT_MAX ;
2013-04-26 06:47:07 -03:00
}
2020-09-10 03:28:09 -03:00
// minimum altitude fence check
if ( _floor_enabled & & check_fence_alt_min ( ) ) {
ret | = AC_FENCE_TYPE_ALT_MIN ;
}
2013-04-26 06:47:07 -03:00
// circle fence check
2017-12-07 20:18:29 -04:00
if ( check_fence_circle ( ) ) {
ret | = AC_FENCE_TYPE_CIRCLE ;
2013-04-26 06:47:07 -03:00
}
2016-06-23 03:24:48 -03:00
// polygon fence check
2017-12-07 20:10:16 -04:00
if ( check_fence_polygon ( ) ) {
ret | = AC_FENCE_TYPE_POLYGON ;
2016-06-23 03:24:48 -03:00
}
2013-04-26 06:47:07 -03:00
// return any new breaches that have occurred
return ret ;
}
2016-05-19 05:31:36 -03:00
// returns true if the destination is within fence (used to reject waypoints outside the fence)
2019-01-01 22:54:09 -04:00
bool AC_Fence : : check_destination_within_fence ( const Location & loc )
2016-04-28 04:29:35 -03:00
{
2020-09-10 03:28:09 -03:00
// Altitude fence check - Fence Ceiling
2016-07-02 05:14:17 -03:00
if ( ( get_enabled_fences ( ) & AC_FENCE_TYPE_ALT_MAX ) ) {
int32_t alt_above_home_cm ;
2019-03-14 22:45:12 -03:00
if ( loc . get_alt_cm ( Location : : AltFrame : : ABOVE_HOME , alt_above_home_cm ) ) {
2016-07-02 05:14:17 -03:00
if ( ( alt_above_home_cm * 0.01f ) > _alt_max ) {
return false ;
}
}
2016-04-28 04:29:35 -03:00
}
2020-09-10 03:28:09 -03:00
// Altitude fence check - Fence Floor
if ( ( get_enabled_fences ( ) & AC_FENCE_TYPE_ALT_MIN ) ) {
int32_t alt_above_home_cm ;
if ( loc . get_alt_cm ( Location : : AltFrame : : ABOVE_HOME , alt_above_home_cm ) ) {
if ( ( alt_above_home_cm * 0.01f ) < _alt_min ) {
return false ;
}
}
}
2016-04-28 04:29:35 -03:00
// Circular fence check
2016-07-02 05:14:17 -03:00
if ( ( get_enabled_fences ( ) & AC_FENCE_TYPE_CIRCLE ) ) {
2019-02-24 20:12:59 -04:00
if ( AP : : ahrs ( ) . get_home ( ) . get_distance ( loc ) > _circle_radius ) {
2016-07-02 05:14:17 -03:00
return false ;
}
}
// polygon fence check
2019-05-29 10:02:04 -03:00
if ( ( get_enabled_fences ( ) & AC_FENCE_TYPE_POLYGON ) ) {
if ( _poly_loader . breached ( loc ) ) {
return false ;
2016-07-02 05:14:17 -03:00
}
2016-04-28 04:29:35 -03:00
}
return true ;
}
2013-04-26 06:47:07 -03:00
/// record_breach - update breach bitmask, time and count
void AC_Fence : : record_breach ( uint8_t fence_type )
{
// if we haven't already breached a limit, update the breach time
2017-12-15 06:06:56 -04:00
if ( ! _breached_fences ) {
2021-02-12 23:01:25 -04:00
const uint32_t now = AP_HAL : : millis ( ) ;
_breach_time = now ;
// emit a message indicated we're newly-breached, but not too often
if ( now - _last_breach_notify_sent_ms > 1000 ) {
_last_breach_notify_sent_ms = now ;
2023-09-02 02:21:34 -03:00
GCS_SEND_MESSAGE ( MSG_FENCE_STATUS ) ;
2021-02-12 23:01:25 -04:00
}
2013-04-26 06:47:07 -03:00
}
// update breach count
2013-05-01 05:05:04 -03:00
if ( _breach_count < 65500 ) {
2013-04-26 06:47:07 -03:00
_breach_count + + ;
}
// update bitmask
2013-05-01 05:05:04 -03:00
_breached_fences | = fence_type ;
2013-04-26 06:47:07 -03:00
}
/// clear_breach - update breach bitmask, time and count
void AC_Fence : : clear_breach ( uint8_t fence_type )
{
2013-05-01 05:05:04 -03:00
_breached_fences & = ~ fence_type ;
}
2013-04-26 06:47:07 -03:00
2019-08-08 00:16:54 -03:00
/// get_breach_distance - returns maximum distance in meters outside
/// of the given fences. fence_type is a bitmask here.
2013-05-01 05:05:04 -03:00
float AC_Fence : : get_breach_distance ( uint8_t fence_type ) const
{
2019-08-08 00:16:54 -03:00
float max = 0.0f ;
2020-09-10 03:28:09 -03:00
2019-08-08 00:16:54 -03:00
if ( fence_type & AC_FENCE_TYPE_ALT_MAX ) {
max = MAX ( _alt_max_breach_distance , max ) ;
}
2020-09-10 03:28:09 -03:00
if ( fence_type & AC_FENCE_TYPE_ALT_MIN ) {
2021-01-06 08:15:59 -04:00
max = MAX ( _alt_min_breach_distance , max ) ;
2020-09-10 03:28:09 -03:00
}
2019-08-08 00:16:54 -03:00
if ( fence_type & AC_FENCE_TYPE_CIRCLE ) {
max = MAX ( _circle_breach_distance , max ) ;
}
return max ;
2013-07-24 11:05:21 -03:00
}
2014-04-26 23:08:37 -03:00
/// manual_recovery_start - caller indicates that pilot is re-taking manual control so fence should be disabled for 10 seconds
/// has no effect if no breaches have occurred
void AC_Fence : : manual_recovery_start ( )
{
// return immediate if we haven't breached a fence
2017-12-15 06:06:56 -04:00
if ( ! _breached_fences ) {
2014-04-26 23:08:37 -03:00
return ;
}
// record time pilot began manual recovery
2015-11-19 23:05:31 -04:00
_manual_recovery_start_ms = AP_HAL : : millis ( ) ;
2014-04-26 23:08:37 -03:00
}
2016-06-23 03:24:48 -03:00
2018-12-04 00:32:42 -04:00
// methods for mavlink SYS_STATUS message (send_sys_status)
2017-12-27 00:31:32 -04:00
bool AC_Fence : : sys_status_present ( ) const
2017-12-12 01:49:14 -04:00
{
2020-09-10 03:28:09 -03:00
return present ( ) ;
2017-12-12 01:49:14 -04:00
}
2017-12-27 00:31:32 -04:00
bool AC_Fence : : sys_status_enabled ( ) const
2017-12-12 01:49:14 -04:00
{
2017-12-27 00:31:32 -04:00
if ( ! sys_status_present ( ) ) {
2017-12-12 01:49:14 -04:00
return false ;
}
if ( _action = = AC_FENCE_ACTION_REPORT_ONLY ) {
return false ;
}
2020-12-18 05:08:56 -04:00
// Fence is only enabled when the flag is enabled
return _enabled ;
2017-12-12 01:49:14 -04:00
}
2017-12-27 00:31:32 -04:00
bool AC_Fence : : sys_status_failed ( ) const
2017-12-12 01:49:14 -04:00
{
2017-12-27 00:31:32 -04:00
if ( ! sys_status_present ( ) ) {
2017-12-12 01:49:14 -04:00
// not failed if not present; can fail if present but not enabled
return false ;
}
if ( get_breaches ( ) ! = 0 ) {
return true ;
}
return false ;
}
2019-01-30 21:54:13 -04:00
2020-09-10 03:28:09 -03:00
AC_PolyFence_loader & AC_Fence : : polyfence ( )
{
2019-08-28 04:22:16 -03:00
return _poly_loader ;
}
2020-09-10 03:28:09 -03:00
const AC_PolyFence_loader & AC_Fence : : polyfence ( ) const
{
2019-08-28 04:22:16 -03:00
return _poly_loader ;
}
2022-03-04 16:25:54 -04:00
# else // build type is not appropriate; provide a dummy implementation:
const AP_Param : : GroupInfo AC_Fence : : var_info [ ] = { AP_GROUPEND } ;
AC_Fence : : AC_Fence ( ) { } ;
void AC_Fence : : enable ( bool value ) { } ;
void AC_Fence : : disable_floor ( ) { } ;
void AC_Fence : : auto_enable_fence_after_takeoff ( ) { } ;
void AC_Fence : : auto_disable_fence_for_landing ( ) { } ;
bool AC_Fence : : present ( ) const { return false ; }
uint8_t AC_Fence : : get_enabled_fences ( ) const { return 0 ; }
bool AC_Fence : : pre_arm_check ( const char * & fail_msg ) const { return true ; }
uint8_t AC_Fence : : check ( ) { return 0 ; }
bool AC_Fence : : check_destination_within_fence ( const Location & loc ) { return true ; }
float AC_Fence : : get_breach_distance ( uint8_t fence_type ) const { return 0.0 ; }
void AC_Fence : : manual_recovery_start ( ) { }
bool AC_Fence : : sys_status_present ( ) const { return false ; }
bool AC_Fence : : sys_status_enabled ( ) const { return false ; }
bool AC_Fence : : sys_status_failed ( ) const { return false ; }
AC_PolyFence_loader & AC_Fence : : polyfence ( )
{
return _poly_loader ;
}
const AC_PolyFence_loader & AC_Fence : : polyfence ( ) const
{
return _poly_loader ;
}
# endif // #if AC_FENCE_DUMMY_METHODS_ENABLED
2019-01-30 21:54:13 -04:00
// singleton instance
AC_Fence * AC_Fence : : _singleton ;
2020-09-10 03:28:09 -03:00
namespace AP
{
2019-01-30 21:54:13 -04:00
AC_Fence * fence ( )
{
return AC_Fence : : get_singleton ( ) ;
}
}
2022-03-04 12:42:09 -04:00
2022-07-19 08:32:28 -03:00
# endif // AP_FENCE_ENABLED