2019-08-22 09:37:25 -03:00
# include "Copter.h"
// adjust_climb_rate - hold copter at the desired distance above the
// ground; returns climb rate (in cm/s) which should be passed to
// the position controller
float Copter : : SurfaceTracking : : adjust_climb_rate ( float target_rate )
{
# if RANGEFINDER_ENABLED == ENABLED
2019-08-23 22:59:22 -03:00
// check tracking state and that range finders are healthy
2019-10-25 08:31:31 -03:00
if ( ( surface = = Surface : : NONE ) | |
( ( surface = = Surface : : GROUND ) & & ( ! copter . rangefinder_alt_ok ( ) | | ( copter . rangefinder_state . glitch_count ! = 0 ) ) ) | |
( ( surface = = Surface : : CEILING ) & & ! copter . rangefinder_up_ok ( ) ) | | ( copter . rangefinder_up_state . glitch_count ! = 0 ) ) {
2019-08-22 09:37:25 -03:00
return target_rate ;
}
2019-08-22 09:57:52 -03:00
// calculate current ekf based altitude error
const float current_alt_error = copter . pos_control - > get_alt_target ( ) - copter . inertial_nav . get_altitude ( ) ;
2019-08-22 09:37:25 -03:00
2019-08-23 22:59:22 -03:00
// init based on tracking direction/state
2019-10-25 08:31:31 -03:00
RangeFinderState & rf_state = ( surface = = Surface : : GROUND ) ? copter . rangefinder_state : copter . rangefinder_up_state ;
const float dir = ( surface = = Surface : : GROUND ) ? 1.0f : - 1.0f ;
2019-08-23 22:59:22 -03:00
2019-08-22 09:37:25 -03:00
// reset target altitude if this controller has just been engaged
2019-08-23 22:59:22 -03:00
// target has been changed between upwards vs downwards
// or glitch has cleared
2019-08-22 02:22:30 -03:00
const uint32_t now = millis ( ) ;
2019-08-23 22:59:22 -03:00
if ( ( now - last_update_ms > SURFACE_TRACKING_TIMEOUT_MS ) | |
reset_target | |
( last_glitch_cleared_ms ! = rf_state . glitch_cleared_ms ) ) {
target_dist_cm = rf_state . alt_cm + ( dir * current_alt_error ) ;
reset_target = false ;
last_glitch_cleared_ms = rf_state . glitch_cleared_ms ; \
2019-08-22 09:37:25 -03:00
}
last_update_ms = now ;
// adjust rangefinder target alt if motors have not hit their limits
if ( ( target_rate < 0 & & ! copter . motors - > limit . throttle_lower ) | | ( target_rate > 0 & & ! copter . motors - > limit . throttle_upper ) ) {
2019-08-23 22:59:22 -03:00
target_dist_cm + = dir * target_rate * copter . G_Dt ;
2019-08-22 09:37:25 -03:00
}
2019-08-22 02:22:30 -03:00
valid_for_logging = true ;
2019-08-22 09:37:25 -03:00
2019-10-31 19:43:16 -03:00
# if AC_AVOID_ENABLED == ENABLED
2019-09-19 23:07:53 -03:00
// upward facing terrain following never gets closer than avoidance margin
2019-10-25 08:31:31 -03:00
if ( surface = = Surface : : CEILING ) {
2019-09-19 23:07:53 -03:00
const float margin_cm = copter . avoid . enabled ( ) ? copter . avoid . get_margin ( ) * 100.0f : 0.0f ;
target_dist_cm = MAX ( target_dist_cm , margin_cm ) ;
}
2019-10-31 19:43:16 -03:00
# endif
2019-09-19 23:07:53 -03:00
2019-08-22 09:37:25 -03:00
// calc desired velocity correction from target rangefinder alt vs actual rangefinder alt (remove the error already passed to Altitude controller to avoid oscillations)
2019-08-23 22:59:22 -03:00
const float distance_error = ( target_dist_cm - rf_state . alt_cm ) - ( dir * current_alt_error ) ;
float velocity_correction = dir * distance_error * copter . g . rangefinder_gain ;
2019-08-22 09:37:25 -03:00
velocity_correction = constrain_float ( velocity_correction , - SURFACE_TRACKING_VELZ_MAX , SURFACE_TRACKING_VELZ_MAX ) ;
// return combined pilot climb rate + rate to correct rangefinder alt error
return ( target_rate + velocity_correction ) ;
# else
return target_rate ;
# endif
}
2019-08-22 02:22:30 -03:00
// get target altitude (in cm) above ground
2019-08-22 09:37:25 -03:00
// returns true if there is a valid target
bool Copter : : SurfaceTracking : : get_target_alt_cm ( float & _target_alt_cm ) const
{
2019-08-23 22:59:22 -03:00
// fail if we are not tracking downwards
2019-10-25 08:31:31 -03:00
if ( surface ! = Surface : : GROUND ) {
2019-08-23 22:59:22 -03:00
return false ;
}
2019-08-22 09:37:25 -03:00
// check target has been updated recently
if ( AP_HAL : : millis ( ) - last_update_ms > SURFACE_TRACKING_TIMEOUT_MS ) {
return false ;
}
2019-08-23 22:59:22 -03:00
_target_alt_cm = target_dist_cm ;
2019-08-22 09:37:25 -03:00
return true ;
}
2019-08-22 02:22:30 -03:00
// set target altitude (in cm) above ground
2019-08-22 09:37:25 -03:00
void Copter : : SurfaceTracking : : set_target_alt_cm ( float _target_alt_cm )
{
2019-08-23 22:59:22 -03:00
// fail if we are not tracking downwards
2019-10-25 08:31:31 -03:00
if ( surface ! = Surface : : GROUND ) {
2019-08-23 22:59:22 -03:00
return ;
}
target_dist_cm = _target_alt_cm ;
2019-08-22 09:37:25 -03:00
last_update_ms = AP_HAL : : millis ( ) ;
}
2019-08-23 22:59:22 -03:00
bool Copter : : SurfaceTracking : : get_dist_for_logging ( float & target_dist , float & actual_dist ) const
{
2019-10-25 08:31:31 -03:00
if ( ! valid_for_logging | | ( surface = = Surface : : NONE ) ) {
2019-08-23 22:59:22 -03:00
return false ;
}
target_dist = target_dist_cm * 0.01f ;
2019-10-25 08:31:31 -03:00
actual_dist = ( ( surface = = Surface : : GROUND ) ? copter . rangefinder_state . alt_cm : copter . rangefinder_up_state . alt_cm ) * 0.01f ;
2019-08-23 22:59:22 -03:00
return true ;
}
// set direction
2019-10-25 08:31:31 -03:00
void Copter : : SurfaceTracking : : set_surface ( Surface new_surface )
2019-08-22 02:22:30 -03:00
{
2019-10-25 08:31:31 -03:00
if ( surface = = new_surface ) {
2019-08-23 22:59:22 -03:00
return ;
}
// check we have a range finder in the correct direction
2019-10-25 08:31:31 -03:00
if ( ( new_surface = = Surface : : GROUND ) & & ! copter . rangefinder . has_orientation ( ROTATION_PITCH_270 ) ) {
2019-08-23 22:59:22 -03:00
copter . gcs ( ) . send_text ( MAV_SEVERITY_WARNING , " SurfaceTracking: no downward rangefinder " ) ;
AP_Notify : : events . user_mode_change_failed = 1 ;
return ;
}
2019-10-25 08:31:31 -03:00
if ( ( new_surface = = Surface : : CEILING ) & & ! copter . rangefinder . has_orientation ( ROTATION_PITCH_90 ) ) {
2019-08-23 22:59:22 -03:00
copter . gcs ( ) . send_text ( MAV_SEVERITY_WARNING , " SurfaceTracking: no upward rangefinder " ) ;
AP_Notify : : events . user_mode_change_failed = 1 ;
return ;
2019-08-22 02:22:30 -03:00
}
2019-10-25 08:31:31 -03:00
surface = new_surface ;
2019-08-23 22:59:22 -03:00
reset_target = true ;
2019-08-22 02:22:30 -03:00
}