LCOV - code coverage report
Current view: top level - home/pbarker/rc/ardupilot/ArduPlane - avoidance_adsb.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 57 110 51.8 %
Date: 2026-09-09 11:02:08 Functions: 5 6 83.3 %

          Line data    Source code
       1             : 
       2             : #include <stdio.h>
       3             : #include "Plane.h"
       4             : 
       5             : #if HAL_ADSB_ENABLED || AP_ADSB_AVOIDANCE_ENABLED
       6      547089 : void Plane::avoidance_adsb_update(void)
       7             : {
       8             : #if HAL_ADSB_ENABLED
       9      547089 :     adsb.update();
      10             : #endif  // HAL_ADSB_ENABLED
      11             : #if AP_ADSB_AVOIDANCE_ENABLED
      12      547089 :     avoidance_adsb.update();
      13             : #endif  // AP_ADSB_AVOIDANCE_ENABLED
      14      547089 : }
      15             : #endif  // HAL_ADSB_ENABLED || AP_ADSB_AVOIDANCE_ENABLED
      16             : 
      17             : #if AP_ADSB_AVOIDANCE_ENABLED
      18         117 : MAV_COLLISION_ACTION AP_Avoidance_Plane::handle_avoidance(const AP_Avoidance::Obstacle *obstacle, MAV_COLLISION_ACTION requested_action)
      19             : {
      20         117 :     MAV_COLLISION_ACTION actual_action = requested_action;
      21         117 :     bool failsafe_state_change = false;
      22             : 
      23             :     // check for changes in failsafe
      24         117 :     if (!plane.failsafe.adsb) {
      25           4 :         plane.failsafe.adsb = true;
      26           4 :         failsafe_state_change = true;
      27             :         // record flight mode in case it's required for the recovery
      28           4 :         prev_control_mode_number = plane.control_mode->mode_number();
      29             :     }
      30             : 
      31             :     // take no action in some flight modes
      32         117 :     bool flightmode_prohibits_action = false;
      33         117 :     if (plane.control_mode == &plane.mode_manual ||
      34         117 :         (plane.control_mode == &plane.mode_auto && !plane.auto_state.takeoff_complete) ||
      35         117 :         (plane.flight_stage == AP_FixedWing::FlightStage::LAND) || // TODO: consider allowing action during approach
      36         117 :         plane.control_mode == &plane.mode_autotune) {
      37           0 :         flightmode_prohibits_action = true;
      38             :     }
      39             : #if HAL_QUADPLANE_ENABLED
      40         117 :     if (plane.control_mode == &plane.mode_qland) {
      41           0 :         flightmode_prohibits_action = true;
      42             :     }
      43             : #endif
      44         117 :     if (flightmode_prohibits_action) {
      45           0 :         actual_action = MAV_COLLISION_ACTION_NONE;
      46             :     }
      47             : 
      48             :     // take action based on requested action
      49         117 :     switch (actual_action) {
      50             : 
      51          40 :         case MAV_COLLISION_ACTION_RTL:
      52          40 :             if (failsafe_state_change) {
      53           1 :                 plane.set_mode(plane.mode_rtl, ModeReason::AVOIDANCE);
      54             :             }
      55          40 :             break;
      56             : 
      57           0 :         case MAV_COLLISION_ACTION_HOVER:
      58           0 :             if (failsafe_state_change) {
      59             : #if HAL_QUADPLANE_ENABLED
      60           0 :                 if (plane.quadplane.is_flying()) {
      61           0 :                     plane.set_mode(plane.mode_qloiter, ModeReason::AVOIDANCE);
      62           0 :                     break;
      63             :                 }
      64             : #endif
      65           0 :                 plane.set_mode(plane.mode_loiter, ModeReason::AVOIDANCE);
      66             :             }
      67           0 :             break;
      68             : 
      69           0 :         case MAV_COLLISION_ACTION_ASCEND_OR_DESCEND: {
      70             :             // climb or descend to avoid obstacle
      71           0 :             Location loc = plane.next_WP_loc;
      72           0 :             if (handle_avoidance_vertical(obstacle, failsafe_state_change, loc)) {
      73           0 :                 plane.set_guided_WP(loc);
      74             :             } else {
      75           0 :                 actual_action = MAV_COLLISION_ACTION_NONE;
      76             :             }
      77           0 :             break;
      78             :         }
      79          77 :         case MAV_COLLISION_ACTION_MOVE_HORIZONTALLY: {
      80             :             // move horizontally to avoid obstacle
      81          77 :             Location loc = plane.next_WP_loc;
      82          77 :             if (handle_avoidance_horizontal(obstacle, failsafe_state_change, loc)) {
      83          77 :                 plane.set_guided_WP(loc);
      84             :             } else {
      85           0 :                 actual_action = MAV_COLLISION_ACTION_NONE;
      86             :             }
      87          77 :             break;
      88             :         }
      89           0 :         case MAV_COLLISION_ACTION_MOVE_PERPENDICULAR:
      90             :         {
      91             :             // move horizontally and vertically to avoid obstacle
      92           0 :             Location loc = plane.next_WP_loc;
      93           0 :             const bool success_vert = handle_avoidance_vertical(obstacle, failsafe_state_change, loc);
      94           0 :             const bool success_hor = handle_avoidance_horizontal(obstacle, failsafe_state_change, loc);
      95           0 :             if (success_vert || success_hor) {
      96           0 :                 plane.set_guided_WP(loc);
      97             :             } else {
      98           0 :                 actual_action = MAV_COLLISION_ACTION_NONE;
      99             :             }
     100             :         }
     101           0 :             break;
     102             : 
     103             :         // unsupported actions and those that require no response
     104           0 :         case MAV_COLLISION_ACTION_NONE:
     105           0 :             return actual_action;
     106           0 :         case MAV_COLLISION_ACTION_REPORT:
     107             :         default:
     108           0 :             break;
     109             :     }
     110             : 
     111         117 :     if (failsafe_state_change) {
     112           4 :         gcs().send_text(MAV_SEVERITY_ALERT, "Avoid: Performing action: %d", actual_action);
     113             :     }
     114             : 
     115             :     // return with action taken
     116         117 :     return actual_action;
     117             : }
     118             : 
     119           7 : void AP_Avoidance_Plane::handle_recovery(RecoveryAction recovery_action)
     120             : {
     121             :     // check we are coming out of failsafe
     122           7 :     if (plane.failsafe.adsb) {
     123           4 :         plane.failsafe.adsb = false;
     124           4 :         gcs().send_text(MAV_SEVERITY_INFO, "Avoid: Resuming with action: %u", (unsigned)recovery_action);
     125             : 
     126             :         // restore flight mode if requested and user has not changed mode since
     127           4 :         if (plane.control_mode_reason == ModeReason::AVOIDANCE) {
     128           4 :             switch (recovery_action) {
     129             : 
     130           0 :             case RecoveryAction::REMAIN_IN_AVOID_ADSB:
     131             :                 // do nothing, we'll stay in the AVOID_ADSB mode which is guided which will loiter
     132           0 :                 break;
     133             : 
     134           0 :             case RecoveryAction::RESUME_PREVIOUS_FLIGHTMODE:
     135           0 :                 plane.set_mode_by_number(prev_control_mode_number, ModeReason::AVOIDANCE_RECOVERY);
     136           0 :                 break;
     137             : 
     138           0 :             case RecoveryAction::RTL:
     139           0 :                 plane.set_mode(plane.mode_rtl, ModeReason::AVOIDANCE_RECOVERY);
     140           0 :                 break;
     141             : 
     142           4 :             case RecoveryAction::RESUME_IF_AUTO_ELSE_LOITER:
     143           4 :                 if (prev_control_mode_number == Mode::Number::AUTO) {
     144           1 :                     plane.set_mode(plane.mode_auto, ModeReason::AVOIDANCE_RECOVERY);
     145             :                 } else {
     146             :                     // let ModeAvoidADSB continue in its guided
     147             :                     // behaviour, but reset the loiter location,
     148             :                     // rather than where the avoidance location was
     149           3 :                     plane.set_guided_WP(plane.current_loc);
     150             :                 }
     151           4 :                 break;
     152             : 
     153           0 :             default:
     154             :                 // user has specified an invalid recovery action;
     155             :                 // loiter where we are
     156           0 :                 plane.set_guided_WP(plane.current_loc);
     157           0 :                 break;
     158             :             } // switch
     159             :         }
     160             :     }
     161           7 : }
     162             : 
     163             : // check flight mode is avoid_adsb
     164          77 : bool AP_Avoidance_Plane::check_flightmode(bool allow_mode_change)
     165             : {
     166             :     // ensure plane is in avoid_adsb mode
     167          77 :     if (allow_mode_change && plane.control_mode != &plane.mode_avoidADSB) {
     168           2 :         plane.set_mode(plane.mode_avoidADSB, ModeReason::AVOIDANCE);
     169             :     }
     170             : 
     171             :     // check flight mode
     172          77 :     return (plane.control_mode == &plane.mode_avoidADSB);
     173             : }
     174             : 
     175           0 : bool AP_Avoidance_Plane::handle_avoidance_vertical(const AP_Avoidance::Obstacle *obstacle, bool allow_mode_change, Location &new_loc)
     176             : {
     177             :     // ensure copter is in avoid_adsb mode
     178           0 :      if (!check_flightmode(allow_mode_change)) {
     179           0 :          return false;
     180             :      }
     181             : 
     182             :      // get best vector away from obstacle
     183           0 :      if (plane.current_loc.alt > obstacle->_location.alt) {
     184             :          // should climb, set alt demand to be 10m above us, climb rate will be TECS_CLMB_MAX
     185           0 :          new_loc.set_alt_cm(plane.current_loc.alt + 1000, Location::AltFrame::ABSOLUTE);
     186           0 :          return true;
     187             : 
     188           0 :      } else if (plane.current_loc.alt > plane.g.RTL_altitude*100) {
     189             :          // should descend while above RTL alt
     190             :          // TODO: consider using a lower altitude than RTL_altitude since it's default (100m) is quite high
     191           0 :          new_loc.set_alt_cm(plane.current_loc.alt - 1000, Location::AltFrame::ABSOLUTE);
     192           0 :          return true;
     193             :      }
     194             : 
     195           0 :      return false;
     196             : }
     197             : 
     198          77 : bool AP_Avoidance_Plane::handle_avoidance_horizontal(const AP_Avoidance::Obstacle *obstacle, bool allow_mode_change, Location &new_loc)
     199             : {
     200             :     // ensure plane is in avoid_adsb mode
     201          77 :     if (!check_flightmode(allow_mode_change)) {
     202           0 :         return false;
     203             :     }
     204             : 
     205             :     // get best vector away from obstacle
     206          77 :     Vector3f velocity_neu;
     207          77 :     if (get_vector_perpendicular(obstacle, velocity_neu)) {
     208             :         // remove vertical component
     209          77 :         velocity_neu.z = 0.0f;
     210             : 
     211             :         // check for divide by zero
     212          77 :         if (is_zero(velocity_neu.x) && is_zero(velocity_neu.y)) {
     213           0 :             return false;
     214             :         }
     215             : 
     216             :         // re-normalize
     217          77 :         velocity_neu.normalize();
     218             : 
     219             :         // push vector further away.
     220          77 :         velocity_neu *= 10000;
     221             : 
     222             :         // set target
     223          77 :         new_loc.offset(velocity_neu.x, velocity_neu.y);
     224          77 :         return true;
     225             :     }
     226             : 
     227             :     // if we got this far we failed to set the new target
     228           0 :     return false;
     229             : }
     230             : 
     231             : #endif // AP_ADSB_AVOIDANCE_ENABLED

Generated by: LCOV version 1.14