2014-11-15 21:58:23 -04:00
|
|
|
/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
|
|
|
2015-08-11 03:28:42 -03:00
|
|
|
#include <AP_HAL/AP_HAL.h>
|
2014-11-15 21:58:23 -04:00
|
|
|
#include "Compass.h"
|
|
|
|
#include "AP_Compass_Backend.h"
|
|
|
|
|
2015-02-23 19:17:44 -04:00
|
|
|
extern const AP_HAL::HAL& hal;
|
|
|
|
|
2014-11-15 21:58:23 -04:00
|
|
|
AP_Compass_Backend::AP_Compass_Backend(Compass &compass) :
|
2015-02-23 19:17:44 -04:00
|
|
|
_compass(compass)
|
2015-01-19 12:58:26 -04:00
|
|
|
{}
|
|
|
|
|
|
|
|
/*
|
2015-03-18 19:15:22 -03:00
|
|
|
* A compass measurement is expected to pass through the following functions:
|
|
|
|
* 1. rotate_field - this rotates the measurement in-place from sensor frame
|
|
|
|
* to body frame
|
|
|
|
* 2. publish_raw_field - this provides an uncorrected point-sample for
|
|
|
|
* calibration libraries
|
|
|
|
* 3. correct_field - this corrects the measurement in-place for hard iron,
|
|
|
|
* soft iron, motor interference, and non-orthagonality errors
|
|
|
|
* 4. publish_unfiltered_field - this (optionally) provides a corrected
|
|
|
|
* point sample for fusion into the EKF
|
|
|
|
* 5. publish_filtered_field - legacy filtered magnetic field
|
2015-09-29 16:51:21 -03:00
|
|
|
*
|
|
|
|
* All those functions expect the mag field to be in milligauss.
|
2015-01-19 12:58:26 -04:00
|
|
|
*/
|
2015-03-18 19:15:22 -03:00
|
|
|
|
|
|
|
void AP_Compass_Backend::rotate_field(Vector3f &mag, uint8_t instance)
|
2015-02-23 19:17:44 -04:00
|
|
|
{
|
|
|
|
Compass::mag_state &state = _compass._state[instance];
|
2015-03-18 19:15:22 -03:00
|
|
|
mag.rotate(MAG_BOARD_ORIENTATION);
|
2015-01-19 12:58:26 -04:00
|
|
|
|
2015-02-23 19:17:44 -04:00
|
|
|
if (!state.external) {
|
2015-01-19 12:58:26 -04:00
|
|
|
// and add in AHRS_ORIENTATION setting if not an external compass
|
2015-03-18 19:15:22 -03:00
|
|
|
mag.rotate(_compass._board_orientation);
|
2015-03-13 02:43:34 -03:00
|
|
|
} else {
|
|
|
|
// add user selectable orientation
|
2015-03-18 19:15:22 -03:00
|
|
|
mag.rotate((enum Rotation)state.orientation.get());
|
2015-02-23 19:17:44 -04:00
|
|
|
}
|
2015-03-18 19:15:22 -03:00
|
|
|
}
|
2015-02-23 19:17:44 -04:00
|
|
|
|
2015-03-18 19:15:22 -03:00
|
|
|
void AP_Compass_Backend::publish_raw_field(const Vector3f &mag, uint32_t time_us, uint8_t instance)
|
|
|
|
{
|
|
|
|
Compass::mag_state &state = _compass._state[instance];
|
2015-02-23 19:17:44 -04:00
|
|
|
|
2015-11-19 23:09:17 -04:00
|
|
|
state.last_update_ms = AP_HAL::millis();
|
2015-10-20 23:22:24 -03:00
|
|
|
|
|
|
|
// note that we do not set last_update_usec here as otherwise the
|
|
|
|
// EKF and DCM would end up consuming compass data at the full
|
|
|
|
// sensor rate. We want them to consume only the filtered fields
|
|
|
|
|
2015-03-18 19:15:22 -03:00
|
|
|
state.raw_field = mag;
|
|
|
|
state.raw_meas_time_us = time_us;
|
|
|
|
state.updated_raw_field = true;
|
|
|
|
state.has_raw_field = true;
|
2015-03-18 20:55:22 -03:00
|
|
|
|
|
|
|
_compass._calibrator[instance].new_sample(mag);
|
2015-02-23 19:17:44 -04:00
|
|
|
}
|
|
|
|
|
2015-03-18 19:15:22 -03:00
|
|
|
void AP_Compass_Backend::correct_field(Vector3f &mag, uint8_t i)
|
2015-02-23 19:17:44 -04:00
|
|
|
{
|
|
|
|
Compass::mag_state &state = _compass._state[i];
|
2015-03-18 19:15:22 -03:00
|
|
|
|
2015-03-18 20:18:47 -03:00
|
|
|
if (state.diagonals.get().is_zero()) {
|
|
|
|
state.diagonals.set(Vector3f(1.0f,1.0f,1.0f));
|
|
|
|
}
|
|
|
|
|
2015-02-23 19:17:44 -04:00
|
|
|
const Vector3f &offsets = state.offset.get();
|
2015-03-18 20:18:47 -03:00
|
|
|
const Vector3f &diagonals = state.diagonals.get();
|
|
|
|
const Vector3f &offdiagonals = state.offdiagonals.get();
|
2015-02-23 19:17:44 -04:00
|
|
|
const Vector3f &mot = state.motor_compensation.get();
|
|
|
|
|
|
|
|
/*
|
2015-03-18 19:15:22 -03:00
|
|
|
* note that _motor_offset[] is kept even if compensation is not
|
|
|
|
* being applied so it can be logged correctly
|
2015-02-23 19:17:44 -04:00
|
|
|
*/
|
|
|
|
mag += offsets;
|
2015-05-04 23:35:20 -03:00
|
|
|
if(_compass._motor_comp_type != AP_COMPASS_MOT_COMP_DISABLED && !is_zero(_compass._thr_or_curr)) {
|
2015-02-23 19:17:44 -04:00
|
|
|
state.motor_offset = mot * _compass._thr_or_curr;
|
|
|
|
mag += state.motor_offset;
|
|
|
|
} else {
|
|
|
|
state.motor_offset.zero();
|
2015-01-19 12:58:26 -04:00
|
|
|
}
|
2015-03-18 20:18:47 -03:00
|
|
|
|
|
|
|
Matrix3f mat(
|
|
|
|
diagonals.x, offdiagonals.x, offdiagonals.y,
|
|
|
|
offdiagonals.x, diagonals.y, offdiagonals.z,
|
|
|
|
offdiagonals.y, offdiagonals.z, diagonals.z
|
|
|
|
);
|
|
|
|
|
|
|
|
mag = mat * mag;
|
2015-02-23 19:17:44 -04:00
|
|
|
}
|
2015-01-19 12:58:26 -04:00
|
|
|
|
2015-03-18 19:15:22 -03:00
|
|
|
void AP_Compass_Backend::publish_unfiltered_field(const Vector3f &mag, uint32_t time_us, uint8_t instance)
|
|
|
|
{
|
|
|
|
Compass::mag_state &state = _compass._state[instance];
|
|
|
|
|
|
|
|
state.unfiltered_field = mag;
|
|
|
|
state.raw_meas_time_us = time_us;
|
|
|
|
state.updated_unfiltered_field = true;
|
|
|
|
state.has_unfiltered_field = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
copy latest data to the frontend from a backend
|
|
|
|
*/
|
|
|
|
void AP_Compass_Backend::publish_filtered_field(const Vector3f &mag, uint8_t instance)
|
|
|
|
{
|
|
|
|
Compass::mag_state &state = _compass._state[instance];
|
|
|
|
|
|
|
|
state.field = mag;
|
|
|
|
|
2015-11-19 23:09:17 -04:00
|
|
|
state.last_update_ms = AP_HAL::millis();
|
|
|
|
state.last_update_usec = AP_HAL::micros();
|
2015-03-18 19:15:22 -03:00
|
|
|
|
|
|
|
state.has_raw_field = state.updated_raw_field;
|
|
|
|
state.updated_raw_field = false;
|
|
|
|
|
|
|
|
state.has_unfiltered_field = state.updated_unfiltered_field;
|
|
|
|
state.updated_unfiltered_field = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
register a new backend with frontend, returning instance which
|
|
|
|
should be used in publish_field()
|
|
|
|
*/
|
|
|
|
uint8_t AP_Compass_Backend::register_compass(void) const
|
|
|
|
{
|
|
|
|
return _compass.register_compass();
|
|
|
|
}
|
|
|
|
|
2015-02-23 19:17:44 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
set dev_id for an instance
|
|
|
|
*/
|
|
|
|
void AP_Compass_Backend::set_dev_id(uint8_t instance, uint32_t dev_id)
|
|
|
|
{
|
|
|
|
_compass._state[instance].dev_id.set(dev_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
set external for an instance
|
|
|
|
*/
|
|
|
|
void AP_Compass_Backend::set_external(uint8_t instance, bool external)
|
|
|
|
{
|
|
|
|
_compass._state[instance].external.set(external);
|
|
|
|
}
|