2019-01-15 13:46:13 -04:00
# include "mode.h"
# include "Plane.h"
bool ModeGuided : : _enter ( )
{
plane . guided_throttle_passthru = false ;
/*
when entering guided mode we set the target as the current
location . This matches the behaviour of the copter code
*/
2022-02-09 19:44:58 -04:00
Location loc { plane . current_loc } ;
2021-06-04 05:35:23 -03:00
2021-09-10 03:28:21 -03:00
# if HAL_QUADPLANE_ENABLED
2021-06-04 05:35:23 -03:00
if ( plane . quadplane . guided_mode_enabled ( ) ) {
/*
if using Q_GUIDED_MODE then project forward by the stopping distance
*/
2023-02-12 09:33:27 -04:00
loc . offset_bearing ( degrees ( ahrs . groundspeed_vector ( ) . angle ( ) ) ,
2022-02-09 19:44:58 -04:00
plane . quadplane . stopping_distance ( ) ) ;
2021-06-04 05:35:23 -03:00
}
2021-09-10 03:28:21 -03:00
# endif
2022-10-10 18:58:30 -03:00
// set guided radius to WP_LOITER_RAD on mode change.
active_radius_m = 0 ;
2022-02-09 19:44:58 -04:00
plane . set_guided_WP ( loc ) ;
2019-01-15 13:46:13 -04:00
return true ;
}
void ModeGuided : : update ( )
{
2021-09-10 03:28:21 -03:00
# if HAL_QUADPLANE_ENABLED
2019-01-15 13:46:13 -04:00
if ( plane . auto_state . vtol_loiter & & plane . quadplane . available ( ) ) {
plane . quadplane . guided_update ( ) ;
2021-09-10 03:28:21 -03:00
return ;
2019-01-15 13:46:13 -04:00
}
2021-09-10 03:28:21 -03:00
# endif
2023-02-14 10:11:41 -04:00
// Received an external msg that guides roll in the last 3 seconds?
if ( plane . guided_state . last_forced_rpy_ms . x > 0 & &
millis ( ) - plane . guided_state . last_forced_rpy_ms . x < 3000 ) {
plane . nav_roll_cd = constrain_int32 ( plane . guided_state . forced_rpy_cd . x , - plane . roll_limit_cd , plane . roll_limit_cd ) ;
plane . update_load_factor ( ) ;
2024-08-01 00:07:38 -03:00
# if AP_PLANE_OFFBOARD_GUIDED_SLEW_ENABLED
2023-02-14 10:11:41 -04:00
// guided_state.target_heading is radians at this point between -pi and pi ( defaults to -4 )
// This function is used in Guided and AvoidADSB, check for guided
} else if ( ( plane . control_mode = = & plane . mode_guided ) & & ( plane . guided_state . target_heading_type ! = GUIDED_HEADING_NONE ) ) {
uint32_t tnow = AP_HAL : : millis ( ) ;
float delta = ( tnow - plane . guided_state . target_heading_time_ms ) * 1e-3 f ;
plane . guided_state . target_heading_time_ms = tnow ;
float error = 0.0f ;
if ( plane . guided_state . target_heading_type = = GUIDED_HEADING_HEADING ) {
2024-01-12 08:40:24 -04:00
error = wrap_PI ( plane . guided_state . target_heading - AP : : ahrs ( ) . get_yaw ( ) ) ;
2023-02-14 10:11:41 -04:00
} else {
Vector2f groundspeed = AP : : ahrs ( ) . groundspeed_vector ( ) ;
error = wrap_PI ( plane . guided_state . target_heading - atan2f ( - groundspeed . y , - groundspeed . x ) + M_PI ) ;
}
float bank_limit = degrees ( atanf ( plane . guided_state . target_heading_accel_limit / GRAVITY_MSS ) ) * 1e2 f ;
bank_limit = MIN ( bank_limit , plane . roll_limit_cd ) ;
2023-09-23 14:56:42 -03:00
// push error into AC_PID
const float desired = plane . g2 . guidedHeading . update_error ( error , delta , plane . guided_state . target_heading_limit ) ;
2023-02-14 10:11:41 -04:00
2023-09-23 14:56:42 -03:00
// Check for output saturation
plane . guided_state . target_heading_limit = fabsf ( desired ) > = bank_limit ;
2023-02-14 10:11:41 -04:00
plane . nav_roll_cd = constrain_int32 ( desired , - bank_limit , bank_limit ) ;
plane . update_load_factor ( ) ;
2024-08-01 00:07:38 -03:00
# endif // AP_PLANE_OFFBOARD_GUIDED_SLEW_ENABLED
2023-02-14 10:11:41 -04:00
} else {
plane . calc_nav_roll ( ) ;
}
if ( plane . guided_state . last_forced_rpy_ms . y > 0 & &
millis ( ) - plane . guided_state . last_forced_rpy_ms . y < 3000 ) {
2024-01-18 21:50:36 -04:00
plane . nav_pitch_cd = constrain_int32 ( plane . guided_state . forced_rpy_cd . y , plane . pitch_limit_min * 100 , plane . aparm . pitch_limit_max . get ( ) * 100 ) ;
2023-02-14 10:11:41 -04:00
} else {
plane . calc_nav_pitch ( ) ;
}
2024-01-30 19:47:57 -04:00
// Throttle output
if ( plane . guided_throttle_passthru ) {
// manual passthrough of throttle in fence breach
SRV_Channels : : set_output_scaled ( SRV_Channel : : k_throttle , plane . get_throttle_input ( true ) ) ;
} else if ( plane . aparm . throttle_cruise > 1 & &
2023-02-14 10:11:41 -04:00
plane . guided_state . last_forced_throttle_ms > 0 & &
millis ( ) - plane . guided_state . last_forced_throttle_ms < 3000 ) {
2024-01-30 19:47:57 -04:00
// Received an external msg that guides throttle in the last 3 seconds?
2023-02-14 10:11:41 -04:00
SRV_Channels : : set_output_scaled ( SRV_Channel : : k_throttle , plane . guided_state . forced_throttle ) ;
2024-01-30 19:47:57 -04:00
2023-02-14 10:11:41 -04:00
} else {
2024-01-30 19:47:57 -04:00
// TECS control
2023-02-14 10:11:41 -04:00
plane . calc_throttle ( ) ;
2024-01-30 19:47:57 -04:00
2023-02-14 10:11:41 -04:00
}
2019-01-15 13:46:13 -04:00
}
2020-08-19 04:51:00 -03:00
void ModeGuided : : navigate ( )
2020-07-29 12:01:34 -03:00
{
2022-10-10 18:58:30 -03:00
plane . update_loiter ( active_radius_m ) ;
2020-07-29 12:01:34 -03:00
}
2021-09-27 16:28:39 -03:00
bool ModeGuided : : handle_guided_request ( Location target_loc )
{
// add home alt if needed
2022-02-09 19:44:58 -04:00
if ( target_loc . relative_alt ) {
target_loc . alt + = plane . home . alt ;
target_loc . relative_alt = 0 ;
2021-09-27 16:28:39 -03:00
}
2022-02-09 19:44:58 -04:00
plane . set_guided_WP ( target_loc ) ;
2021-09-27 16:28:39 -03:00
return true ;
}
2022-10-10 18:58:30 -03:00
void ModeGuided : : set_radius_and_direction ( const float radius , const bool direction_is_ccw )
{
// constrain to (uint16_t) range for update_loiter()
active_radius_m = constrain_int32 ( fabsf ( radius ) , 0 , UINT16_MAX ) ;
plane . loiter . direction = direction_is_ccw ? - 1 : 1 ;
}
2022-12-22 15:02:17 -04:00
void ModeGuided : : update_target_altitude ( )
{
2024-08-01 00:07:38 -03:00
# if AP_PLANE_OFFBOARD_GUIDED_SLEW_ENABLED
2024-08-24 19:52:16 -03:00
// target altitude can be negative (e.g. flying below home altitude from the top of a mountain)
if ( ( ( plane . guided_state . target_alt_time_ms ! = 0 ) | | plane . guided_state . target_location . alt ! = - 1 ) ) { // target_alt now defaults to -1, and _time_ms defaults to zero.
2022-12-22 15:02:17 -04:00
// offboard altitude demanded
uint32_t now = AP_HAL : : millis ( ) ;
float delta = 1e-3 f * ( now - plane . guided_state . target_alt_time_ms ) ;
plane . guided_state . target_alt_time_ms = now ;
// determine delta accurately as a float
2024-08-24 19:52:16 -03:00
float delta_amt_f = delta * plane . guided_state . target_alt_rate ;
2022-12-22 15:02:17 -04:00
// then scale x100 to match last_target_alt and convert to a signed int32_t as it may be negative
int32_t delta_amt_i = ( int32_t ) ( 100.0 * delta_amt_f ) ;
2024-08-24 19:52:16 -03:00
// To calculate the required velocity (up or down), we need to target and current altitudes in the target frame
const Location : : AltFrame target_frame = plane . guided_state . target_location . get_alt_frame ( ) ;
int32_t target_alt_previous_cm ;
if ( plane . current_loc . initialised ( ) & & plane . guided_state . target_location . initialised ( ) & &
plane . current_loc . get_alt_cm ( target_frame , target_alt_previous_cm ) ) {
// create a new interim target location that that takes current_location and moves delta_amt_i in the right direction
int32_t temp_alt_cm = constrain_int32 ( plane . guided_state . target_location . alt , target_alt_previous_cm - delta_amt_i , target_alt_previous_cm + delta_amt_i ) ;
Location temp_location = plane . guided_state . target_location ;
temp_location . set_alt_cm ( temp_alt_cm , target_frame ) ;
// incrementally step the altitude towards the target
plane . set_target_altitude_location ( temp_location ) ;
2022-12-22 15:02:17 -04:00
}
} else
2024-08-01 00:07:38 -03:00
# endif // AP_PLANE_OFFBOARD_GUIDED_SLEW_ENABLED
2022-12-22 15:02:17 -04:00
{
Mode : : update_target_altitude ( ) ;
}
}