LCOV - code coverage report
Current view: top level - home/pbarker/rc/ardupilot/ArduSub - mode_guided.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 157 387 40.6 %
Date: 2026-09-09 11:02:08 Functions: 14 26 53.8 %

          Line data    Source code
       1             : #include "Sub.h"
       2             : 
       3             : /*
       4             :  * Init and run calls for guided flight mode
       5             :  */
       6             : 
       7             : #define GUIDED_VEL_TIMEOUT_MS       3000    // velocity controllers time out after 3 seconds with no new updates
       8             : #define GUIDED_ATTITUDE_TIMEOUT_MS  1000    // attitude controller times out after 1 second with no new updates
       9             : 
      10             : // targets for Guided_PosVelAccel mode
      11             : static Vector3p posvelaccel_pos_target_neu_cm;
      12             : static Vector3f posvelaccel_vel_target_neu_cms;
      13             : static Vector3f posvelaccel_accel_target_neu_cmss;
      14             : static uint32_t update_time_ms;
      15             : 
      16             : struct {
      17             :     uint32_t update_time_ms;
      18             :     float roll_cd;
      19             :     float pitch_cd;
      20             :     float yaw_cd;
      21             :     float climb_rate_cms;
      22             : } static guided_angle_state = {0,0.0f, 0.0f, 0.0f, 0.0f};
      23             : 
      24             : struct Guided_Limit {
      25             :     uint32_t timeout_ms;  // timeout (in seconds) from the time that guided is invoked
      26             :     float alt_min_cm;   // lower altitude limit in cm above home (0 = no limit)
      27             :     float alt_max_cm;   // upper altitude limit in cm above home (0 = no limit)
      28             :     float horiz_max_cm; // horizontal position limit in cm from where guided mode was initiated (0 = no limit)
      29             :     uint32_t start_time_ms;// system time in milliseconds that control was handed to the external computer
      30             :     Vector3f start_pos_neu_cm; // start position as a distance from home in cm.  used for checking horiz_max limit
      31             : } guided_limit;
      32             : 
      33             : // guided_init - initialise guided controller
      34           6 : bool ModeGuided::init(bool ignore_checks)
      35             : {
      36           6 :     if (!sub.position_ok() && !ignore_checks) {
      37           0 :         return false;
      38             :     }
      39             : 
      40             :     // start in position control mode
      41           6 :     guided_pos_control_start();
      42           6 :     return true;
      43             : }
      44             : 
      45             : // get_default_auto_yaw_mode - returns auto_yaw_mode based on WP_YAW_BEHAVIOR parameter
      46             : // set rtl parameter to true if this is during an RTL
      47          47 : autopilot_yaw_mode ModeGuided::get_default_auto_yaw_mode(bool rtl) const
      48             : {
      49          47 :     switch (g.wp_yaw_behavior) {
      50             : 
      51           0 :     case WP_YAW_BEHAVIOR_NONE:
      52           0 :         return AUTO_YAW_HOLD;
      53             :         break;
      54             : 
      55           0 :     case WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP_EXCEPT_RTL:
      56           0 :         if (rtl) {
      57           0 :             return AUTO_YAW_HOLD;
      58             :         } else {
      59           0 :             return AUTO_YAW_LOOK_AT_NEXT_WP;
      60             :         }
      61             :         break;
      62             : 
      63           0 :     case WP_YAW_BEHAVIOR_LOOK_AHEAD:
      64           0 :         return AUTO_YAW_LOOK_AHEAD;
      65             :         break;
      66             : 
      67          47 :     case WP_YAW_BEHAVIOR_CORRECT_XTRACK:
      68          47 :         return AUTO_YAW_CORRECT_XTRACK;
      69             :         break;
      70             : 
      71           0 :     case WP_YAW_BEHAVIOR_LOOK_AT_NEXT_WP:
      72             :     default:
      73           0 :         return AUTO_YAW_LOOK_AT_NEXT_WP;
      74             :         break;
      75             :     }
      76             : }
      77             : 
      78             : 
      79             : // initialise guided mode's position controller
      80           6 : void ModeGuided::guided_pos_control_start()
      81             : {
      82             :     // set to position control mode
      83           6 :     sub.guided_mode = Guided_WP;
      84             : 
      85             :     // initialise waypoint controller
      86           6 :     sub.wp_nav.wp_and_spline_init_m();
      87             : 
      88             :     // initialise wpnav to stopping point at current altitude
      89             :     // To-Do: set to current location if disarmed?
      90             :     // To-Do: set to stopping point altitude?
      91           6 :     Vector3f stopping_point_neu_cm;
      92           6 :     sub.wp_nav.get_wp_stopping_point_NEU_cm(stopping_point_neu_cm);
      93             : 
      94             :     // no need to check return status because terrain data is not used
      95           6 :     sub.wp_nav.set_wp_destination_NEU_cm(stopping_point_neu_cm, false);
      96             : 
      97             :     // initialise yaw
      98           6 :     sub.yaw_rate_only = false;
      99           6 :     set_auto_yaw_mode(get_default_auto_yaw_mode(false));
     100           6 : }
     101             : 
     102             : // initialise guided mode's velocity controller
     103           0 : void ModeGuided::guided_vel_control_start()
     104             : {
     105             :     // set guided_mode to velocity controller
     106           0 :     sub.guided_mode = Guided_Velocity;
     107             : 
     108             :     // initialize vertical maximum speeds and acceleration
     109             :     // All limits must be positive
     110           0 :     position_control->D_set_max_speed_accel_cm(sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
     111           0 :     position_control->D_set_correction_speed_accel_cm(sub.get_pilot_speed_dn(), g.pilot_speed_up, g.pilot_accel_z);
     112             : 
     113             :     // initialise velocity controller
     114           0 :     position_control->D_init_controller();
     115           0 :     position_control->NE_init_controller();
     116             : 
     117             :     // pilot always controls yaw
     118           0 :     sub.yaw_rate_only = false;
     119           0 :     set_auto_yaw_mode(AUTO_YAW_HOLD);
     120           0 : }
     121             : 
     122             : // initialise guided mode's posvelaccel controller
     123           2 : void ModeGuided::guided_posvelaccel_control_start()
     124             : {
     125             :     // set guided_mode to posvelaccel controller
     126           2 :     sub.guided_mode = Guided_PosVelAccel;
     127             : 
     128             :     // initialise horizontal speed, acceleration
     129           2 :     position_control->NE_set_max_speed_accel_cm(sub.wp_nav.get_default_speed_NE_cms(), sub.wp_nav.get_wp_acceleration_cmss());
     130           2 :     position_control->NE_set_correction_speed_accel_cm(sub.wp_nav.get_default_speed_NE_cms(), sub.wp_nav.get_wp_acceleration_cmss());
     131             : 
     132             :     // set vertical speed and acceleration
     133             :     // All limits must be positive
     134           2 :     position_control->D_set_max_speed_accel_cm(sub.wp_nav.get_default_speed_down_cms(), sub.wp_nav.get_default_speed_up_cms(), sub.wp_nav.get_accel_D_cmss());
     135           2 :     position_control->D_set_correction_speed_accel_cm(sub.wp_nav.get_default_speed_down_cms(), sub.wp_nav.get_default_speed_up_cms(), sub.wp_nav.get_accel_D_cmss());
     136             : 
     137             :     // initialise velocity controller
     138           2 :     position_control->D_init_controller();
     139           2 :     position_control->NE_init_controller();
     140             : 
     141             :     // pilot always controls yaw
     142           2 :     sub.yaw_rate_only = false;
     143           2 :     set_auto_yaw_mode(AUTO_YAW_HOLD);
     144           2 : }
     145             : 
     146             : // initialise guided mode's angle controller
     147           0 : void ModeGuided::guided_angle_control_start()
     148             : {
     149             :     // set guided_mode to velocity controller
     150           0 :     sub.guided_mode = Guided_Angle;
     151             : 
     152             :     // set vertical speed and acceleration
     153             :     // All limits must be positive
     154           0 :     position_control->D_set_max_speed_accel_cm(sub.wp_nav.get_default_speed_down_cms(), sub.wp_nav.get_default_speed_up_cms(), sub.wp_nav.get_accel_D_cmss());
     155           0 :     position_control->D_set_correction_speed_accel_cm(sub.wp_nav.get_default_speed_down_cms(), sub.wp_nav.get_default_speed_up_cms(), sub.wp_nav.get_accel_D_cmss());
     156             : 
     157             :     // initialise velocity controller
     158           0 :     position_control->D_init_controller();
     159             : 
     160             :     // initialise targets
     161           0 :     guided_angle_state.update_time_ms = AP_HAL::millis();
     162           0 :     guided_angle_state.roll_cd = ahrs.roll_sensor;
     163           0 :     guided_angle_state.pitch_cd = ahrs.pitch_sensor;
     164           0 :     guided_angle_state.yaw_cd = ahrs.yaw_sensor;
     165           0 :     guided_angle_state.climb_rate_cms = 0.0f;
     166             : 
     167             :     // pilot always controls yaw
     168           0 :     sub.yaw_rate_only = false;
     169           0 :     set_auto_yaw_mode(AUTO_YAW_HOLD);
     170           0 : }
     171             : 
     172             : // sets guided mode's target from a Location object
     173             : // returns false if destination could not be set (probably caused by missing terrain data)
     174             : // or if the fence is enabled and guided waypoint is outside the fence
     175           5 : bool ModeGuided::guided_set_destination(const Location& dest_loc)
     176             : {
     177             : #if AP_FENCE_ENABLED
     178             :     // reject destination outside the fence.
     179             :     // Note: there is a danger that a target specified as a terrain altitude might not be checked if the conversion to alt-above-home fails
     180           5 :     if (!sub.fence.check_location_within_fence(dest_loc)) {
     181           0 :         LOGGER_WRITE_ERROR(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
     182             :         // failure is propagated to GCS with NAK
     183           0 :         return false;
     184             :     }
     185             : #endif
     186             : 
     187             :     // ensure we are in position control mode
     188           5 :     if (sub.guided_mode != Guided_WP) {
     189           0 :         guided_pos_control_start();
     190             :     }
     191             : 
     192           5 :     if (!sub.wp_nav.set_wp_destination_loc(dest_loc)) {
     193             :         // failure to set destination can only be because of missing terrain data
     194           0 :         LOGGER_WRITE_ERROR(LogErrorSubsystem::NAVIGATION, LogErrorCode::FAILED_TO_SET_DESTINATION);
     195             :         // failure is propagated to GCS with NAK
     196           0 :         return false;
     197             :     }
     198             : 
     199             : #if HAL_LOGGING_ENABLED
     200             :     // log target
     201           5 :     sub.Log_Write_GuidedTarget(sub.guided_mode, Vector3f(dest_loc.lat, dest_loc.lng, dest_loc.alt), Vector3f(), Vector3f());
     202             : #endif
     203             : 
     204           5 :     return true;
     205             : }
     206             : 
     207             : // guided_set_destination - sets guided mode's target destination and target heading
     208             : // Returns true if the fence is enabled and guided waypoint is within the fence
     209             : // else return false if the waypoint is outside the fence
     210           0 : bool ModeGuided::guided_set_destination(const Vector3f& destination_neu_cm, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw)
     211             : {
     212             : #if AP_FENCE_ENABLED
     213             :     // reject destination if outside the fence
     214           0 :     const Location dest_loc(destination_neu_cm, Location::AltFrame::ABOVE_ORIGIN);
     215           0 :     if (!sub.fence.check_location_within_fence(dest_loc)) {
     216           0 :         LOGGER_WRITE_ERROR(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
     217             :         // failure is propagated to GCS with NAK
     218           0 :         return false;
     219             :     }
     220             : #endif
     221             : 
     222             :     // ensure we are in position control mode
     223           0 :     if (sub.guided_mode != Guided_WP) {
     224           0 :         guided_pos_control_start();
     225             :     }
     226             : 
     227             :     // set yaw state
     228           0 :     guided_set_yaw_state(use_yaw, yaw_cd, use_yaw_rate, yaw_rate_cds, relative_yaw);
     229             : 
     230           0 :     update_time_ms = AP_HAL::millis();
     231             : 
     232             :     // no need to check return status because terrain data is not used
     233           0 :     sub.wp_nav.set_wp_destination_NEU_cm(destination_neu_cm, false);
     234             : 
     235             : #if HAL_LOGGING_ENABLED
     236             :     // log target
     237           0 :     sub.Log_Write_GuidedTarget(sub.guided_mode, destination_neu_cm, Vector3f(), Vector3f());
     238             : #endif
     239             : 
     240           0 :     return true;
     241             : }
     242             : 
     243             : // guided_set_velocity - sets guided mode's target velocity
     244           0 : void ModeGuided::guided_set_velocity(const Vector3f& velocity_neu_cms)
     245             : {
     246             :     // check we are in velocity control mode
     247           0 :     if (sub.guided_mode != Guided_Velocity) {
     248           0 :         guided_vel_control_start();
     249             :     }
     250             : 
     251           0 :     update_time_ms = AP_HAL::millis();
     252             : 
     253             :     // set position controller velocity target
     254           0 :     position_control->set_vel_desired_NEU_cms(velocity_neu_cms);
     255           0 : }
     256             : 
     257             : // guided_set_velocity - sets guided mode's target velocity
     258           0 : void ModeGuided::guided_set_velocity(const Vector3f& velocity_neu_cms, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw)
     259             : {
     260             :    // check we are in velocity control mode
     261           0 :     if (sub.guided_mode != Guided_Velocity) {
     262           0 :         guided_vel_control_start();
     263             :     }
     264             : 
     265             :     // set yaw state
     266           0 :     guided_set_yaw_state(use_yaw, yaw_cd, use_yaw_rate, yaw_rate_cds, relative_yaw);
     267             : 
     268           0 :     update_time_ms = AP_HAL::millis();
     269             : 
     270             :     // set position controller velocity target
     271           0 :     position_control->set_vel_desired_NEU_cms(velocity_neu_cms);
     272             : 
     273           0 : }
     274             : 
     275             : // expose the current Guided_PosVelAccel position target so the GCS layer can
     276             : // report POSITION_TARGET_GLOBAL_INT in that submode.
     277        1865 : bool ModeGuided::get_posvelaccel_target_NEU_cm(Vector3f &pos) const
     278             : {
     279        1865 :     if (sub.guided_mode != Guided_PosVelAccel) {
     280           0 :         return false;
     281             :     }
     282        1865 :     pos = posvelaccel_pos_target_neu_cm.tofloat();
     283        1865 :     return true;
     284             : }
     285             : 
     286             : // set guided mode posvelaccel target
     287           0 : bool ModeGuided::guided_set_posvelaccel(const Vector3f& destination_neu_cm, const Vector3f& velocity_neu_cms, const Vector3f& accel_neu_cmss)
     288             : {
     289             : #if AP_FENCE_ENABLED
     290             :     // reject destination if outside the fence
     291           0 :     const Location dest_loc(destination_neu_cm, Location::AltFrame::ABOVE_ORIGIN);
     292           0 :     if (!sub.fence.check_location_within_fence(dest_loc)) {
     293           0 :         LOGGER_WRITE_ERROR(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
     294             :         // failure is propagated to GCS with NAK
     295           0 :         return false;
     296             :     }
     297             : #endif
     298             : 
     299             :     // check we are in posvelaccel control mode
     300           0 :     if (sub.guided_mode != Guided_PosVelAccel) {
     301           0 :         guided_posvelaccel_control_start();
     302             :     }
     303             : 
     304           0 :     update_time_ms = AP_HAL::millis();
     305           0 :     posvelaccel_pos_target_neu_cm = destination_neu_cm.topostype();
     306           0 :     posvelaccel_vel_target_neu_cms = velocity_neu_cms;
     307           0 :     posvelaccel_accel_target_neu_cmss = accel_neu_cmss;
     308             : 
     309           0 :     position_control->input_pos_vel_accel_NE_cm(posvelaccel_pos_target_neu_cm.xy(), posvelaccel_vel_target_neu_cms.xy(), posvelaccel_accel_target_neu_cmss.xy());
     310           0 :     float dz = posvelaccel_pos_target_neu_cm.z;
     311           0 :     position_control->input_pos_vel_accel_U_cm(dz, posvelaccel_vel_target_neu_cms.z, posvelaccel_accel_target_neu_cmss.z);
     312           0 :     posvelaccel_pos_target_neu_cm.z = dz;
     313             : 
     314             : #if HAL_LOGGING_ENABLED
     315             :     // log target
     316           0 :     sub.Log_Write_GuidedTarget(sub.guided_mode, destination_neu_cm, velocity_neu_cms, accel_neu_cmss);
     317             : #endif
     318             : 
     319           0 :     return true;
     320             : }
     321             : 
     322             : // set guided mode posvelaccel target
     323        1228 : bool ModeGuided::guided_set_posvelaccel(const Vector3f& destination_neu_cm, const Vector3f& velocity_neu_cms, const Vector3f& accel_neu_cmss, bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_yaw)
     324             : {
     325             :     #if AP_FENCE_ENABLED
     326             :     // reject destination if outside the fence
     327        1228 :     const Location dest_loc(destination_neu_cm, Location::AltFrame::ABOVE_ORIGIN);
     328        1228 :     if (!sub.fence.check_location_within_fence(dest_loc)) {
     329           0 :         LOGGER_WRITE_ERROR(LogErrorSubsystem::NAVIGATION, LogErrorCode::DEST_OUTSIDE_FENCE);
     330             :         // failure is propagated to GCS with NAK
     331           0 :         return false;
     332             :     }
     333             :     #endif
     334             : 
     335             :     // check we are in posvelaccel control mode
     336        1228 :     if (sub.guided_mode != Guided_PosVelAccel) {
     337           2 :         guided_posvelaccel_control_start();
     338             :     }
     339             : 
     340             :     // set yaw state
     341        1228 :     guided_set_yaw_state(use_yaw, yaw_cd, use_yaw_rate, yaw_rate_cds, relative_yaw);
     342             : 
     343        1228 :     update_time_ms = AP_HAL::millis();
     344             : 
     345        1228 :     posvelaccel_pos_target_neu_cm = destination_neu_cm.topostype();
     346        1228 :     posvelaccel_vel_target_neu_cms = velocity_neu_cms;
     347        1228 :     posvelaccel_accel_target_neu_cmss = accel_neu_cmss;
     348             : 
     349        1228 :     position_control->input_pos_vel_accel_NE_cm(posvelaccel_pos_target_neu_cm.xy(), posvelaccel_vel_target_neu_cms.xy(), posvelaccel_accel_target_neu_cmss.xy());
     350        1228 :     float dz = posvelaccel_pos_target_neu_cm.z;
     351        1228 :     position_control->input_pos_vel_accel_U_cm(dz, posvelaccel_vel_target_neu_cms.z, posvelaccel_accel_target_neu_cmss.z);
     352        1228 :     posvelaccel_pos_target_neu_cm.z = dz;
     353             : 
     354             : #if HAL_LOGGING_ENABLED
     355             :     // log target
     356        1228 :     sub.Log_Write_GuidedTarget(sub.guided_mode, destination_neu_cm, velocity_neu_cms, accel_neu_cmss);
     357             : #endif
     358             : 
     359        1228 :     return true;
     360             : }
     361             : 
     362             : // set guided mode angle target
     363           0 : void ModeGuided::guided_set_angle(const Quaternion &q, float climb_rate_cms)
     364             : {
     365             :     // check we are in angle control mode
     366           0 :     if (sub.guided_mode != Guided_Angle) {
     367           0 :         guided_angle_control_start();
     368             :     }
     369             : 
     370             :     // convert quaternion to euler angles
     371           0 :     q.to_euler(guided_angle_state.roll_cd, guided_angle_state.pitch_cd, guided_angle_state.yaw_cd);
     372           0 :     guided_angle_state.roll_cd = degrees(guided_angle_state.roll_cd) * 100.0f;
     373           0 :     guided_angle_state.pitch_cd = degrees(guided_angle_state.pitch_cd) * 100.0f;
     374           0 :     guided_angle_state.yaw_cd = wrap_180_cd(degrees(guided_angle_state.yaw_cd) * 100.0f);
     375             : 
     376           0 :     guided_angle_state.climb_rate_cms = climb_rate_cms;
     377           0 :     guided_angle_state.update_time_ms = AP_HAL::millis();
     378           0 : }
     379             : 
     380             : // helper function to set yaw state and targets
     381        1228 : void ModeGuided::guided_set_yaw_state(bool use_yaw, float yaw_cd, bool use_yaw_rate, float yaw_rate_cds, bool relative_angle)
     382             : {    
     383        1228 :     float current_yaw = wrap_2PI(AP::ahrs().get_yaw_rad());
     384             :     float euler_yaw_angle;
     385             :     float yaw_error;
     386             : 
     387        1228 :     euler_yaw_angle = wrap_2PI((yaw_cd * 0.01f));
     388        1228 :     yaw_error = wrap_PI(euler_yaw_angle - current_yaw);
     389             : 
     390        1228 :     int direction = 0;
     391        1228 :     if (yaw_error < 0){
     392           0 :         direction = -1;
     393             :     } else {
     394        1228 :         direction = 1;
     395             :     }
     396             : 
     397             :     /*
     398             :     case 1: target yaw only
     399             :     case 2: target yaw and yaw rate
     400             :     case 3: target yaw rate only
     401             :     case 4: hold current yaw
     402             :     */
     403        1228 :     if (use_yaw && !use_yaw_rate) {
     404           0 :         sub.yaw_rate_only = false;
     405           0 :         sub.mode_auto.set_auto_yaw_look_at_heading(yaw_cd * 0.01f, 0.0f, direction, relative_angle);
     406        1228 :     } else if (use_yaw && use_yaw_rate) { 
     407           0 :         sub.yaw_rate_only = false;
     408           0 :         sub.mode_auto.set_auto_yaw_look_at_heading(yaw_cd * 0.01f, yaw_rate_cds * 0.01f, direction, relative_angle);
     409        1228 :     } else if (!use_yaw && use_yaw_rate) {
     410           0 :         sub.yaw_rate_only = true;
     411           0 :         sub.mode_auto.set_yaw_rate(yaw_rate_cds * 0.01f);
     412             :     } else{
     413        1228 :         sub.yaw_rate_only = false;
     414        1228 :         set_auto_yaw_mode(AUTO_YAW_HOLD);
     415             :     }
     416        1228 : }
     417             : 
     418             : // guided_run - runs the guided controller
     419             : // should be called at 100hz or more
     420      171173 : void ModeGuided::run()
     421             : {
     422             :     // call the correct auto controller
     423      171173 :     switch (sub.guided_mode) {
     424             : 
     425       96369 :     case Guided_WP:
     426             :         // run position controller
     427       96369 :         guided_pos_control_run();
     428       96369 :         break;
     429             : 
     430           0 :     case Guided_Velocity:
     431             :         // run velocity controller
     432           0 :         guided_vel_control_run();
     433           0 :         break;
     434             : 
     435       74804 :     case Guided_PosVelAccel:
     436             :         // run position-velocity-acceleration controller
     437       74804 :         guided_posvelaccel_control_run();
     438       74804 :         break;
     439             : 
     440           0 :     case Guided_Angle:
     441             :         // run angle controller
     442           0 :         guided_angle_control_run();
     443           0 :         break;
     444             :     }
     445      171173 : }
     446             : 
     447             : // guided_pos_control_run - runs the guided position controller
     448             : // called from guided_run
     449       96369 : void ModeGuided::guided_pos_control_run()
     450             : {
     451             :     // if motors not enabled set throttle to zero and exit immediately
     452       96369 :     if (!motors.armed()) {
     453        4876 :         motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
     454             :         // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
     455        4876 :         attitude_control->set_throttle_out(NEUTRAL_THROTTLE,true,g.throttle_filt);
     456        4876 :         attitude_control->relax_attitude_controllers();
     457        4876 :         sub.wp_nav.wp_and_spline_init_m();
     458        4876 :         return;
     459             :     }
     460             : 
     461             :     // process pilot's yaw input
     462       91493 :     float target_yaw_rate = 0;
     463       91493 :     if (!sub.failsafe.pilot_input) {
     464             :         // get pilot's desired yaw rate
     465       91493 :         target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
     466       91493 :         if (!is_zero(target_yaw_rate)) {
     467           0 :             set_auto_yaw_mode(AUTO_YAW_HOLD);
     468             :         } else{
     469       91493 :             if (sub.yaw_rate_only){
     470           0 :                 set_auto_yaw_mode(AUTO_YAW_RATE);
     471             :             } else{
     472       91493 :                 set_auto_yaw_mode(AUTO_YAW_LOOK_AT_HEADING);
     473             :             }
     474             :         }
     475             :     }
     476             : 
     477             :     // set motors to full range
     478       91493 :     motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
     479             : 
     480             :     // run waypoint controller
     481       91493 :     sub.failsafe_terrain_set_status(sub.wp_nav.update_wpnav());
     482             : 
     483             :     float lateral_out, forward_out;
     484       91493 :     sub.translate_wpnav_rp(lateral_out, forward_out);
     485             : 
     486             :     // Send to forward/lateral outputs
     487       91493 :     motors.set_lateral(lateral_out);
     488       91493 :     motors.set_forward(forward_out);
     489             : 
     490             :     // WP_Nav has set the vertical position control targets
     491             :     // run the vertical position controller and set output throttle
     492       91493 :     position_control->D_update_controller();
     493             : 
     494             :     // call attitude controller
     495       91493 :     if (sub.auto_yaw_mode == AUTO_YAW_HOLD) {
     496             :         // roll & pitch & yaw rate from pilot
     497           0 :         attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
     498       91493 :     } else if (sub.auto_yaw_mode == AUTO_YAW_LOOK_AT_HEADING) {
     499             :         // roll, pitch from pilot, yaw & yaw_rate from auto_control
     500       91493 :         target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
     501       91493 :         attitude_control->input_euler_angle_roll_pitch_slew_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), target_yaw_rate);
     502           0 :     } else if (sub.auto_yaw_mode == AUTO_YAW_RATE) {
     503             :         // roll, pitch from pilot, yaw_rate from auto_control
     504           0 :         target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
     505           0 :         attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
     506             :     } else {
     507             :         // roll, pitch from pilot, yaw heading from auto_heading()
     508           0 :         attitude_control->input_euler_angle_roll_pitch_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
     509             :     }
     510             : }
     511             : 
     512             : // guided_vel_control_run - runs the guided velocity controller
     513             : // called from guided_run
     514           0 : void ModeGuided::guided_vel_control_run()
     515             : {
     516             :     // ifmotors not enabled set throttle to zero and exit immediately
     517           0 :     if (!motors.armed()) {
     518           0 :         motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
     519             :         // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
     520           0 :         attitude_control->set_throttle_out(NEUTRAL_THROTTLE,true,g.throttle_filt);
     521           0 :         attitude_control->relax_attitude_controllers();
     522             :         // initialise velocity controller
     523           0 :         position_control->D_init_controller();
     524           0 :         position_control->NE_init_controller();
     525           0 :         return;
     526             :     }
     527             : 
     528             :     // process pilot's yaw input
     529           0 :     float target_yaw_rate = 0;
     530           0 :     if (!sub.failsafe.pilot_input) {
     531             :         // get pilot's desired yaw rate
     532           0 :         target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
     533           0 :         if (!is_zero(target_yaw_rate)) {
     534           0 :             set_auto_yaw_mode(AUTO_YAW_HOLD);
     535             :         } else{
     536           0 :             if (sub.yaw_rate_only){
     537           0 :                 set_auto_yaw_mode(AUTO_YAW_RATE);
     538             :             } else{
     539           0 :                 set_auto_yaw_mode(AUTO_YAW_LOOK_AT_HEADING);
     540             :             }
     541             :         }
     542             :     }
     543             : 
     544             :     // set motors to full range
     545           0 :     motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
     546             : 
     547             :     // set velocity to zero if no updates received for 3 seconds
     548           0 :     uint32_t tnow = AP_HAL::millis();
     549           0 :     if (tnow - update_time_ms > GUIDED_VEL_TIMEOUT_MS && !position_control->get_vel_desired_NEU_cms().is_zero()) {
     550           0 :         position_control->set_vel_desired_NEU_cms(Vector3f(0,0,0));
     551             :     }
     552             : 
     553           0 :     position_control->NE_stop_pos_stabilisation();
     554             :     // call velocity controller which includes z axis controller
     555           0 :     position_control->NE_update_controller();
     556             : 
     557           0 :     position_control->D_set_pos_target_from_climb_rate_cms(position_control->get_vel_desired_NEU_cms().z);
     558           0 :     position_control->D_update_controller();
     559             : 
     560             :     float lateral_out, forward_out;
     561           0 :     sub.translate_pos_control_rp(lateral_out, forward_out);
     562             : 
     563             :     // Send to forward/lateral outputs
     564           0 :     motors.set_lateral(lateral_out);
     565           0 :     motors.set_forward(forward_out);
     566             : 
     567             :     // call attitude controller
     568           0 :     if (sub.auto_yaw_mode == AUTO_YAW_HOLD) {
     569             :         // roll & pitch & yaw rate from pilot
     570           0 :         attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
     571           0 :     } else if (sub.auto_yaw_mode == AUTO_YAW_LOOK_AT_HEADING) {
     572             :         // roll, pitch from pilot, yaw & yaw_rate from auto_control
     573           0 :         target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
     574           0 :         attitude_control->input_euler_angle_roll_pitch_slew_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), target_yaw_rate);
     575           0 :     } else if (sub.auto_yaw_mode == AUTO_YAW_RATE) {
     576             :         // roll, pitch from pilot, yaw_rate from auto_control
     577           0 :         target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
     578           0 :         attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
     579             :     } else {
     580             :         // roll, pitch from pilot, yaw heading from auto_heading()
     581           0 :         attitude_control->input_euler_angle_roll_pitch_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
     582             :     }
     583             : }
     584             : 
     585             : // guided_posvelaccel_control_run - runs the guided posvelaccel controller
     586             : // called from guided_run
     587       74804 : void ModeGuided::guided_posvelaccel_control_run()
     588             : {
     589             :     // if motors not enabled set throttle to zero and exit immediately
     590       74804 :     if (!motors.armed()) {
     591        2566 :         motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
     592             :         // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
     593        2566 :         attitude_control->set_throttle_out(NEUTRAL_THROTTLE,true,g.throttle_filt);
     594        2566 :         attitude_control->relax_attitude_controllers();
     595             :         // initialise velocity controller
     596        2566 :         position_control->D_init_controller();
     597        2566 :         position_control->NE_init_controller();
     598        2566 :         return;
     599             :     }
     600             : 
     601             :     // process pilot's yaw input
     602       72238 :     float target_yaw_rate = 0;
     603             : 
     604       72238 :     if (!sub.failsafe.pilot_input) {
     605             :         // get pilot's desired yaw rate
     606       72238 :         target_yaw_rate = sub.get_pilot_desired_yaw_rate(channel_yaw->get_control_in());
     607       72238 :         if (!is_zero(target_yaw_rate)) {
     608           0 :             set_auto_yaw_mode(AUTO_YAW_HOLD);
     609             :         } else{
     610       72238 :             if (sub.yaw_rate_only){
     611           0 :                 set_auto_yaw_mode(AUTO_YAW_RATE);
     612             :             } else{
     613       72238 :                 set_auto_yaw_mode(AUTO_YAW_LOOK_AT_HEADING);
     614             :             }
     615             :         }
     616             :     }
     617             : 
     618             :     // set motors to full range
     619       72238 :     motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
     620             : 
     621             :     // set velocity to zero if no updates received for 3 seconds
     622       72238 :     uint32_t tnow = AP_HAL::millis();
     623       72238 :     if (tnow - update_time_ms > GUIDED_VEL_TIMEOUT_MS && !posvelaccel_vel_target_neu_cms.is_zero()) {
     624           0 :         posvelaccel_vel_target_neu_cms.zero();
     625           0 :         posvelaccel_accel_target_neu_cmss.zero();
     626             :     }
     627             : 
     628             :     // send position and velocity targets to position controller
     629       72238 :     position_control->input_pos_vel_accel_NE_cm(posvelaccel_pos_target_neu_cm.xy(), posvelaccel_vel_target_neu_cms.xy(), posvelaccel_accel_target_neu_cmss.xy());
     630       72238 :     float pz = posvelaccel_pos_target_neu_cm.z;
     631       72238 :     position_control->input_pos_vel_accel_U_cm(pz, posvelaccel_vel_target_neu_cms.z, posvelaccel_accel_target_neu_cmss.z);
     632       72238 :     posvelaccel_pos_target_neu_cm.z = pz;
     633             : 
     634             :     // run position controller
     635       72238 :     position_control->NE_update_controller();
     636       72238 :     position_control->D_update_controller();
     637             : 
     638             :     float lateral_out, forward_out;
     639       72238 :     sub.translate_pos_control_rp(lateral_out, forward_out);
     640             : 
     641             :     // Send to forward/lateral outputs
     642       72238 :     motors.set_lateral(lateral_out);
     643       72238 :     motors.set_forward(forward_out);
     644             : 
     645             :     // call attitude controller
     646       72238 :     if (sub.auto_yaw_mode == AUTO_YAW_HOLD) {
     647             :         // roll & pitch & yaw rate from pilot
     648           0 :         attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
     649       72238 :     } else if (sub.auto_yaw_mode == AUTO_YAW_LOOK_AT_HEADING) {
     650             :         // roll, pitch from pilot, yaw & yaw_rate from auto_control
     651       72238 :         target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
     652       72238 :         attitude_control->input_euler_angle_roll_pitch_slew_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), target_yaw_rate);
     653           0 :     } else if (sub.auto_yaw_mode == AUTO_YAW_RATE) {
     654             :         // roll, pitch from pilot, and yaw_rate from auto_control
     655           0 :         target_yaw_rate = sub.yaw_look_at_heading_slew * 100.0;
     656           0 :         attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), target_yaw_rate);
     657             :     } else {
     658             :         // roll, pitch from pilot, yaw heading from auto_heading()
     659           0 :         attitude_control->input_euler_angle_roll_pitch_yaw_cd(channel_roll->get_control_in(), channel_pitch->get_control_in(), get_auto_heading(), true);
     660             :     }
     661             : }
     662             : 
     663             : // guided_angle_control_run - runs the guided angle controller
     664             : // called from guided_run
     665           0 : void ModeGuided::guided_angle_control_run()
     666             : {
     667             :     // if motors not enabled set throttle to zero and exit immediately
     668           0 :     if (!motors.armed()) {
     669           0 :         motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::GROUND_IDLE);
     670             :         // Sub vehicles do not stabilize roll/pitch/yaw when disarmed
     671           0 :         attitude_control->set_throttle_out(NEUTRAL_THROTTLE,true,g.throttle_filt);
     672           0 :         attitude_control->relax_attitude_controllers();
     673             :         // initialise velocity controller
     674           0 :         position_control->D_init_controller();
     675           0 :         return;
     676             :     }
     677             : 
     678             :     // constrain desired lean angles
     679           0 :     float roll_in = guided_angle_state.roll_cd;
     680           0 :     float pitch_in = guided_angle_state.pitch_cd;
     681           0 :     float total_in = norm(roll_in, pitch_in);
     682           0 :     float angle_max = MIN(attitude_control->get_althold_lean_angle_max_cd(), attitude_control->lean_angle_max_cd());
     683           0 :     if (total_in > angle_max) {
     684           0 :         float ratio = angle_max / total_in;
     685           0 :         roll_in *= ratio;
     686           0 :         pitch_in *= ratio;
     687             :     }
     688             : 
     689             :     // wrap yaw request
     690           0 :     float yaw_in = wrap_180_cd(guided_angle_state.yaw_cd);
     691             : 
     692             :     // constrain climb rate
     693           0 :     float climb_rate_cms = constrain_float(guided_angle_state.climb_rate_cms, -sub.wp_nav.get_default_speed_down_cms(), sub.wp_nav.get_default_speed_up_cms());
     694             : 
     695             :     // check for timeout - set lean angles and climb rate to zero if no updates received for 3 seconds
     696           0 :     uint32_t tnow = AP_HAL::millis();
     697           0 :     if (tnow - guided_angle_state.update_time_ms > GUIDED_ATTITUDE_TIMEOUT_MS) {
     698           0 :         roll_in = 0.0f;
     699           0 :         pitch_in = 0.0f;
     700           0 :         climb_rate_cms = 0.0f;
     701             :     }
     702             : 
     703             :     // set motors to full range
     704           0 :     motors.set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
     705             : 
     706             :     // call attitude controller
     707           0 :     attitude_control->input_euler_angle_roll_pitch_yaw_cd(roll_in, pitch_in, yaw_in, true);
     708             : 
     709             :     // call position controller
     710           0 :     position_control->D_set_pos_target_from_climb_rate_cms(climb_rate_cms);
     711           0 :     position_control->D_update_controller();
     712             : }
     713             : 
     714             : // Guided Limit code
     715             : 
     716             : // guided_limit_clear - clear/turn off guided limits
     717           9 : void ModeGuided::guided_limit_clear()
     718             : {
     719           9 :     guided_limit.timeout_ms = 0;
     720           9 :     guided_limit.alt_min_cm = 0.0f;
     721           9 :     guided_limit.alt_max_cm = 0.0f;
     722           9 :     guided_limit.horiz_max_cm = 0.0f;
     723           9 : }
     724             : 
     725             : 
     726             : // set_auto_yaw_mode - sets the yaw mode for auto
     727      165026 : void ModeGuided::set_auto_yaw_mode(autopilot_yaw_mode yaw_mode)
     728             : {
     729             :     // return immediately if no change
     730      165026 :     if (sub.auto_yaw_mode == yaw_mode) {
     731      162600 :         return;
     732             :     }
     733        2426 :     sub.auto_yaw_mode = yaw_mode;
     734             : 
     735             :     // perform initialisation
     736        2426 :     switch (sub.auto_yaw_mode) {
     737             :     
     738        1207 :     case AUTO_YAW_HOLD:
     739             :         // pilot controls the heading
     740        1207 :         break;
     741             : 
     742           0 :     case AUTO_YAW_LOOK_AT_NEXT_WP:
     743             :         // wpnav will initialise heading when wpnav's set_destination method is called
     744           0 :         break;
     745             : 
     746           0 :     case AUTO_YAW_ROI:
     747             :         // point towards a location held in yaw_look_at_WP
     748           0 :         sub.yaw_look_at_WP_bearing = ahrs.yaw_sensor;
     749           0 :         break;
     750             : 
     751        1206 :     case AUTO_YAW_LOOK_AT_HEADING:
     752             :         // keep heading pointing in the direction held in yaw_look_at_heading
     753             :         // caller should set the yaw_look_at_heading
     754        1206 :         break;
     755             : 
     756           0 :     case AUTO_YAW_LOOK_AHEAD:
     757             :         // Commanded Yaw to automatically look ahead.
     758           0 :         sub.yaw_look_ahead_bearing = ahrs.yaw_sensor;
     759           0 :         break;
     760             : 
     761           0 :     case AUTO_YAW_RESETTOARMEDYAW:
     762             :         // initial_armed_bearing will be set during arming so no init required
     763           0 :         break;
     764             :     
     765           0 :     case AUTO_YAW_RATE:
     766             :         // set target yaw rate to yaw_look_at_heading_slew
     767           0 :         break;
     768             :     }
     769             : }
     770             : 
     771             : // get_auto_heading - returns target heading depending upon auto_yaw_mode
     772             : // 100hz update rate
     773      562548 : float ModeGuided::get_auto_heading()
     774             : {
     775      562548 :     switch (sub.auto_yaw_mode) {
     776             : 
     777           0 :     case AUTO_YAW_ROI:
     778             :         // point towards a location held in roi_WP_neu_cm
     779           0 :         return sub.get_roi_yaw();
     780             :         break;
     781             : 
     782      163731 :     case AUTO_YAW_LOOK_AT_HEADING:
     783             :         // keep heading pointing in the direction held in yaw_look_at_heading with no pilot input allowed
     784      163731 :         return sub.yaw_look_at_heading;
     785             :         break;
     786             : 
     787           0 :     case AUTO_YAW_LOOK_AHEAD:
     788             :         // Commanded Yaw to automatically look ahead.
     789           0 :         return sub.get_look_ahead_yaw();
     790             :         break;
     791             : 
     792           0 :     case AUTO_YAW_RESETTOARMEDYAW:
     793             :         // changes yaw to be same as when quad was armed
     794           0 :         return sub.initial_armed_bearing;
     795             :         break;
     796             : 
     797      398817 :     case AUTO_YAW_CORRECT_XTRACK: {
     798             :         // TODO return current yaw if not in appropriate mode
     799             :         // Bearing of current track (centidegrees)
     800      398817 :         float track_bearing = get_bearing_cd(sub.wp_nav.get_wp_origin_NEU_cm().xy(), sub.wp_nav.get_wp_destination_NEU_cm().xy());
     801             : 
     802             :         // Bearing from current position towards intermediate position target (centidegrees)
     803      398817 :         const Vector2f target_vel_ne_cms = position_control->get_vel_target_NEU_cms().xy();
     804      398817 :         float angle_error = 0.0f;
     805      398817 :         if (target_vel_ne_cms.length() >= position_control->NE_get_max_speed_cms() * 0.1f) {
     806      393198 :             const float desired_angle_cd = degrees(target_vel_ne_cms.angle()) * 100.0f;
     807      393198 :             angle_error = wrap_180_cd(desired_angle_cd - track_bearing);
     808             :         }
     809      398817 :         float angle_limited = constrain_float(angle_error, -g.xtrack_angle_limit * 100.0f, g.xtrack_angle_limit * 100.0f);
     810      398817 :         return wrap_360_cd(track_bearing + angle_limited);
     811             :     }
     812             :     break;
     813             : 
     814           0 :     case AUTO_YAW_LOOK_AT_NEXT_WP:
     815             :     default:
     816             :         // point towards next waypoint.
     817             :         // we don't use wp_bearing because we don't want the vehicle to turn too much during flight
     818           0 :         return sub.wp_nav.get_yaw();
     819             :         break;
     820             :     }
     821             : }
     822             : // guided_limit_set - set guided timeout and movement limits
     823           0 : void ModeGuided::guided_limit_set(uint32_t timeout_ms, float alt_min_cm, float alt_max_cm, float horiz_max_cm)
     824             : {
     825           0 :     guided_limit.timeout_ms = timeout_ms;
     826           0 :     guided_limit.alt_min_cm = alt_min_cm;
     827           0 :     guided_limit.alt_max_cm = alt_max_cm;
     828           0 :     guided_limit.horiz_max_cm = horiz_max_cm;
     829           0 : }
     830             : 
     831             : // guided_limit_init_time_and_pos - initialise guided start time and position as reference for limit checking
     832             : //  only called from AUTO mode's auto_nav_guided_start function
     833           0 : void ModeGuided::guided_limit_init_time_and_pos()
     834             : {
     835             :     // initialise start time
     836           0 :     guided_limit.start_time_ms = AP_HAL::millis();
     837             : 
     838             :     // initialise start position from current position
     839           0 :     Vector3f pos_cm = (position_control->get_pos_estimate_NED_m() * 100.0f).tofloat();
     840           0 :     pos_cm.z = -pos_cm.z;
     841           0 :     guided_limit.start_pos_neu_cm = pos_cm;
     842           0 : }
     843             : 
     844             : // guided_limit_check - returns true if guided mode has breached a limit
     845             : //  used when guided is invoked from the NAV_GUIDED_ENABLE mission command
     846           0 : bool ModeGuided::guided_limit_check()
     847             : {
     848             :     // check if we have passed the timeout
     849           0 :     if ((guided_limit.timeout_ms > 0) && (AP_HAL::millis() - guided_limit.start_time_ms >= guided_limit.timeout_ms)) {
     850           0 :         return true;
     851             :     }
     852             : 
     853             :     // get current location
     854           0 :     Vector3f curr_pos_neu_cm = (position_control->get_pos_estimate_NED_m() * 100.0f).tofloat();
     855           0 :     curr_pos_neu_cm.z = -curr_pos_neu_cm.z;
     856             : 
     857             :     // check if we have gone below min alt
     858           0 :     if (!is_zero(guided_limit.alt_min_cm) && (curr_pos_neu_cm.z < guided_limit.alt_min_cm)) {
     859           0 :         return true;
     860             :     }
     861             : 
     862             :     // check if we have gone above max alt
     863           0 :     if (!is_zero(guided_limit.alt_max_cm) && (curr_pos_neu_cm.z > guided_limit.alt_max_cm)) {
     864           0 :         return true;
     865             :     }
     866             : 
     867             :     // check if we have gone beyond horizontal limit
     868           0 :     if (guided_limit.horiz_max_cm > 0.0f) {
     869           0 :         const float horiz_move_cm = get_horizontal_distance(guided_limit.start_pos_neu_cm.xy(), curr_pos_neu_cm.xy());
     870           0 :         if (horiz_move_cm > guided_limit.horiz_max_cm) {
     871           0 :             return true;
     872             :         }
     873             :     }
     874             : 
     875             :     // if we got this far we must be within limits
     876           0 :     return false;
     877             : }

Generated by: LCOV version 1.14