diff --git a/libraries/AP_Compass/Compass.cpp b/libraries/AP_Compass/Compass.cpp index 74de9b205c..6fec1a8baa 100644 --- a/libraries/AP_Compass/Compass.cpp +++ b/libraries/AP_Compass/Compass.cpp @@ -781,3 +781,80 @@ void Compass::motor_compensation_type(const uint8_t comp_type) } } } + +uint8_t Compass::get_use_mask() const +{ + uint8_t ret = 0; + for (uint8_t i=0; i<COMPASS_MAX_INSTANCES; i++) { + if (use_for_yaw(i)) { + ret |= 1 << i; + } + } + return ret; +} + +bool Compass::consistent(uint8_t mask) const +{ + Vector3f primary_mag_field = get_field(); + float primary_mag_field_mag = primary_mag_field.length(); + Vector3f primary_mag_field_norm; + + if (!is_zero(primary_mag_field_mag)) { + primary_mag_field_norm = primary_mag_field / primary_mag_field_mag; + } else { + return false; + } + + Vector2f primary_mag_field_xy = Vector2f(primary_mag_field.x,primary_mag_field.y); + float primary_mag_field_xy_mag = primary_mag_field_xy.length(); + Vector2f primary_mag_field_xy_norm; + + if (!is_zero(primary_mag_field_xy_mag)) { + primary_mag_field_xy_norm = primary_mag_field_xy / primary_mag_field_xy_mag; + } else { + return false; + } + + for (uint8_t i=0; i<COMPASS_MAX_INSTANCES; i++) { + if ((1<<i) & mask) { + Vector3f mag_field = get_field(i); + float mag_field_mag = mag_field.length(); + Vector3f mag_field_norm; + + if (!is_zero(mag_field_mag)) { + mag_field_norm = mag_field / mag_field_mag; + } else { + return false; + } + + Vector2f mag_field_xy = Vector2f(mag_field.x,mag_field.y); + float mag_field_xy_mag = mag_field_xy.length(); + Vector2f mag_field_xy_norm; + + if (!is_zero(mag_field_xy_mag)) { + mag_field_xy_norm = mag_field_xy / mag_field_xy_mag; + } else { + return false; + } + + float xyz_ang_diff = acosf(constrain_float(mag_field_norm * primary_mag_field_norm,-1.0f,1.0f)); + float xy_ang_diff = acosf(constrain_float(mag_field_xy_norm*primary_mag_field_xy_norm,-1.0f,1.0f)); + float xy_len_diff = (primary_mag_field_xy-mag_field_xy).length(); + + // check for gross misalignment on all axes + bool xyz_ang_diff_large = xyz_ang_diff > AP_COMPASS_MAX_XYZ_ANG_DIFF; + + // check for an unacceptable angle difference on the xy plane + bool xy_ang_diff_large = xy_ang_diff > AP_COMPASS_MAX_XY_ANG_DIFF; + + // check for an unacceptable length difference on the xy plane + bool xy_length_diff_large = xy_len_diff > AP_COMPASS_MAX_XY_LENGTH_DIFF; + + // check for inconsistency in the XY plane + if (xyz_ang_diff_large || xy_ang_diff_large || xy_length_diff_large) { + return false; + } + } + } + return true; +} diff --git a/libraries/AP_Compass/Compass.h b/libraries/AP_Compass/Compass.h index b7bc794f69..e54f69872f 100644 --- a/libraries/AP_Compass/Compass.h +++ b/libraries/AP_Compass/Compass.h @@ -54,6 +54,9 @@ //MAXIMUM COMPASS REPORTS #define MAX_CAL_REPORTS 10 #define CONTINUOUS_REPORTS 0 +#define AP_COMPASS_MAX_XYZ_ANG_DIFF radians(50.0f) +#define AP_COMPASS_MAX_XY_ANG_DIFF radians(30.0f) +#define AP_COMPASS_MAX_XY_LENGTH_DIFF 100.0f class Compass { @@ -167,6 +170,10 @@ public: void send_mag_cal_progress(mavlink_channel_t chan); void send_mag_cal_report(mavlink_channel_t chan); + uint8_t get_use_mask() const; + bool consistent(uint8_t mask) const; + bool consistent() const { return consistent(get_use_mask()); } + /// Return the health of a compass bool healthy(uint8_t i) const { return _state[i].healthy; } bool healthy(void) const { return healthy(get_primary()); }