Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AP_Compass/AP_Compass.h
Views: 1798
#pragma once12#include "AP_Compass_config.h"34#include <inttypes.h>56#include <AP_Common/AP_Common.h>7#include <AP_Declination/AP_Declination.h>8#include <AP_HAL/AP_HAL.h>9#include <AP_Math/AP_Math.h>10#include <AP_Param/AP_Param.h>11#include <GCS_MAVLink/GCS_MAVLink.h>12#include <AP_MSP/msp.h>13#include <AP_ExternalAHRS/AP_ExternalAHRS.h>1415#include "AP_Compass_Backend.h"16#include "Compass_PerMotor.h"17#include <AP_Common/TSIndex.h>1819// motor compensation types (for use with motor_comp_enabled)20#define AP_COMPASS_MOT_COMP_DISABLED 0x0021#define AP_COMPASS_MOT_COMP_THROTTLE 0x0122#define AP_COMPASS_MOT_COMP_CURRENT 0x0223#define AP_COMPASS_MOT_COMP_PER_MOTOR 0x032425// setup default mag orientation for some board types26#ifndef MAG_BOARD_ORIENTATION27#if CONFIG_HAL_BOARD == HAL_BOARD_LINUX && CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_BEBOP28# define MAG_BOARD_ORIENTATION ROTATION_YAW_9029#elif CONFIG_HAL_BOARD == HAL_BOARD_LINUX && (CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_ERLEBRAIN2 || \30CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_PXFMINI)31# define MAG_BOARD_ORIENTATION ROTATION_YAW_27032#else33# define MAG_BOARD_ORIENTATION ROTATION_NONE34#endif35#endif3637#ifndef COMPASS_MOT_ENABLED38#define COMPASS_MOT_ENABLED 139#endif40#ifndef COMPASS_LEARN_ENABLED41#define COMPASS_LEARN_ENABLED AP_COMPASS_CALIBRATION_FIXED_YAW_ENABLED42#endif4344// define default compass calibration fitness and consistency checks45#define AP_COMPASS_CALIBRATION_FITNESS_DEFAULT 16.0f46#define AP_COMPASS_MAX_XYZ_ANG_DIFF radians(90.0f)47#define AP_COMPASS_MAX_XY_ANG_DIFF radians(60.0f)48#define AP_COMPASS_MAX_XY_LENGTH_DIFF 200.0f4950/**51maximum number of compass instances available on this platform. If more52than 1 then redundant sensors may be available53*/54#ifndef HAL_BUILD_AP_PERIPH55#ifndef HAL_COMPASS_MAX_SENSORS56#define HAL_COMPASS_MAX_SENSORS 357#endif58#if HAL_COMPASS_MAX_SENSORS > 159#define COMPASS_MAX_UNREG_DEV 560#else61#define COMPASS_MAX_UNREG_DEV 062#endif63#else64#ifndef HAL_COMPASS_MAX_SENSORS65#define HAL_COMPASS_MAX_SENSORS 166#endif67#define COMPASS_MAX_UNREG_DEV 068#endif6970#define COMPASS_MAX_INSTANCES HAL_COMPASS_MAX_SENSORS71#define COMPASS_MAX_BACKEND HAL_COMPASS_MAX_SENSORS7273#define MAX_CONNECTED_MAGS (COMPASS_MAX_UNREG_DEV+COMPASS_MAX_INSTANCES)7475#include "CompassCalibrator.h"7677class CompassLearn;7879class Compass80{81friend class AP_Compass_Backend;82public:83Compass();8485/* Do not allow copies */86CLASS_NO_COPY(Compass);8788// get singleton instance89static Compass *get_singleton() {90return _singleton;91}9293friend class CompassLearn;9495/// Initialize the compass device.96///97/// @returns True if the compass was initialized OK, false if it was not98/// found or is not functioning.99///100void init();101102/// Read the compass and update the mag_ variables.103///104bool read();105106// available returns true if the compass is both enabled and has107// been initialised108bool available() const { return _enabled && init_done; }109110/// Calculate the tilt-compensated heading_ variables.111///112/// @param dcm_matrix The current orientation rotation matrix113///114/// @returns heading in radians115///116float calculate_heading(const Matrix3f &dcm_matrix) const {117return calculate_heading(dcm_matrix, _first_usable);118}119float calculate_heading(const Matrix3f &dcm_matrix, uint8_t i) const;120121/// Sets offset x/y/z values.122///123/// @param i compass instance124/// @param offsets Offsets to the raw mag_ values in milligauss.125///126void set_offsets(uint8_t i, const Vector3f &offsets);127128/// Sets and saves the compass offset x/y/z values.129///130/// @param i compass instance131/// @param offsets Offsets to the raw mag_ values in milligauss.132///133void set_and_save_offsets(uint8_t i, const Vector3f &offsets);134#if AP_COMPASS_DIAGONALS_ENABLED135void set_and_save_diagonals(uint8_t i, const Vector3f &diagonals);136void set_and_save_offdiagonals(uint8_t i, const Vector3f &diagonals);137#endif138void set_and_save_scale_factor(uint8_t i, float scale_factor);139void set_and_save_orientation(uint8_t i, Rotation orientation);140141/// Saves the current offset x/y/z values for one or all compasses142///143/// @param i compass instance144///145/// This should be invoked periodically to save the offset values maintained by146/// ::learn_offsets.147///148void save_offsets(uint8_t i);149void save_offsets(void);150151// return the number of compass instances152uint8_t get_count(void) const { return _compass_count; }153154// return the number of enabled sensors155uint8_t get_num_enabled(void) const;156157/// Return the current field as a Vector3f in milligauss158const Vector3f &get_field(uint8_t i) const { return _get_state(Priority(i)).field; }159const Vector3f &get_field(void) const { return get_field(_first_usable); }160161/// Return true if we have set a scale factor for a compass162bool have_scale_factor(uint8_t i) const;163164#if COMPASS_MOT_ENABLED165// per-motor calibration access166void per_motor_calibration_start(void) {167_per_motor.calibration_start();168}169void per_motor_calibration_update(void) {170_per_motor.calibration_update();171}172void per_motor_calibration_end(void) {173_per_motor.calibration_end();174}175#endif176177#if COMPASS_CAL_ENABLED178// compass calibrator interface179void cal_update();180181// start_calibration_all will only return false if there are no182// compasses to calibrate.183bool start_calibration_all(bool retry=false, bool autosave=false, float delay_sec=0.0f, bool autoreboot = false);184185void cancel_calibration_all();186187bool compass_cal_requires_reboot() const { return _cal_requires_reboot; }188bool is_calibrating() const;189190#if HAL_MAVLINK_BINDINGS_ENABLED191/*192handle an incoming MAG_CAL command193*/194MAV_RESULT handle_mag_cal_command(const mavlink_command_int_t &packet);195196bool send_mag_cal_progress(const class GCS_MAVLINK& link);197bool send_mag_cal_report(const class GCS_MAVLINK& link);198#endif // HAL_MAVLINK_BINDINGS_ENABLED199#endif // COMPASS_CAL_ENABLED200201// indicate which bit in LOG_BITMASK indicates we should log compass readings202void set_log_bit(uint32_t log_bit) { _log_bit = log_bit; }203204// check if the compasses are pointing in the same direction205bool consistent() const;206207/// Return the health of a compass208bool healthy(uint8_t i) const;209bool healthy(void) const { return healthy(_first_usable); }210uint8_t get_healthy_mask() const;211212/// Returns the current offset values213///214/// @returns The current compass offsets in milligauss.215///216const Vector3f &get_offsets(uint8_t i) const { return _get_state(Priority(i)).offset; }217const Vector3f &get_offsets(void) const { return get_offsets(_first_usable); }218219#if AP_COMPASS_DIAGONALS_ENABLED220const Vector3f &get_diagonals(uint8_t i) const { return _get_state(Priority(i)).diagonals; }221const Vector3f &get_diagonals(void) const { return get_diagonals(_first_usable); }222223const Vector3f &get_offdiagonals(uint8_t i) const { return _get_state(Priority(i)).offdiagonals; }224const Vector3f &get_offdiagonals(void) const { return get_offdiagonals(_first_usable); }225#endif // AP_COMPASS_DIAGONALS_ENABLED226227// learn offsets accessor228bool learn_offsets_enabled() const { return _learn == LEARN_INFLIGHT; }229230/// return true if the compass should be used for yaw calculations231bool use_for_yaw(uint8_t i) const;232bool use_for_yaw(void) const;233234/// Sets the local magnetic field declination.235///236/// @param radians Local field declination.237/// @param save_to_eeprom true to save to eeprom (false saves only to memory)238///239void set_declination(float radians, bool save_to_eeprom = true);240float get_declination() const;241242bool auto_declination_enabled() const { return _auto_declination != 0; }243244// set overall board orientation245void set_board_orientation(enum Rotation orientation) {246_board_orientation = orientation;247}248249// get overall board orientation250enum Rotation get_board_orientation(void) const {251return _board_orientation;252}253254/// Set the motor compensation type255///256/// @param comp_type 0 = disabled, 1 = enabled use throttle, 2 = enabled use current257///258void motor_compensation_type(const uint8_t comp_type);259260/// get the motor compensation value.261uint8_t get_motor_compensation_type() const {262return _motor_comp_type;263}264265/// Set the motor compensation factor x/y/z values.266///267/// @param i instance of compass268/// @param offsets Offsets multiplied by the throttle value and added to the raw mag_ values.269///270void set_motor_compensation(uint8_t i, const Vector3f &motor_comp_factor);271272/// get motor compensation factors as a vector273const Vector3f& get_motor_compensation(uint8_t i) const { return _get_state(Priority(i)).motor_compensation; }274const Vector3f& get_motor_compensation(void) const { return get_motor_compensation(_first_usable); }275276/// Saves the current motor compensation x/y/z values.277///278/// This should be invoked periodically to save the offset values calculated by the motor compensation auto learning279///280void save_motor_compensation();281282/// Returns the current motor compensation offset values283///284/// @returns The current compass offsets in milligauss.285///286const Vector3f &get_motor_offsets(uint8_t i) const { return _get_state(Priority(i)).motor_offset; }287const Vector3f &get_motor_offsets(void) const { return get_motor_offsets(_first_usable); }288289/// Set the throttle as a percentage from 0.0 to 1.0290/// @param thr_pct throttle expressed as a percentage from 0 to 1.0291void set_throttle(float thr_pct) {292if (_motor_comp_type == AP_COMPASS_MOT_COMP_THROTTLE) {293_thr = thr_pct;294}295}296297#if COMPASS_MOT_ENABLED298/// Set the battery voltage for per-motor compensation299void set_voltage(float voltage) {300_per_motor.set_voltage(voltage);301}302#endif303304/// Returns True if the compasses have been configured (i.e. offsets saved)305///306/// @returns True if compass has been configured307///308bool configured(uint8_t i);309bool configured(char *failure_msg, uint8_t failure_msg_len);310311// return last update time in microseconds312uint32_t last_update_usec(void) const { return last_update_usec(_first_usable); }313uint32_t last_update_usec(uint8_t i) const { return _get_state(Priority(i)).last_update_usec; }314315uint32_t last_update_ms(void) const { return last_update_ms(_first_usable); }316uint32_t last_update_ms(uint8_t i) const { return _get_state(Priority(i)).last_update_ms; }317318static const struct AP_Param::GroupInfo var_info[];319320enum LearnType {321LEARN_NONE=0,322LEARN_INTERNAL=1,323LEARN_EKF=2,324LEARN_INFLIGHT=3325};326327// return the chosen learning type328enum LearnType get_learn_type(void) const {329return (enum LearnType)_learn.get();330}331332// set the learning type333void set_learn_type(enum LearnType type, bool save) {334if (save) {335_learn.set_and_save((int8_t)type);336} else {337_learn.set((int8_t)type);338}339}340341// return maximum allowed compass offsets342uint16_t get_offsets_max(void) const {343return (uint16_t)_offset_max.get();344}345346uint8_t get_filter_range() const { return uint8_t(_filter_range.get()); }347348#if AP_COMPASS_CALIBRATION_FIXED_YAW_ENABLED349/*350fast compass calibration given vehicle position and yaw351*/352bool mag_cal_fixed_yaw(float yaw_deg, uint8_t compass_mask,353float lat_deg, float lon_deg,354bool force_use=false);355#endif356357#if AP_COMPASS_MSP_ENABLED358void handle_msp(const MSP::msp_compass_data_message_t &pkt);359#endif360361#if AP_COMPASS_EXTERNALAHRS_ENABLED362void handle_external(const AP_ExternalAHRS::mag_data_message_t &pkt);363#endif364365// force save of current calibration as valid366void force_save_calibration(void);367368// get the first compass marked for use by COMPASSx_USE369uint8_t get_first_usable(void) const { return _first_usable; }370371private:372static Compass *_singleton;373374// Use Priority and StateIndex typesafe index types375// to distinguish between two different type of indexing376// We use StateIndex for access by Backend377// and Priority for access by Frontend378DECLARE_TYPESAFE_INDEX(Priority, uint8_t);379DECLARE_TYPESAFE_INDEX(StateIndex, uint8_t);380381/// Register a new compas driver, allocating an instance number382///383/// @param dev_id Dev ID of compass to register against384///385/// @return instance number saved against the dev id or first available empty instance number386bool register_compass(int32_t dev_id, uint8_t& instance);387388// load backend drivers389bool _add_backend(AP_Compass_Backend *backend);390void _probe_external_i2c_compasses(void);391void _detect_backends(void);392void probe_i2c_spi_compasses(void);393#if AP_COMPASS_DRONECAN_ENABLED394void probe_dronecan_compasses(void);395#endif396397#if COMPASS_CAL_ENABLED398// compass cal399void _update_calibration_trampoline();400bool _accept_calibration(uint8_t i);401bool _accept_calibration_mask(uint8_t mask);402void _cancel_calibration(uint8_t i);403void _cancel_calibration_mask(uint8_t mask);404uint8_t _get_cal_mask();405bool _start_calibration(uint8_t i, bool retry=false, float delay_sec=0.0f);406bool _start_calibration_mask(uint8_t mask, bool retry=false, bool autosave=false, float delay_sec=0.0f, bool autoreboot=false);407bool _auto_reboot() const { return _compass_cal_autoreboot; }408#if HAL_MAVLINK_BINDINGS_ENABLED409Priority next_cal_progress_idx[MAVLINK_COMM_NUM_BUFFERS];410Priority next_cal_report_idx[MAVLINK_COMM_NUM_BUFFERS];411#endif412#endif // COMPASS_CAL_ENABLED413414// see if we already have probed a i2c driver by bus number and address415bool _have_i2c_driver(uint8_t bus_num, uint8_t address) const;416417#if AP_COMPASS_CALIBRATION_FIXED_YAW_ENABLED418/*419get mag field with the effects of offsets, diagonals and420off-diagonals removed421*/422bool get_uncorrected_field(uint8_t instance, Vector3f &field) const;423#endif424425#if COMPASS_CAL_ENABLED426//keep track of which calibrators have been saved427RestrictIDTypeArray<bool, COMPASS_MAX_INSTANCES, Priority> _cal_saved;428bool _cal_autosave;429430//autoreboot after compass calibration431bool _compass_cal_autoreboot;432bool _cal_requires_reboot;433bool _cal_has_run;434#endif // COMPASS_CAL_ENABLED435436// enum of drivers for COMPASS_DISBLMSK437enum DriverType {438#if AP_COMPASS_HMC5843_ENABLED439DRIVER_HMC5843 =0,440#endif441#if AP_COMPASS_LSM303D_ENABLED442DRIVER_LSM303D =1,443#endif444#if AP_COMPASS_AK8963_ENABLED445DRIVER_AK8963 =2,446#endif447#if AP_COMPASS_BMM150_ENABLED448DRIVER_BMM150 =3,449#endif450#if AP_COMPASS_LSM9DS1_ENABLED451DRIVER_LSM9DS1 =4,452#endif453#if AP_COMPASS_LIS3MDL_ENABLED454DRIVER_LIS3MDL =5,455#endif456#if AP_COMPASS_AK09916_ENABLED457DRIVER_AK09916 =6,458#endif459#if AP_COMPASS_IST8310_ENABLED460DRIVER_IST8310 =7,461#endif462#if AP_COMPASS_ICM20948_ENABLED463DRIVER_ICM20948 =8,464#endif465#if AP_COMPASS_MMC3416_ENABLED466DRIVER_MMC3416 =9,467#endif468#if AP_COMPASS_DRONECAN_ENABLED469DRIVER_UAVCAN =11,470#endif471#if AP_COMPASS_QMC5883L_ENABLED472DRIVER_QMC5883L =12,473#endif474#if AP_COMPASS_SITL_ENABLED475DRIVER_SITL =13,476#endif477#if AP_COMPASS_MAG3110_ENABLED478DRIVER_MAG3110 =14,479#endif480#if AP_COMPASS_IST8308_ENABLED481DRIVER_IST8308 =15,482#endif483#if AP_COMPASS_RM3100_ENABLED484DRIVER_RM3100 =16,485#endif486#if AP_COMPASS_MSP_ENABLED487DRIVER_MSP =17,488#endif489#if AP_COMPASS_EXTERNALAHRS_ENABLED490DRIVER_EXTERNALAHRS =18,491#endif492#if AP_COMPASS_MMC5XX3_ENABLED493DRIVER_MMC5XX3 =19,494#endif495#if AP_COMPASS_QMC5883P_ENABLED496DRIVER_QMC5883P =20,497#endif498#if AP_COMPASS_BMM350_ENABLED499DRIVER_BMM350 =21,500#endif501#if AP_COMPASS_IIS2MDC_ENABLED502DRIVER_IIS2MDC =22,503#endif504};505506bool _driver_enabled(enum DriverType driver_type);507508// backend objects509AP_Compass_Backend *_backends[COMPASS_MAX_BACKEND];510uint8_t _backend_count;511512// whether to enable the compass drivers at all513AP_Int8 _enabled;514515// number of registered compasses.516uint8_t _compass_count;517518// number of unregistered compasses.519uint8_t _unreg_compass_count;520521// settable parameters522AP_Int8 _learn;523524// board orientation from AHRS525enum Rotation _board_orientation = ROTATION_NONE;526527// declination in radians528AP_Float _declination;529530// enable automatic declination code531AP_Int8 _auto_declination;532533// stores which bit is used to indicate we should log compass readings534uint32_t _log_bit = -1;535536// motor compensation type537// 0 = disabled, 1 = enabled for throttle, 2 = enabled for current538AP_Int8 _motor_comp_type;539540// automatic compass orientation on calibration541AP_Int8 _rotate_auto;542543// throttle expressed as a percentage from 0 ~ 1.0, used for motor compensation544float _thr;545546struct mag_state {547AP_Int8 external;548bool healthy;549bool registered;550Compass::Priority priority;551AP_Int8 orientation;552AP_Vector3f offset;553#if AP_COMPASS_DIAGONALS_ENABLED554AP_Vector3f diagonals;555AP_Vector3f offdiagonals;556#endif557AP_Float scale_factor;558559// device id detected at init.560// saved to eeprom when offsets are saved allowing ram &561// eeprom values to be compared as consistency check562AP_Int32 dev_id;563// Initialised when compass is detected564int32_t detected_dev_id;565// Initialised at boot from saved devid566int32_t expected_dev_id;567568// factors multiplied by throttle and added to compass outputs569AP_Vector3f motor_compensation;570571// latest compensation added to compass572Vector3f motor_offset;573574// corrected magnetic field strength575Vector3f field;576577// when we last got data578uint32_t last_update_ms;579uint32_t last_update_usec;580581// board specific orientation582enum Rotation rotation;583584// accumulated samples, protected by _sem, used by AP_Compass_Backend585Vector3f accum;586uint32_t accum_count;587// We only copy persistent params588void copy_from(const mag_state& state);589};590591//Create an Array of mag_state to be accessible by StateIndex only592RestrictIDTypeArray<mag_state, COMPASS_MAX_INSTANCES+1, StateIndex> _state;593594//Convert Priority to StateIndex595StateIndex _get_state_id(Priority priority) const;596//Get State Struct by Priority597const struct mag_state& _get_state(Priority priority) const { return _state[_get_state_id(priority)]; }598//Convert StateIndex to Priority599Priority _get_priority(StateIndex state_id) { return _state[state_id].priority; }600//Method to detect compass beyond initialisation stage601void _detect_runtime(void);602// This method reorganises devid list to match603// priority list, only call before detection at boot604#if COMPASS_MAX_INSTANCES > 1605void _reorder_compass_params();606#endif607// Update Priority List for Mags, by default, we just608// load them as they come up the first time609Priority _update_priority_list(int32_t dev_id);610611// method to check if the mag with the devid612// is a replacement mag613bool is_replacement_mag(uint32_t dev_id);614615//remove the devid from unreg compass list616void remove_unreg_dev_id(uint32_t devid);617618void _reset_compass_id();619//Create Arrays to be accessible by Priority only620RestrictIDTypeArray<AP_Int8, COMPASS_MAX_INSTANCES, Priority> _use_for_yaw;621#if COMPASS_MAX_INSTANCES > 1622RestrictIDTypeArray<AP_Int32, COMPASS_MAX_INSTANCES, Priority> _priority_did_stored_list;623RestrictIDTypeArray<int32_t, COMPASS_MAX_INSTANCES, Priority> _priority_did_list;624#endif625626AP_Int16 _offset_max;627628// bitmask of options629enum class Option : uint16_t {630CAL_REQUIRE_GPS = (1U<<0),631ALLOW_DRONECAN_AUTO_REPLACEMENT = (1U<<1),632};633bool option_set(Option opt) const { return (_options.get() & uint16_t(opt)) != 0; }634AP_Int16 _options;635636#if COMPASS_CAL_ENABLED637RestrictIDTypeArray<CompassCalibrator*, COMPASS_MAX_INSTANCES, Priority> _calibrator;638#endif639640#if COMPASS_MOT_ENABLED641// per-motor compass compensation642Compass_PerMotor _per_motor{*this};643#endif644645AP_Float _calibration_threshold;646647// mask of driver types to not load. Bit positions match DEVTYPE_ in backend648AP_Int32 _driver_type_mask;649650#if COMPASS_MAX_UNREG_DEV651// Put extra dev ids detected652AP_Int32 extra_dev_id[COMPASS_MAX_UNREG_DEV];653uint32_t _previously_unreg_mag[COMPASS_MAX_UNREG_DEV];654#endif655656AP_Int8 _filter_range;657658CompassLearn *learn;659bool learn_allocated;660661/// Sets the initial location used to get declination662///663/// @param latitude GPS Latitude.664/// @param longitude GPS Longitude.665///666void try_set_initial_location();667bool _initial_location_set;668669bool _cal_thread_started;670671#if AP_COMPASS_MSP_ENABLED672uint8_t msp_instance_mask;673#endif674bool init_done;675676bool suppress_devid_save;677678uint8_t _first_usable; // first compass usable based on COMPASSx_USE param679};680681namespace AP {682Compass &compass();683};684685686