2012-07-14 23:26:17 -03:00
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
/// @file limits.cpp
/// @brief Imposes limits on location (geofence), altitude and other parameters.
2012-10-11 22:35:35 -03:00
/// Each limit breach will trigger an action or set of actions to recover.
/// Adapted from geofence.
2012-07-14 23:26:17 -03:00
/// @author Andrew Tridgell
/// Andreas Antonopoulos
2012-12-13 16:02:19 -04:00
# include "AP_Limit_Geofence.h"
# include <AP_HAL.h>
extern const AP_HAL : : HAL & hal ;
2012-07-14 23:26:17 -03:00
const AP_Param : : GroupInfo AP_Limit_Geofence : : var_info [ ] PROGMEM = {
2012-08-21 23:19:52 -03:00
// @Param: FNC_ON
// @DisplayName: Enable Geofence
2012-12-08 00:19:36 -04:00
// @Description: Setting this to Enabled(1) will enable the geofence. Setting this to Disabled(0) will disable the geofence
2012-08-21 23:19:52 -03:00
// @Values: 0:Disabled,1:Enabled
// @User: Standard
AP_GROUPINFO ( " FNC_ON " , 0 , AP_Limit_Geofence , _enabled , 0 ) ,
// @Param: FNC_REQ
// @DisplayName: Require Geofence
2012-12-08 00:19:36 -04:00
// @Description: Setting this to Enabled(1) will make being inside the geofence a required check before arming the vehicle.
2012-08-21 23:19:52 -03:00
// @Values: 0:Disabled,1:Enabled
// @User: Standard
AP_GROUPINFO ( " FNC_REQ " , 1 , AP_Limit_Geofence , _required , 0 ) ,
// @Param: FNC_SMPL
// @DisplayName: Require Geofence
2012-12-08 00:19:36 -04:00
// @Description: "Simple" geofence (enabled - 1) is based on a radius from the home position, "Complex" (disabled - 0) define a complex fence by lat/long positions
2012-08-21 23:19:52 -03:00
// @Values: 0:Disabled,1:Enabled
// @User: Standard
AP_GROUPINFO ( " FNC_SMPL " , 2 , AP_Limit_Geofence , _simple , 0 ) ,
// @Param: FNC_RAD
// @DisplayName: Require Geofence
2012-12-08 00:19:36 -04:00
// @Description: Radius of fenced area in meters. A value of 20 creates a 20-meter radius circle (40-meter diameter) from the home point.
2012-08-21 23:19:52 -03:00
// @Units: Meters
// @Range: 0 32767
// @Increment: 1
// @User: Standard
AP_GROUPINFO ( " FNC_RAD " , 3 , AP_Limit_Geofence , _radius , 0 ) ,
2013-01-02 05:50:03 -04:00
// @Param: FNC_TOT
// @DisplayName: Total number of geofence points
// @Description: Total number of geofence points. This parameter should not be updated manually
// @Range: 0 6
// @Increment: 1
2012-08-21 23:19:52 -03:00
AP_GROUPINFO ( " FNC_TOT " , 4 , AP_Limit_Geofence , _fence_total , 0 ) ,
2012-07-14 23:26:17 -03:00
AP_GROUPEND
} ;
2012-12-13 16:02:19 -04:00
AP_Limit_Geofence : : AP_Limit_Geofence ( uint16_t efs , uint8_t f_wp_s ,
2013-03-26 08:58:54 -03:00
uint8_t max_fp , GPS * & gps , const struct Location * h_loc ,
const struct Location * c_loc ) :
2012-08-21 23:19:52 -03:00
AP_Limit_Module ( AP_LIMITS_GEOFENCE ) ,
_gps ( gps ) ,
_current_loc ( c_loc ) ,
_home ( h_loc ) ,
_eeprom_fence_start ( efs ) ,
_fence_wp_size ( f_wp_s ) ,
_max_fence_points ( max_fp ) ,
_boundary_uptodate ( false )
2012-07-14 23:26:17 -03:00
{
2012-12-12 17:49:46 -04:00
AP_Param : : setup_object_defaults ( this , var_info ) ;
2012-08-21 23:19:52 -03:00
update_boundary ( ) ;
2012-07-14 23:26:17 -03:00
}
bool AP_Limit_Geofence : : triggered ( ) {
2012-08-21 23:19:52 -03:00
// reset trigger before checking
_triggered = false ;
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:52 -03:00
// never trigger while disabled
if ( ! _enabled ) return false ;
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:52 -03:00
// if Geofence is required and we don't know where we are, trigger.
if ( _required & & ( ! _gps | | ! _gps - > fix | | ! _home | | ! _current_loc ) ) {
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:52 -03:00
// TRIGGER
_triggered = true ;
}
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:52 -03:00
uint32_t distance ;
2012-07-14 23:26:17 -03:00
2012-10-11 22:35:35 -03:00
// simple mode, pointers to current and home exist.
if ( _simple & & _current_loc & & _home ) {
2013-08-04 21:14:52 -03:00
distance = ( uint32_t ) get_distance ( * _current_loc , * _home ) ;
2012-08-21 23:19:52 -03:00
if ( distance > 0 & & distance > ( uint16_t ) _radius ) {
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:52 -03:00
// TRIGGER
_triggered = true ;
}
}
else {
// COMPLEX GEOFENCE mode
// check boundary and update if necessary
if ( ! _boundary_uptodate ) {
update_boundary ( ) ;
}
2012-10-11 22:35:35 -03:00
// if boundary is correct, and current_loc exists check if we
// are inside the fence.
2012-08-21 23:19:52 -03:00
if ( boundary_correct ( ) & & _current_loc ) {
Vector2l location ;
location . x = _current_loc - > lat ;
location . y = _current_loc - > lng ;
2012-10-11 22:35:35 -03:00
// trigger if outside
if ( Polygon_outside ( location , & _boundary [ 1 ] , _fence_total - 1 ) ) {
2012-08-21 23:19:52 -03:00
// TRIGGER
_triggered = true ;
}
2012-10-11 22:35:35 -03:00
} else {
// boundary incorrect
// If geofence is required and our boundary fence is incorrect,
// we trigger.
2012-08-21 23:19:52 -03:00
if ( _required ) {
// TRIGGER
_triggered = true ;
}
}
}
return _triggered ;
2012-07-14 23:26:17 -03:00
}
2012-08-21 23:19:52 -03:00
AP_Int8 AP_Limit_Geofence : : fence_total ( ) {
return _fence_total ;
2012-07-14 23:26:17 -03:00
}
// save a fence point
void AP_Limit_Geofence : : set_fence_point_with_index ( Vector2l & point , uint8_t i )
{
if ( i > = ( unsigned ) fence_total ( ) ) {
// not allowed
return ;
}
2012-12-13 16:02:19 -04:00
uint16_t mem = _eeprom_fence_start + ( i * _fence_wp_size ) ;
2012-07-14 23:26:17 -03:00
2012-12-13 16:02:19 -04:00
hal . storage - > write_dword ( mem , point . x ) ;
mem + = 4 ;
hal . storage - > write_dword ( mem , point . y ) ;
2012-07-14 23:26:17 -03:00
_boundary_uptodate = false ;
}
/*
2012-08-21 23:19:52 -03:00
* fence boundaries fetch / store
2012-07-14 23:26:17 -03:00
*/
Vector2l AP_Limit_Geofence : : get_fence_point_with_index ( uint8_t i )
{
Vector2l ret ;
if ( i > ( unsigned ) fence_total ( ) ) {
return Vector2l ( 0 , 0 ) ;
}
// read fence point
2012-12-13 16:02:19 -04:00
uint16_t mem = _eeprom_fence_start + ( i * _fence_wp_size ) ;
ret . x = hal . storage - > read_dword ( mem ) ;
mem + = 4 ;
ret . y = hal . storage - > read_dword ( mem ) ;
2012-07-14 23:26:17 -03:00
return ret ;
}
void AP_Limit_Geofence : : update_boundary ( ) {
2012-08-21 23:19:52 -03:00
if ( ! _simple & & _fence_total > 0 ) {
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:52 -03:00
for ( uint8_t i = 0 ; i < ( uint8_t ) _fence_total ; i + + ) {
_boundary [ i ] = get_fence_point_with_index ( i ) ;
}
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:52 -03:00
_boundary_uptodate = true ;
2012-07-14 23:26:17 -03:00
2012-08-21 23:19:52 -03:00
}
2012-07-14 23:26:17 -03:00
}
bool AP_Limit_Geofence : : boundary_correct ( ) {
2012-08-21 23:19:52 -03:00
if ( Polygon_complete ( & _boundary [ 1 ] , _fence_total - 1 ) & &
! Polygon_outside ( _boundary [ 0 ] , & _boundary [ 1 ] , _fence_total - 1 ) ) {
return true ;
} else return false ;
2012-07-14 23:26:17 -03:00
}