2023-09-02 02:21:35 -03:00
# include "AP_Rally_config.h"
# if HAL_RALLY_ENABLED
2014-04-06 21:35:40 -03:00
# include "AP_Rally.h"
2019-02-18 05:33:09 -04:00
# include <AP_AHRS/AP_AHRS.h>
2018-12-29 00:08:38 -04:00
# include <AP_Logger/AP_Logger.h>
2019-02-18 05:33:09 -04:00
# include <StorageManager/StorageManager.h>
2022-10-27 22:38:07 -03:00
# include <AP_Vehicle/AP_Vehicle_Type.h>
2014-04-06 21:35:40 -03:00
2014-08-13 01:43:28 -03:00
// storage object
StorageAccess AP_Rally : : _storage ( StorageManager : : StorageRally ) ;
2019-04-03 23:29:11 -03:00
assert_storage_size < RallyLocation , 15 > _assert_storage_size_RallyLocation ;
2021-10-25 14:10:02 -03:00
# if APM_BUILD_COPTER_OR_HELI
2018-04-10 16:22:01 -03:00
# define RALLY_LIMIT_KM_DEFAULT 0.3f
# define RALLY_INCLUDE_HOME_DEFAULT 1
# elif APM_BUILD_TYPE(APM_BUILD_ArduPlane)
# define RALLY_LIMIT_KM_DEFAULT 5.0f
# define RALLY_INCLUDE_HOME_DEFAULT 0
2020-03-26 21:51:16 -03:00
# elif APM_BUILD_TYPE(APM_BUILD_Rover)
2018-04-10 16:22:01 -03:00
# define RALLY_LIMIT_KM_DEFAULT 0.5f
2018-08-29 21:36:00 -03:00
# define RALLY_INCLUDE_HOME_DEFAULT 1
2018-04-10 16:22:01 -03:00
# else
# define RALLY_LIMIT_KM_DEFAULT 1.0f
# define RALLY_INCLUDE_HOME_DEFAULT 0
2015-08-01 13:42:44 -03:00
# endif
2015-10-25 14:03:46 -03:00
const AP_Param : : GroupInfo AP_Rally : : var_info [ ] = {
2014-04-06 21:35:40 -03:00
// @Param: TOTAL
// @DisplayName: Rally Total
// @Description: Number of rally points currently loaded
// @User: Advanced
AP_GROUPINFO ( " TOTAL " , 0 , AP_Rally , _rally_point_total_count , 0 ) ,
// @Param: LIMIT_KM
// @DisplayName: Rally Limit
// @Description: Maximum distance to rally point. If the closest rally point is more than this number of kilometers from the current position and the home location is closer than any of the rally points from the current position then do RTL to home rather than to the closest rally point. This prevents a leftover rally point from a different airfield being used accidentally. If this is set to 0 then the closest rally point is always used.
// @User: Advanced
2017-05-02 10:47:42 -03:00
// @Units: km
2014-04-06 21:35:40 -03:00
// @Increment: 0.1
AP_GROUPINFO ( " LIMIT_KM " , 1 , AP_Rally , _rally_limit_km , RALLY_LIMIT_KM_DEFAULT ) ,
2015-08-04 08:12:53 -03:00
// @Param: INCL_HOME
// @DisplayName: Rally Include Home
// @Description: Controls if Home is included as a Rally point (i.e. as a safe landing place) for RTL
2015-08-01 13:42:44 -03:00
// @User: Standard
2015-08-04 08:12:53 -03:00
// @Values: 0:DoNotIncludeHome,1:IncludeHome
AP_GROUPINFO ( " INCL_HOME " , 2 , AP_Rally , _rally_incl_home , RALLY_INCLUDE_HOME_DEFAULT ) ,
2015-08-01 13:42:44 -03:00
2014-04-06 21:35:40 -03:00
AP_GROUPEND
} ;
// constructor
2019-02-18 05:33:09 -04:00
AP_Rally : : AP_Rally ( )
2014-04-06 21:35:40 -03:00
{
2018-12-25 01:17:15 -04:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
if ( _singleton ! = nullptr ) {
AP_HAL : : panic ( " Rally must be singleton " ) ;
}
# endif
_singleton = this ;
2014-04-06 21:35:40 -03:00
AP_Param : : setup_object_defaults ( this , var_info ) ;
}
// get a rally point from EEPROM
bool AP_Rally : : get_rally_point_with_index ( uint8_t i , RallyLocation & ret ) const
{
if ( i > = ( uint8_t ) _rally_point_total_count ) {
return false ;
}
2014-08-13 01:43:28 -03:00
_storage . read_block ( & ret , i * sizeof ( RallyLocation ) , sizeof ( RallyLocation ) ) ;
2014-04-06 21:35:40 -03:00
if ( ret . lat = = 0 & & ret . lng = = 0 ) {
return false ; // sanity check
}
return true ;
}
2019-01-30 07:18:16 -04:00
void AP_Rally : : truncate ( uint8_t num )
{
if ( num > _rally_point_total_count ) {
// we never make the space larger this way
return ;
}
_rally_point_total_count . set_and_save_ifchanged ( num ) ;
}
bool AP_Rally : : append ( const RallyLocation & loc )
{
const uint8_t current_total = get_rally_total ( ) ;
_rally_point_total_count . set_and_save_ifchanged ( current_total + 1 ) ;
if ( ! set_rally_point_with_index ( current_total , loc ) ) {
_rally_point_total_count . set_and_save_ifchanged ( current_total ) ;
return false ;
}
return true ;
}
2014-04-06 21:35:40 -03:00
// save a rally point to EEPROM - this assumes that the RALLY_TOTAL param has been incremented beforehand, which is the case in Mission Planner
bool AP_Rally : : set_rally_point_with_index ( uint8_t i , const RallyLocation & rallyLoc )
{
if ( i > = ( uint8_t ) _rally_point_total_count ) {
return false ;
}
2014-08-13 01:43:28 -03:00
if ( i > = get_rally_max ( ) ) {
2014-04-06 21:35:40 -03:00
return false ;
}
2014-08-13 01:43:28 -03:00
_storage . write_block ( i * sizeof ( RallyLocation ) , & rallyLoc , sizeof ( RallyLocation ) ) ;
2014-04-06 21:35:40 -03:00
2015-11-19 23:14:17 -04:00
_last_change_time_ms = AP_HAL : : millis ( ) ;
2014-08-06 03:35:43 -03:00
2019-02-11 23:21:04 -04:00
AP : : logger ( ) . Write_RallyPoint ( _rally_point_total_count , i , rallyLoc ) ;
2018-12-29 00:08:38 -04:00
2014-04-06 21:35:40 -03:00
return true ;
}
// helper function to translate a RallyLocation to a Location
2014-04-21 18:30:06 -03:00
Location AP_Rally : : rally_location_to_location ( const RallyLocation & rally_loc ) const
2014-04-06 21:35:40 -03:00
{
2022-06-30 22:16:06 -03:00
//Relative altitudes are relative to HOME point's altitude:
Location ret {
rally_loc . lat ,
rally_loc . lng ,
rally_loc . alt * 100 ,
Location : : AltFrame : : ABOVE_HOME
} ;
// notionally the following call can fail, but we have no facility
// to return that fact here:
ret . change_alt_frame ( Location : : AltFrame : : ABSOLUTE ) ;
2014-04-06 21:35:40 -03:00
return ret ;
}
// returns true if a valid rally point is found, otherwise returns false to indicate home position should be used
bool AP_Rally : : find_nearest_rally_point ( const Location & current_loc , RallyLocation & return_loc ) const
{
float min_dis = - 1 ;
for ( uint8_t i = 0 ; i < ( uint8_t ) _rally_point_total_count ; i + + ) {
RallyLocation next_rally ;
if ( ! get_rally_point_with_index ( i , next_rally ) ) {
continue ;
}
2014-04-21 18:30:06 -03:00
Location rally_loc = rally_location_to_location ( next_rally ) ;
2019-02-24 20:16:26 -04:00
float dis = current_loc . get_distance ( rally_loc ) ;
2014-04-06 21:35:40 -03:00
2016-07-19 19:40:22 -03:00
if ( is_valid ( rally_loc ) & & ( dis < min_dis | | min_dis < 0 ) ) {
2014-04-06 21:35:40 -03:00
min_dis = dis ;
return_loc = next_rally ;
}
}
2015-08-04 08:12:53 -03:00
// if a limit is defined and all rally points are beyond that limit, use home if it is closer
2018-12-28 23:55:25 -04:00
if ( ( _rally_limit_km > 0 ) & & ( min_dis > _rally_limit_km * 1000.0f ) ) {
2014-04-06 21:35:40 -03:00
return false ; // use home position
}
2015-08-04 08:12:53 -03:00
// use home if no rally points found
2014-04-06 21:35:40 -03:00
return min_dis > = 0 ;
}
// return best RTL location from current position
2022-02-03 22:48:03 -04:00
Location AP_Rally : : calc_best_rally_or_home_location ( const Location & current_loc , float rtl_home_alt_amsl_cm ) const
2014-04-06 21:35:40 -03:00
{
2022-06-30 00:11:45 -03:00
// if no valid rally point, return home position:
Location return_loc { AP : : ahrs ( ) . get_home ( ) } ;
2022-02-03 22:48:03 -04:00
return_loc . set_alt_cm ( rtl_home_alt_amsl_cm , Location : : AltFrame : : ABSOLUTE ) ;
2018-12-28 23:55:25 -04:00
2022-06-30 00:11:45 -03:00
RallyLocation ral_loc ;
2014-04-06 21:35:40 -03:00
if ( find_nearest_rally_point ( current_loc , ral_loc ) ) {
2018-12-28 23:55:25 -04:00
Location loc = rally_location_to_location ( ral_loc ) ;
// use the rally point if it's closer then home, or we aren't generally considering home as acceptable
2019-02-24 20:16:26 -04:00
if ( ! _rally_incl_home | | ( current_loc . get_distance ( loc ) < current_loc . get_distance ( return_loc ) ) ) {
2018-12-28 23:55:25 -04:00
return_loc = rally_location_to_location ( ral_loc ) ;
}
2014-04-06 21:35:40 -03:00
}
return return_loc ;
}
2018-12-25 01:17:15 -04:00
// singleton instance
AP_Rally * AP_Rally : : _singleton ;
namespace AP {
AP_Rally * rally ( )
{
return AP_Rally : : get_singleton ( ) ;
}
}
2021-06-20 03:17:15 -03:00
# endif //HAL_RALLY_ENABLED