AP_SmartRTL.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #pragma once
  2. #include <AP_HAL/AP_HAL.h>
  3. #include <AP_Common/Bitmask.h>
  4. #include <AP_Math/AP_Math.h>
  5. // definitions and macros
  6. #define SMARTRTL_ACCURACY_DEFAULT 2.0f // default _ACCURACY parameter value. Points will be no closer than this distance (in meters) together.
  7. #define SMARTRTL_POINTS_DEFAULT 300 // default _POINTS parameter value. High numbers improve path pruning but use more memory and CPU for cleanup. Memory used will be 20bytes * this number.
  8. #define SMARTRTL_POINTS_MAX 500 // the absolute maximum number of points this library can support.
  9. #define SMARTRTL_TIMEOUT 15000 // the time in milliseconds with no points saved to the path (for whatever reason), before SmartRTL is disabled for the flight
  10. #define SMARTRTL_CLEANUP_POINT_TRIGGER 50 // simplification will trigger when this many points are added to the path
  11. #define SMARTRTL_CLEANUP_START_MARGIN 10 // routine cleanup algorithms begin when the path array has only this many empty slots remaining
  12. #define SMARTRTL_CLEANUP_POINT_MIN 10 // cleanup algorithms will remove points if they remove at least this many points
  13. #define SMARTRTL_SIMPLIFY_EPSILON (_accuracy * 0.5f)
  14. #define SMARTRTL_SIMPLIFY_STACK_LEN_MULT (2.0f/3.0f)+1 // simplify buffer size as compared to maximum number of points.
  15. // The minimum is int((s/2-1)+min(s/2, SMARTRTL_POINTS_MAX-s)), where s = pow(2, floor(log(SMARTRTL_POINTS_MAX)/log(2)))
  16. // To avoid this annoying math, a good-enough overestimate is ceil(SMARTRTL_POINTS_MAX*2.0f/3.0f)
  17. #define SMARTRTL_SIMPLIFY_TIME_US 200 // maximum time (in microseconds) the simplification algorithm will run before returning
  18. #define SMARTRTL_PRUNING_DELTA (_accuracy * 0.99) // How many meters apart must two points be, such that we can assume that there is no obstacle between them. must be smaller than _ACCURACY parameter
  19. #define SMARTRTL_PRUNING_LOOP_BUFFER_LEN_MULT 0.25f // pruning loop buffer size as compared to maximum number of points
  20. #define SMARTRTL_PRUNING_LOOP_TIME_US 200 // maximum time (in microseconds) that the loop finding algorithm will run before returning
  21. class AP_SmartRTL {
  22. public:
  23. // constructor, destructor
  24. AP_SmartRTL(bool example_mode = false);
  25. // initialise safe rtl including setting up background processes
  26. void init();
  27. // return true if smart_rtl is usable (it may become unusable if the user took off without GPS lock or the path became too long)
  28. bool is_active() const { return _active; }
  29. // returns number of points on the path
  30. uint16_t get_num_points() const;
  31. // get a point on the path
  32. const Vector3f& get_point(uint16_t index) const { return _path[index]; }
  33. // get next point on the path to home, returns true on success
  34. bool pop_point(Vector3f& point);
  35. // clear return path and set return location if position_ok is true. This should be called as part of the arming procedure
  36. // if position_ok is false, SmartRTL will not be available.
  37. // example sketches use the method that allows providing vehicle position directly
  38. void set_home(bool position_ok);
  39. void set_home(bool position_ok, const Vector3f& current_pos);
  40. // call this at 3hz (or higher) regardless of what mode the vehicle is in
  41. // example sketches use method that allows providing vehicle position directly
  42. void update(bool position_ok, bool save_position);
  43. void update(bool position_ok, const Vector3f& current_pos);
  44. // enum for argument passed to request_through_cleanup
  45. enum ThoroughCleanupType {
  46. THOROUGH_CLEAN_DEFAULT = 0, // perform simplify and prune (used by vehicle code)
  47. THOROUGH_CLEAN_ALL, // same as above but used by example sketch
  48. THOROUGH_CLEAN_SIMPLIFY_ONLY, // perform simplify only (used by example sketch)
  49. THOROUGH_CLEAN_PRUNE_ONLY, // perform prune only (used by example sketch)
  50. };
  51. // triggers thorough cleanup including simplification, pruning and removal of all unnecessary points
  52. // returns true if the thorough cleanup was completed, false if it has not yet completed
  53. // this method should be called repeatedly until it returns true before initiating the return journey
  54. // clean_type should only be set by the example sketch
  55. bool request_thorough_cleanup(ThoroughCleanupType clean_type = THOROUGH_CLEAN_DEFAULT);
  56. // cancel request for thorough cleanup
  57. void cancel_request_for_thorough_cleanup();
  58. // run background cleanup - should be run regularly from the IO thread
  59. void run_background_cleanup();
  60. // parameter var table
  61. static const struct AP_Param::GroupInfo var_info[];
  62. private:
  63. // enums for logging latest actions
  64. enum SRTL_Actions {
  65. SRTL_POINT_ADD,
  66. SRTL_POINT_PRUNE,
  67. SRTL_POINT_SIMPLIFY,
  68. SRTL_ADD_FAILED_NO_SEMAPHORE,
  69. SRTL_ADD_FAILED_PATH_FULL,
  70. SRTL_POP_FAILED_NO_SEMAPHORE,
  71. SRTL_DEACTIVATED_INIT_FAILED,
  72. SRTL_DEACTIVATED_BAD_POSITION,
  73. SRTL_DEACTIVATED_BAD_POSITION_TIMEOUT,
  74. SRTL_DEACTIVATED_PATH_FULL_TIMEOUT,
  75. SRTL_DEACTIVATED_PROGRAM_ERROR,
  76. };
  77. // add point to end of path
  78. bool add_point(const Vector3f& point);
  79. // routine cleanup attempts to remove 10 points (see SMARTRTL_CLEANUP_POINT_MIN definition) by simplification or loop pruning
  80. void routine_cleanup(uint16_t path_points_count, uint16_t path_points_complete_limit);
  81. // thorough cleanup simplifies and prunes all loops. returns true if the cleanup was completed.
  82. // path_points_count is _path_points_count but passed in to avoid having to take the semaphore
  83. bool thorough_cleanup(uint16_t path_points_count, ThoroughCleanupType clean_type);
  84. // the two cleanup steps run from the background thread
  85. // these are public so that they can be tested by the example sketch
  86. void detect_simplifications();
  87. void detect_loops();
  88. // restart simplify or pruning if new points have been added to path
  89. // path_points_count is _path_points_count but passed in to avoid having to take the semaphore
  90. void restart_simplify_if_new_points(uint16_t path_points_count);
  91. // restart pruning if new points have been simplified
  92. void restart_pruning_if_new_points();
  93. // restart simplify algorithm so that detect_simplify will check all new points that have been added
  94. // to the path since it last completed.
  95. // path_points_count is _path_points_count but passed in to avoid having to take the semaphore
  96. void restart_simplification(uint16_t path_points_count);
  97. // reset simplify algorithm so that it will re-check all points in the path
  98. void reset_simplification();
  99. // restart pruning algorithm so that detect_loops will check all new points that have been added
  100. // to the path since it last completed.
  101. // path_points_count is _path_points_count but passed in to avoid having to take the semaphore
  102. void restart_pruning(uint16_t path_points_count);
  103. // reset pruning algorithm so that it will re-check all points in the path
  104. void reset_pruning();
  105. // remove all simplify-able points from the path
  106. void remove_points_by_simplify_bitmask();
  107. // remove loops until at least num_point_to_remove have been removed from path
  108. // does not necessarily prune all loops
  109. // returns false if it failed to remove points (because it could not take semaphore)
  110. bool remove_points_by_loops(uint16_t num_points_to_remove);
  111. // add loop to loops array
  112. // returns true if loop added successfully, false on failure (because loop array is full)
  113. // checks if loop overlaps with an existing loop, keeps only the longer loop
  114. // example: segment_a(point2~point3) overlaps with segment_b (point5~point6), add_loop(3,5,midpoint)
  115. bool add_loop(uint16_t start_index, uint16_t end_index, const Vector3f& midpoint);
  116. // dist_point holds the closest distance reached between 2 line segments, and the point exactly between them
  117. typedef struct {
  118. float distance;
  119. Vector3f midpoint;
  120. } dist_point;
  121. // get the closest distance between 2 line segments and the point midway between the closest points
  122. static dist_point segment_segment_dist(const Vector3f& p1, const Vector3f& p2, const Vector3f& p3, const Vector3f& p4);
  123. // de-activate SmartRTL, send warning to GCS and logger
  124. void deactivate(SRTL_Actions action, const char *reason);
  125. // logging
  126. void log_action(SRTL_Actions action, const Vector3f &point = Vector3f());
  127. // parameters
  128. AP_Float _accuracy;
  129. AP_Int16 _points_max;
  130. // SmartRTL State Variables
  131. bool _active; // true if SmartRTL is usable. may become unusable if the path becomes too long to keep in memory, and too convoluted to be cleaned up, SmartRTL will be permanently deactivated (for the remainder of the flight)
  132. bool _example_mode; // true when being called from the example sketch, logging and background tasks are disabled
  133. bool _home_saved; // true once home has been saved successfully by the set_home or update methods
  134. uint32_t _last_good_position_ms; // the last system time a last good position was reported. If no position is available for a while, SmartRTL will be disabled.
  135. uint32_t _last_position_save_ms; // the system time a position was saved to the path (used for timeout)
  136. uint32_t _thorough_clean_request_ms;// the last system time the thorough cleanup was requested (set by thorough_cleanup method, used by background cleanup)
  137. uint32_t _thorough_clean_complete_ms; // set to _thorough_clean_request_ms when the background thread completes the thorough cleanup
  138. ThoroughCleanupType _thorough_clean_type; // used by example sketch to test simplify and prune separately
  139. // path variables
  140. Vector3f* _path; // points are stored in meters from EKF origin in NED
  141. uint16_t _path_points_max; // after the array has been allocated, we will need to know how big it is. We can't use the parameter, because a user could change the parameter in-flight
  142. uint16_t _path_points_count;// number of points in the path array
  143. uint16_t _path_points_completed_limit; // set by main thread to the path_point_count when a point is popped. used by simplify and prune algorithms to detect path shrinking
  144. HAL_Semaphore _path_sem; // semaphore for updating path
  145. // Simplify
  146. // structure and buffer to hold the "to-do list" for the simplify algorithm.
  147. typedef struct {
  148. uint16_t start;
  149. uint16_t finish;
  150. } simplify_start_finish_t;
  151. struct {
  152. bool complete; // true after simplify_detection has completed
  153. bool removal_required; // true if some simplify-able points have been found on the path, set true by detect_simplifications, set false by remove_points_by_simplify_bitmask
  154. uint16_t path_points_count; // copy of _path_points_count taken when the simply algorithm started
  155. uint16_t path_points_completed = SMARTRTL_POINTS_MAX; // number of points in that path that have already been simplified and should be ignored
  156. simplify_start_finish_t* stack;
  157. uint16_t stack_max; // maximum number of elements in the _simplify_stack array
  158. uint16_t stack_count; // number of elements in _simplify_stack array
  159. Bitmask<SMARTRTL_POINTS_MAX> bitmask; // simplify algorithm clears bits for each point that can be removed
  160. } _simplify;
  161. // Pruning
  162. typedef struct {
  163. uint16_t start_index; // index of the first point in the loop
  164. uint16_t end_index; // index of the last point in the loop
  165. Vector3f midpoint; // midpoint which should replace the first point when the loop is removed
  166. float length_squared; // length squared (in meters) of the loop (used so we can remove the longest loops)
  167. } prune_loop_t;
  168. struct {
  169. bool complete;
  170. uint16_t path_points_count; // copy of _path_points_count taken when the prune algorithm started
  171. uint16_t path_points_completed; // number of points in that path that have already been checked for loops and should be ignored
  172. uint16_t i; // loop search's outer loop index
  173. uint16_t j; // loop search's inner loop index
  174. prune_loop_t* loops;// the result of the pruning algorithm
  175. uint16_t loops_max; // maximum number of elements in the _prunable_loops array
  176. uint16_t loops_count; // number of elements in the _prunable_loops array
  177. } _prune;
  178. // returns true if the two loops overlap (used within add_loop to determine which loops to keep or throw away)
  179. bool loops_overlap(const prune_loop_t& loop1, const prune_loop_t& loop2) const;
  180. };