You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
5.5 KiB
179 lines
5.5 KiB
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- |
|
#include <AP_HAL/AP_HAL.h> |
|
#include "AC_PrecLand.h" |
|
#include "AC_PrecLand_Backend.h" |
|
#include "AC_PrecLand_Companion.h" |
|
#include "AC_PrecLand_IRLock.h" |
|
|
|
extern const AP_HAL::HAL& hal; |
|
|
|
const AP_Param::GroupInfo AC_PrecLand::var_info[] = { |
|
// @DisplayName: Precision Land enabled/disabled and behaviour |
|
// @Description: Precision Land enabled/disabled and behaviour |
|
// @Values: 0:Disabled, 1:Enabled Always Land, 2:Enabled Strict |
|
// @User: Advanced |
|
AP_GROUPINFO("ENABLED", 0, AC_PrecLand, _enabled, 0), |
|
|
|
// @Param: TYPE |
|
// @DisplayName: Precision Land Type |
|
// @Description: Precision Land Type |
|
// @Values: 0:None, 1:CompanionComputer, 2:IRLock |
|
// @User: Advanced |
|
AP_GROUPINFO("TYPE", 1, AC_PrecLand, _type, 0), |
|
|
|
// @Param: SPEED |
|
// @DisplayName: Precision Land horizontal speed maximum in cm/s |
|
// @Description: Precision Land horizontal speed maximum in cm/s |
|
// @Range: 0 500 |
|
// @User: Advanced |
|
AP_GROUPINFO("SPEED", 2, AC_PrecLand, _speed_xy, AC_PRECLAND_SPEED_XY_DEFAULT), |
|
|
|
AP_GROUPEND |
|
}; |
|
|
|
// Default constructor. |
|
// Note that the Vector/Matrix constructors already implicitly zero |
|
// their values. |
|
// |
|
AC_PrecLand::AC_PrecLand(const AP_AHRS& ahrs, const AP_InertialNav& inav, |
|
AC_PI_2D& pi_precland_xy, float dt) : |
|
_ahrs(ahrs), |
|
_inav(inav), |
|
_pi_precland_xy(pi_precland_xy), |
|
_dt(dt), |
|
_have_estimate(false), |
|
_backend(NULL) |
|
{ |
|
// set parameters to defaults |
|
AP_Param::setup_object_defaults(this, var_info); |
|
|
|
// other initialisation |
|
_backend_state.healthy = false; |
|
} |
|
|
|
|
|
// init - perform any required initialisation of backends |
|
void AC_PrecLand::init() |
|
{ |
|
// exit immediately if init has already been run |
|
if (_backend != NULL) { |
|
return; |
|
} |
|
|
|
// default health to false |
|
_backend = NULL; |
|
_backend_state.healthy = false; |
|
|
|
// instantiate backend based on type parameter |
|
switch ((enum PrecLandType)(_type.get())) { |
|
// no type defined |
|
case PRECLAND_TYPE_NONE: |
|
default: |
|
return; |
|
// companion computer |
|
case PRECLAND_TYPE_COMPANION: |
|
_backend = new AC_PrecLand_Companion(*this, _backend_state); |
|
break; |
|
// IR Lock |
|
#if CONFIG_HAL_BOARD == HAL_BOARD_PX4 || CONFIG_HAL_BOARD == HAL_BOARD_VRBRAIN |
|
case PRECLAND_TYPE_IRLOCK: |
|
_backend = new AC_PrecLand_IRLock(*this, _backend_state); |
|
break; |
|
#endif |
|
} |
|
|
|
// init backend |
|
if (_backend != NULL) { |
|
_backend->init(); |
|
} |
|
} |
|
|
|
// update - give chance to driver to get updates from sensor |
|
void AC_PrecLand::update(float alt_above_terrain_cm) |
|
{ |
|
// run backend update |
|
if (_backend != NULL) { |
|
// read from sensor |
|
_backend->update(); |
|
|
|
// calculate angles to target and position estimate |
|
calc_angles_and_pos(alt_above_terrain_cm); |
|
} |
|
} |
|
|
|
// get_target_shift - returns 3D vector of earth-frame position adjustments to target |
|
Vector3f AC_PrecLand::get_target_shift(const Vector3f &orig_target) |
|
{ |
|
Vector3f shift; // default shift initialised to zero |
|
|
|
// do not shift target if not enabled or no position estimate |
|
if (_backend == NULL || !_have_estimate) { |
|
return shift; |
|
} |
|
|
|
// shift is target_offset - (original target - current position) |
|
Vector3f curr_offset_from_target = orig_target - _inav.get_position(); |
|
shift = _target_pos_offset - curr_offset_from_target; |
|
shift.z = 0.0f; |
|
|
|
// record we have consumed this reading (perhaps there is a cleaner way to do this using timestamps) |
|
_have_estimate = false; |
|
|
|
// return adjusted target |
|
return shift; |
|
} |
|
|
|
// calc_angles_and_pos - converts sensor's body-frame angles to earth-frame angles and position estimate |
|
// raw sensor angles stored in _angle_to_target (might be in earth frame, or maybe body frame) |
|
// earth-frame angles stored in _ef_angle_to_target |
|
// position estimate is stored in _target_pos |
|
void AC_PrecLand::calc_angles_and_pos(float alt_above_terrain_cm) |
|
{ |
|
// exit immediately if not enabled |
|
if (_backend == NULL) { |
|
_have_estimate = false; |
|
return; |
|
} |
|
|
|
// get angles to target from backend |
|
if (!_backend->get_angle_to_target(_angle_to_target.x, _angle_to_target.y)) { |
|
_have_estimate = false; |
|
return; |
|
} |
|
|
|
float x_rad; |
|
float y_rad; |
|
|
|
if(_backend->get_frame_of_reference() == MAV_FRAME_LOCAL_NED){ |
|
//don't subtract vehicle lean angles |
|
x_rad = _angle_to_target.x; |
|
y_rad = -_angle_to_target.y; |
|
}else{ // assume MAV_FRAME_BODY_NED (i.e. a hard-mounted sensor) |
|
// subtract vehicle lean angles |
|
x_rad = _angle_to_target.x - _ahrs.roll; |
|
y_rad = -_angle_to_target.y + _ahrs.pitch; |
|
} |
|
|
|
// rotate to earth-frame angles |
|
_ef_angle_to_target.x = y_rad*_ahrs.cos_yaw() - x_rad*_ahrs.sin_yaw(); |
|
_ef_angle_to_target.y = y_rad*_ahrs.sin_yaw() + x_rad*_ahrs.cos_yaw(); |
|
|
|
// get current altitude (constrained to no lower than 50cm) |
|
float alt = max(alt_above_terrain_cm, 50.0f); |
|
|
|
// convert earth-frame angles to earth-frame position offset |
|
_target_pos_offset.x = alt*tanf(_ef_angle_to_target.x); |
|
_target_pos_offset.y = alt*tanf(_ef_angle_to_target.y); |
|
_target_pos_offset.z = 0; // not used |
|
|
|
_have_estimate = true; |
|
} |
|
|
|
// handle_msg - Process a LANDING_TARGET mavlink message |
|
void AC_PrecLand::handle_msg(mavlink_message_t* msg) |
|
{ |
|
// run backend update |
|
if (_backend != NULL) { |
|
_backend->handle_msg(msg); |
|
} |
|
}
|
|
|