2012-07-14 23:26:17 -03:00
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
/// @file ap_limits.cpp
2012-10-11 22:35:35 -03:00
/// @brief Imposes limits on location (geofence), altitude and other parameters
/// Each 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
2015-08-11 03:28:44 -03:00
# include "AP_Limits.h"
# include "AP_Limit_Module.h"
2012-07-14 23:26:17 -03:00
const AP_Param : : GroupInfo AP_Limits : : var_info [ ] PROGMEM = {
2012-08-17 03:20:06 -03:00
// @Param: ENABLED
// @DisplayName: Enable Limits Library
// @Description: Setting this to Enabled(1) will enable the limits system
// @Values: 0:Disabled,1:Enabled
2012-07-31 22:39:58 -03:00
// @User: Standard
2012-08-17 03:20:06 -03:00
AP_GROUPINFO ( " ENABLED " , 0 , AP_Limits , _enabled , 0 ) ,
// @Param: REQUIRED
// @DisplayName: Limits Library Required
// @Description: Setting this to 1 will enable the limits pre-arm checklist
// @Values: 0:Disabled,1:Enabled
// @User: Standard
AP_GROUPINFO ( " REQUIRED " , 1 , AP_Limits , _required , 0 ) ,
// @Param: DEBUG
// @DisplayName: Enable Limits Debug
2012-12-08 00:19:36 -04:00
// @Description: Setting this to 1 will turn on debugging messages on the console and via MAVLink STATUSTEXT messages
2012-08-17 03:20:06 -03:00
// @Values: 0:Disabled,1:Enabled
// @User: Standard
AP_GROUPINFO ( " DEBUG " , 2 , AP_Limits , _debug , 0 ) ,
// @Param: SAFETIME
// @DisplayName: Limits Safetime
2012-12-08 00:19:36 -04:00
// @Description: Automatic return of controls to pilot. Set to 0 to disable (full RTL) or a number of seconds after complete recovery to return the controls to the pilot in STABILIZE
2012-08-17 03:20:06 -03:00
// @Values: 0:Disabled,1-255:Seconds before returning control
// @User: Standard
AP_GROUPINFO ( " SAFETIME " , 3 , AP_Limits , _safetime , 0 ) ,
// @Param: CHANNEL
// @DisplayName: Limits Channel
2012-12-08 00:19:36 -04:00
// @Description: Channel for Limits on/off control. If channel exceeds LIMITS_ENABLE_PWM, it turns limits on, and vice-versa.
2012-08-17 03:20:06 -03:00
// @Range: 1-8
// @User: Standard
AP_GROUPINFO ( " CHANNEL " , 4 , AP_Limits , _channel , 0 ) ,
// @Param: RECMODE
// @DisplayName: Limits Recovery Mode
2012-12-08 00:19:36 -04:00
// @Description: Select how Limits should "recover". Set to 0 for RTL-like mode, where the vehicle navigates back to home until it is "safe". Set to 1, for bounce-mode, where the vehicle will hold position when it hits a limit. RTL mode is better for large fenced areas, Bounce mode for smaller spaces. Note: RTL mode will cause the vehicle to yaw 180 degrees (turn around) to navigate towards home when it hits a limit.
2012-08-17 03:20:06 -03:00
// @Values: 0:RTL mode, 1: Bounce mode
// @User: Standard
AP_GROUPINFO ( " RECMODE " , 5 , AP_Limits , _recmode , 0 ) ,
2012-07-31 22:39:58 -03:00
AP_GROUPEND
2012-07-14 23:26:17 -03:00
} ;
AP_Limits : : AP_Limits ( ) {
2012-12-12 17:49:46 -04:00
AP_Param : : setup_object_defaults ( this , var_info ) ;
2012-08-17 03:20:06 -03:00
_state = LIMITS_INIT ;
2012-07-14 23:26:17 -03:00
}
void AP_Limits : : modules ( AP_Limit_Module * m )
{
2012-08-17 03:20:06 -03:00
_modules_head = m ;
2012-07-14 23:26:17 -03:00
}
bool AP_Limits : : init ( ) {
2012-08-17 03:20:06 -03:00
AP_Limit_Module * m = modules_first ( ) ;
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
while ( m ) {
m - > init ( ) ;
m = modules_next ( ) ;
}
return true ;
2012-07-14 23:26:17 -03:00
}
bool AP_Limits : : enabled ( ) {
2012-08-17 03:20:06 -03:00
return _enabled ;
2012-07-14 23:26:17 -03:00
}
bool AP_Limits : : debug ( ) {
2012-08-17 03:20:06 -03:00
return _debug ;
2012-07-14 23:26:17 -03:00
}
2012-08-17 03:20:06 -03:00
AP_Limit_Module * AP_Limits : : modules_first ( ) {
2012-10-11 22:35:35 -03:00
// reset current to head of list
_modules_current = _modules_head ;
2012-08-17 03:20:06 -03:00
return _modules_head ;
2012-07-14 23:26:17 -03:00
}
2012-08-17 03:20:06 -03:00
AP_Limit_Module * AP_Limits : : modules_current ( ) {
return _modules_current ;
2012-07-14 23:26:17 -03:00
}
2012-08-17 03:20:06 -03:00
AP_Limit_Module * AP_Limits : : modules_next ( ) {
if ( _modules_current ) {
2012-10-11 22:35:35 -03:00
// move to "next" (which might be NULL)
_modules_current = _modules_current - > next ( ) ;
2012-08-17 03:20:06 -03:00
}
return _modules_current ;
2012-07-14 23:26:17 -03:00
}
2012-08-17 03:20:06 -03:00
uint8_t AP_Limits : : modules_count ( ) {
_modules_count = 0 ;
AP_Limit_Module * m = _modules_head ;
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
while ( m ) {
_modules_count + + ;
m = m - > next ( ) ;
}
return _modules_count ;
2012-07-14 23:26:17 -03:00
}
2012-08-17 03:20:06 -03:00
AP_Limit_Module * AP_Limits : : modules_last ( ) {
AP_Limit_Module * m = _modules_head ;
while ( m & & m - > next ( ) ) {
m = m - > next ( ) ;
}
return m ;
2012-07-14 23:26:17 -03:00
}
2012-08-17 03:20:06 -03:00
void AP_Limits : : modules_add ( AP_Limit_Module * m ) {
2012-10-11 22:35:35 -03:00
if ( _modules_head ) {
// if there is a module linked add to the end of the list
modules_last ( ) - > link ( m ) ;
} else {
// otherwise, this will be the "head"
_modules_head = m ;
2012-08-17 03:20:06 -03:00
}
2012-07-14 23:26:17 -03:00
}
bool AP_Limits : : required ( ) {
2012-08-17 03:20:06 -03:00
return _required ;
2012-07-14 23:26:17 -03:00
}
bool AP_Limits : : check_all ( ) {
2012-10-11 22:35:35 -03:00
// required=false, means "all"
2013-04-23 10:13:54 -03:00
return check_triggered ( false ) ;
2012-07-14 23:26:17 -03:00
}
bool AP_Limits : : check_required ( ) {
2012-10-11 22:35:35 -03:00
// required=true, means "only required modules"
2013-04-23 10:13:54 -03:00
return check_triggered ( true ) ;
2012-07-14 23:26:17 -03:00
}
bool AP_Limits : : check_triggered ( bool only_required ) {
2012-08-17 03:20:06 -03:00
// check all enabled modules for triggered limits
AP_Limit_Module * mod = _modules_head ;
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
// reset bit fields
mods_triggered = 0 ;
mods_enabled = 0 ;
mods_required = 0 ;
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
while ( mod ) {
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
unsigned module_id = mod - > get_module_id ( ) ;
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
// We check enabled, triggered and required across all modules
// We set all the bit-fields each time we check, keeping them up to date
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
if ( mod - > enabled ( ) ) {
mods_enabled | = module_id ;
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
if ( mod - > required ( ) ) mods_required | = module_id ;
if ( mod - > triggered ( ) ) mods_triggered | = module_id ;
}
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
mod = mod - > next ( ) ;
}
2012-07-14 23:26:17 -03:00
2012-08-17 03:20:06 -03:00
if ( only_required ) {
2012-10-11 22:35:35 -03:00
// just modules that are both required AND triggered. (binary AND)
2013-04-23 10:13:54 -03:00
return ( mods_required & mods_triggered ) ! = 0 ;
2012-10-11 22:35:35 -03:00
} else {
2013-04-23 10:13:54 -03:00
return mods_triggered ! = 0 ;
2012-08-17 03:20:06 -03:00
}
2012-07-14 23:26:17 -03:00
}
2013-04-23 10:13:54 -03:00
int8_t AP_Limits : : state ( ) {
return _state . get ( ) ;
2012-07-14 23:26:17 -03:00
}
2013-04-23 10:13:54 -03:00
int8_t AP_Limits : : safetime ( ) {
return _safetime . get ( ) ;
2012-07-14 23:26:17 -03:00
}
void AP_Limits : : set_state ( int s ) {
2013-04-23 10:13:54 -03:00
_state . set ( s ) ;
2012-07-14 23:26:17 -03:00
}
2013-04-23 10:13:54 -03:00
int8_t AP_Limits : : channel ( ) {
return _channel . get ( ) ;
2012-07-14 23:26:17 -03:00
}
2012-07-31 22:39:58 -03:00
2013-04-23 10:13:54 -03:00
int8_t AP_Limits : : recmode ( ) {
return _recmode . get ( ) ;
2012-07-31 22:39:58 -03:00
}