LCOV - code coverage report
Current view: top level - AR_WPNav - AR_WPNav_OA.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 82 93 88.2 %
Date: 2026-09-09 11:02:08 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :    This program is free software: you can redistribute it and/or modify
       3             :    it under the terms of the GNU General Public License as published by
       4             :    the Free Software Foundation, either version 3 of the License, or
       5             :    (at your option) any later version.
       6             : 
       7             :    This program is distributed in the hope that it will be useful,
       8             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10             :    GNU General Public License for more details.
      11             : 
      12             :    You should have received a copy of the GNU General Public License
      13             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      14             :  */
      15             : 
      16             : #include <AP_AHRS/AP_AHRS.h>
      17             : #include <AP_Math/AP_Math.h>
      18             : #include <AP_HAL/AP_HAL.h>
      19             : #include "AR_WPNav_OA.h"
      20             : #include <GCS_MAVLink/GCS.h>
      21             : #include <AP_InternalError/AP_InternalError.h>
      22             : 
      23             : extern const AP_HAL::HAL& hal;
      24             : 
      25             : // update navigation
      26      180861 : void AR_WPNav_OA::update(float dt)
      27             : {
      28             : #if AP_OAPATHPLANNER_ENABLED
      29             :     // exit immediately if no current location, origin or destination
      30      180861 :     Location current_loc;
      31             :     float speed;
      32      180861 :     if (!hal.util->get_soft_armed() || !is_destination_valid() || !AP::ahrs().get_location(current_loc) || !_atc.get_forward_speed(speed)) {
      33       10345 :         _desired_speed_limited = _atc.get_desired_speed_accel_limited(0.0f, dt);
      34       10345 :         _desired_lat_accel = 0.0f;
      35       10345 :         _desired_turn_rate_rads = 0.0f;
      36       10345 :         _oa_active = false;
      37       10490 :         return;
      38             :     }
      39             : 
      40             :     // run path planning around obstacles
      41      170516 :     bool stop_vehicle = false;
      42             : 
      43             :     // backup _origin, _destination and _next_destination when not doing oa
      44      170516 :     if (!_oa_active) {
      45      149006 :         _origin_oabak = _origin;
      46      149006 :         _destination_oabak = _destination;
      47      149006 :         _next_destination_oabak = _next_destination;
      48             :     }
      49             : 
      50      170516 :     AP_OAPathPlanner *oa = AP_OAPathPlanner::get_singleton();
      51      170516 :     if (oa != nullptr) {
      52      170516 :         Location oa_origin_new, oa_destination_new, oa_next_destination_new;
      53             :         AP_OAPathPlanner::OAPathPlannerUsed path_planner_used;
      54             :         bool dest_to_next_dest_clear;
      55      170516 :         const AP_OAPathPlanner::OA_RetState oa_retstate = oa->mission_avoidance(current_loc,
      56      170516 :                                                                                 _origin_oabak,
      57      170516 :                                                                                 _destination_oabak,
      58      170516 :                                                                                 _next_destination_oabak,
      59             :                                                                                 oa_origin_new,
      60             :                                                                                 oa_destination_new,
      61             :                                                                                 oa_next_destination_new,
      62             :                                                                                 dest_to_next_dest_clear,
      63             :                                                                                 path_planner_used);
      64             : 
      65      170516 :         switch (oa_retstate) {
      66             : 
      67      148861 :         case AP_OAPathPlanner::OA_NOT_REQUIRED:
      68      148861 :             if (_oa_active) {
      69             :                 // object avoidance has become inactive so reset target to original destination
      70           6 :                 if (!AR_WPNav::set_desired_location(_destination_oabak)) {
      71             :                     // this should never happen because we should have an EKF origin and the destination must be valid
      72           0 :                     INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
      73           0 :                     stop_vehicle = true;
      74             :                 }
      75           6 :                 _oa_active = false;
      76             :                 // ToDo: handle "if (oa->get_options() & AP_OAPathPlanner::OA_OPTION_WP_RESET)"
      77             :             }
      78      148861 :             break;
      79             : 
      80         145 :         case AP_OAPathPlanner::OA_PROCESSING:
      81             :         case AP_OAPathPlanner::OA_ERROR:
      82             :             // during processing or in case of error, slow vehicle to a stop
      83         145 :             stop_vehicle = true;
      84         145 :             _oa_active = false;
      85         145 :             break;
      86             : 
      87       21510 :         case AP_OAPathPlanner::OA_SUCCESS:
      88             :             // handling of returned destination depends upon path planner used
      89       21510 :             switch (path_planner_used) {
      90             : 
      91           0 :             case AP_OAPathPlanner::OAPathPlannerUsed::None:
      92             :             case AP_OAPathPlanner::OAPathPlannerUsed::BendyRulerVertical:
      93             :                 // this should never happen.  this means the path planner has returned success but has returned an invalid planner
      94           0 :                 INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
      95           0 :                 _oa_active = false;
      96           0 :                 stop_vehicle = true;
      97           0 :                 return;
      98             : 
      99       11461 :             case AP_OAPathPlanner::OAPathPlannerUsed::Dijkstras:
     100             :                 // Dijkstra's.  Action is only needed if path planner has just became active or the target destination's lat or lon has changed
     101       11461 :                 if (!_oa_active || !oa_destination_new.same_latlon_as(_oa_destination)) {
     102          10 :                     if (AR_WPNav::set_desired_location(oa_destination_new)) {
     103             :                         // if new target set successfully, update oa state and destination
     104          10 :                         _oa_active = true;
     105          10 :                         _oa_origin = oa_origin_new;
     106          10 :                         _oa_destination = oa_destination_new;
     107             :                     } else {
     108             :                         // this should never happen
     109           0 :                         INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
     110           0 :                         stop_vehicle = true;
     111             :                     }
     112             :                 }
     113       11461 :                 break;
     114             : 
     115       10049 :             case AP_OAPathPlanner::OAPathPlannerUsed::BendyRulerHorizontal: {
     116             :                 // BendyRuler.  Action is only needed if path planner has just became active or the target destination's lat or lon has changed
     117       10049 :                 if (!_oa_active || !oa_destination_new.same_latlon_as(_oa_destination)) {
     118         199 :                     if (AR_WPNav::set_desired_location_expect_fast_update(oa_destination_new)) {
     119             :                         // if new target set successfully, update oa state and destination
     120         199 :                         _oa_active = true;
     121         199 :                         _oa_origin = oa_origin_new;
     122         199 :                         _oa_destination = oa_destination_new;
     123             :                     } else {
     124             :                         // this should never happen
     125           0 :                         INTERNAL_ERROR(AP_InternalError::error_t::flow_of_control);
     126           0 :                         stop_vehicle = true;
     127             :                     }
     128             :                 }
     129             :             }
     130       10049 :             break;
     131             : 
     132             :             } // switch (path_planner_used) {
     133             :         } // switch (oa_retstate) {
     134             :     } // if (oa != nullptr) {
     135             : 
     136      170516 :     update_oa_distance_and_bearing_to_destination();
     137             : 
     138             :     // handle stopping vehicle if avoidance has failed
     139      170516 :     if (stop_vehicle) {
     140             :         // decelerate to speed to zero and set turn rate to zero
     141         145 :         _desired_speed_limited = _atc.get_desired_speed_accel_limited(0.0f, dt);
     142         145 :         _desired_lat_accel = 0.0f;
     143         145 :         _desired_turn_rate_rads = 0.0f;
     144         145 :         return;
     145             :     }
     146             : #endif  // AP_OAPATHPLANNER_ENABLED
     147             : 
     148             :     // call parent update
     149      170371 :     AR_WPNav::update(dt);
     150             : }
     151             : 
     152             : // set desired location and (optionally) next_destination
     153             : // next_destination should be provided if known to allow smooth cornering
     154         184 : bool AR_WPNav_OA::set_desired_location(const Location& destination, Location next_destination)
     155             : {
     156         184 :     const bool ret = AR_WPNav::set_desired_location(destination, next_destination);
     157             : 
     158         184 :     if (ret) {
     159             :         // disable object avoidance, it will be re-enabled (if necessary) on next update
     160         184 :         _oa_active = false;
     161             :     }
     162             : 
     163         184 :     return ret;
     164             : }
     165             : 
     166             : // true if vehicle has reached desired location. defaults to true because this is normally used by missions and we do not want the mission to become stuck
     167      229165 : bool AR_WPNav_OA::reached_destination() const
     168             : {
     169             :     // object avoidance should always be deactivated before reaching final destination
     170      229165 :     if (_oa_active) {
     171       29436 :         return false;
     172             :     }
     173             : 
     174      199729 :     return AR_WPNav::reached_destination();
     175             : }
     176             : 
     177             : // get object avoidance adjusted origin. Note: this is not guaranteed to be valid (i.e. _orig_and_dest_valid is not checked)
     178      170371 : const Location &AR_WPNav_OA::get_oa_origin() const
     179             : {
     180      170371 :     if (_oa_active) {
     181       21510 :         return _oa_origin;
     182             :     }
     183             : 
     184      148861 :     return _origin;
     185             : }
     186             : 
     187             : // get object avoidance adjusted destination. Note: this is not guaranteed to be valid (i.e. _orig_and_dest_valid is not checked)
     188      206285 : const Location &AR_WPNav_OA::get_oa_destination() const
     189             : {
     190      206285 :     if (_oa_active) {
     191       25812 :         return _oa_destination;
     192             :     }
     193             : 
     194      180473 :     return AR_WPNav::get_oa_destination();
     195             : }
     196             : 
     197             : // return the heading (in centi-degrees) to the next waypoint accounting for OA, (used by sailboats)
     198      181534 : float AR_WPNav_OA::oa_wp_bearing_cd() const
     199             : {
     200      181534 :     if (_oa_active) {
     201       21718 :         return _oa_wp_bearing_cd;
     202             :     }
     203             : 
     204      159816 :     return AR_WPNav::oa_wp_bearing_cd();
     205             : }
     206             : 
     207             : // update distance from vehicle's current position to destination
     208      170516 : void AR_WPNav_OA::update_oa_distance_and_bearing_to_destination()
     209             : {
     210             :     // update OA adjusted values
     211      170516 :     Location current_loc;
     212      170516 :     if (_oa_active && AP::ahrs().get_location(current_loc)) {
     213       21510 :         _oa_distance_to_destination = current_loc.get_distance(_oa_destination);
     214       21510 :         _oa_wp_bearing_cd = current_loc.get_bearing_to(_oa_destination);
     215             :     } else {
     216      149006 :         _oa_distance_to_destination = AR_WPNav::get_distance_to_destination();
     217      149006 :         _oa_wp_bearing_cd = AR_WPNav::wp_bearing_cd();
     218             :     }
     219      170516 : }

Generated by: LCOV version 1.14