LCOV - code coverage report
Current view: top level - AP_Compass - CompassCalibrator.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 4 4 100.0 %
Date: 2026-09-09 11:02:08 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "AP_Compass_config.h"
       4             : 
       5             : #if COMPASS_CAL_ENABLED
       6             : 
       7             : #include <AP_Math/AP_Math.h>
       8             : 
       9             : #define COMPASS_CAL_NUM_SPHERE_PARAMS       4
      10             : #define COMPASS_CAL_NUM_ELLIPSOID_PARAMS    9
      11             : #define COMPASS_CAL_NUM_SAMPLES             300     // number of samples required before fitting begins
      12             : 
      13             : class CompassCalibrator {
      14             : public:
      15             :     CompassCalibrator();
      16             : 
      17             :     // start or stop the calibration
      18             :     void start(bool retry, float delay, uint16_t offset_max, uint8_t compass_idx, float tolerance);
      19             :     void stop();
      20             : 
      21             :     // Update point sample
      22             :     void new_sample(const Vector3f& sample);
      23             : 
      24             :     // set compass's initial orientation and whether it should be automatically fixed (if required)
      25             :     void set_orientation(enum Rotation orientation, bool is_external, bool fix_orientation, bool always_45_deg);
      26             : 
      27             :     // running is true if actively calculating offsets, diagonals or offdiagonals
      28             :     bool running();
      29             : 
      30             :     // failed is true if any terminal failure state is hit
      31             :     bool failed();
      32             : 
      33             : 
      34             :     // update the state machine and calculate offsets, diagonals and offdiagonals
      35             :     void update();
      36             : 
      37             :     // compass calibration states - these correspond to the mavlink
      38             :     // MAG_CAL_STATUS enumeration
      39             :     enum class Status {
      40             :         NOT_STARTED = 0,
      41             :         WAITING_TO_START = 1,
      42             :         RUNNING_STEP_ONE = 2,
      43             :         RUNNING_STEP_TWO = 3,
      44             :         SUCCESS = 4,
      45             :         FAILED = 5,
      46             :         FAILED_ORIENTATION = 6,
      47             :         FAILED_RADIUS = 7,
      48             :         FAILED_OFFSETS = 8,
      49             :         FAILED_DIAG_SCALING = 9,
      50             :         FAILED_RESIDUALS_HIGH = 10,
      51             :     };
      52             : 
      53             :     // get completion mask for mavlink reporting (a bitmask of faces/directions for which we have compass samples)
      54             :     typedef uint8_t completion_mask_t[10];
      55             : 
      56             :     // Structure accessed for cal status update via mavlink 
      57             :     struct State {
      58             :         Status status;
      59             :         uint8_t attempt;
      60             :         float completion_pct;
      61             :         completion_mask_t completion_mask;
      62             :     } cal_state;
      63             : 
      64             :     // Structure accessed after calibration is finished/failed
      65             :     struct Report {
      66             :         Status status;
      67             :         float fitness;
      68             :         Vector3f ofs;
      69             :         Vector3f diag;
      70             :         Vector3f offdiag;
      71             :         float orientation_confidence;
      72             :         Rotation original_orientation;
      73             :         Rotation orientation;
      74             :         float scale_factor;
      75             :         bool check_orientation;
      76             :     } cal_report;
      77             : 
      78             :     // Structure setup to set calibration run settings
      79             :     struct Settings {
      80             :         float tolerance;
      81             :         bool check_orientation;
      82             :         enum Rotation orientation;
      83             :         enum Rotation orig_orientation;
      84             :         bool is_external;
      85             :         bool fix_orientation;
      86             :         uint16_t offset_max;
      87             :         uint8_t attempt;
      88             :         bool retry;
      89             :         float delay_start_sec;
      90             :         uint32_t start_time_ms;
      91             :         uint8_t compass_idx;
      92             :         bool always_45_deg;
      93             :     } cal_settings;
      94             : 
      95             :     // Get calibration result
      96             :     const Report get_report();
      97             :     
      98             :     // Get current Calibration state
      99             :     const State get_state();
     100             : 
     101             : protected:
     102             :     // convert index to rotation, this allows to skip some rotations
     103             :     // protected so CompassCalibrator_index_test can see it
     104             :     Rotation auto_rotation_index(uint8_t n) const;
     105             : 
     106             :     // return true if this is a right angle rotation
     107             :     bool right_angle_rotation(Rotation r) const;
     108             : 
     109             : private:
     110             : 
     111             :     // results
     112             :     class param_t {
     113             :     public:
     114       14720 :         float* get_sphere_params() {
     115       14720 :             return &radius;
     116             :         }
     117             : 
     118       68040 :         float* get_ellipsoid_params() {
     119       68040 :             return &offset.x;
     120             :         }
     121             : 
     122             :         float radius;       // magnetic field strength calculated from samples
     123             :         Vector3f offset;    // offsets
     124             :         Vector3f diag;      // diagonal scaling
     125             :         Vector3f offdiag;   // off diagonal scaling
     126             :         float scale_factor; // scaling factor to compensate for radius error
     127             :     };
     128             : 
     129             :     // compact class for approximate attitude, to save memory
     130             :     class AttitudeSample {
     131             :     public:
     132             :         Matrix3f get_rotmat() const;
     133             :         void set_from_ahrs();
     134             :     private:
     135             :         int8_t roll;
     136             :         int8_t pitch;
     137             :         int8_t yaw;
     138             :     };
     139             : 
     140             :     // compact class to hold compass samples, to save memory
     141             :     class CompassSample {
     142             :     public:
     143             :         Vector3f get() const;
     144             :         void set(const Vector3f &in);
     145             :         AttitudeSample att;
     146             :     private:
     147             :         int16_t x;
     148             :         int16_t y;
     149             :         int16_t z;
     150             :     };
     151             : 
     152             :     // set status including any required initialisation
     153             :     bool set_status(Status status);
     154             : 
     155             :     // consume point raw sample from intermediate structure
     156             :     void pull_sample();
     157             : 
     158             :     // returns true if sample should be added to buffer
     159             :     bool accept_sample(const Vector3f &sample, uint16_t skip_index = UINT16_MAX);
     160             :     bool accept_sample(const CompassSample &sample, uint16_t skip_index = UINT16_MAX);
     161             : 
     162             :     // returns specific failure Status if fit is unacceptable, SUCCESS if acceptable
     163             :     Status fit_acceptable_status() const;
     164             : 
     165             :     // clear sample buffer and reset offsets and scaling to their defaults
     166             :     void reset_state();
     167             : 
     168             :     // initialize fitness before starting a fit
     169             :     void initialize_fit();
     170             : 
     171             :     // true if enough samples have been collected and fitting has begun (aka runniong())
     172             :     bool _fitting() const;
     173             : 
     174             :     // thins out samples between step one and step two
     175             :     void thin_samples();
     176             : 
     177             :     // calc the fitness of a single sample vs a set of parameters (offsets, diagonals, off diagonals)
     178             :     float calc_residual(const Vector3f& sample, const param_t& params) const;
     179             : 
     180             :     // calc the fitness of the parameters (offsets, diagonals, off diagonals) vs all the samples collected
     181             :     // returns 1.0e30f if the sample buffer is empty
     182             :     float calc_mean_squared_residuals(const param_t& params) const;
     183             : 
     184             :     // calculate initial offsets by simply taking the average values of the samples
     185             :     void calc_initial_offset();
     186             : 
     187             :     // run sphere fit to calculate diagonals and offdiagonals
     188             :     void calc_sphere_jacob(const Vector3f& sample, const param_t& params, float* ret) const;
     189             :     void run_sphere_fit();
     190             : 
     191             :     // run ellipsoid fit to calculate diagonals and offdiagonals
     192             :     void calc_ellipsoid_jacob(const Vector3f& sample, const param_t& params, float* ret) const;
     193             :     void run_ellipsoid_fit();
     194             : 
     195             :     // update the completion mask based on a single sample
     196             :     void update_completion_mask(const Vector3f& sample);
     197             : 
     198             :     // reset and updated the completion mask using all samples in the sample buffer
     199             :     void update_completion_mask();
     200             : 
     201             :     // calculate compass orientation
     202             :     Vector3f calculate_earth_field(CompassSample &sample, enum Rotation r);
     203             :     bool calculate_orientation();
     204             : 
     205             :     // fix radius to compensate for sensor scaling errors
     206             :     bool fix_radius();
     207             : 
     208             :     // update methods to read write intermediate structures, called inside thread
     209             :     inline void update_cal_status();
     210             :     inline void update_cal_report();
     211             :     inline void update_cal_settings();
     212             : 
     213             :     // running method for use in thread
     214             :     bool _running() const;
     215             : 
     216             :     uint8_t _compass_idx;                   // index of the compass providing data
     217             :     Status _status;                         // current state of calibrator
     218             : 
     219             :     // values provided by caller
     220             :     float _delay_start_sec;                 // seconds to delay start of calibration (provided by caller)
     221             :     bool _retry;                            // true if calibration should be restarted on failured (provided by caller)
     222             :     float _tolerance = 5.0;                 // worst acceptable RMS tolerance (aka fitness).  see set_tolerance()
     223             :     uint16_t _offset_max;                   // maximum acceptable offsets (provided by caller)
     224             : 
     225             :     // behavioral state
     226             :     uint32_t _start_time_ms;                // system time start() function was last called
     227             :     uint8_t _attempt;                       // number of attempts have been made to calibrate
     228             :     completion_mask_t _completion_mask;     // bitmask of directions in which we have samples
     229             :     CompassSample *_sample_buffer;          // buffer of sensor values
     230             :     uint16_t _samples_collected;            // number of samples in buffer
     231             :     uint16_t _samples_thinned;              // number of samples removed by the thin_samples() call (called before step 2 begins)
     232             : 
     233             :     // fit state
     234             :     class param_t _params;                  // latest calibration outputs
     235             :     uint16_t _fit_step;                     // step during RUNNING_STEP_ONE/TWO which performs sphere fit and ellipsoid fit
     236             :     float _fitness;                         // fitness (mean squared residuals) of current parameters
     237             :     float _initial_fitness;                 // fitness before latest "fit" was attempted (used to determine if fit was an improvement)
     238             :     float _sphere_lambda;                   // sphere fit's lambda
     239             :     float _ellipsoid_lambda;                // ellipsoid fit's lambda
     240             : 
     241             :     // variables for orientation checking
     242             :     enum Rotation _orientation;             // latest detected orientation
     243             :     enum Rotation _orig_orientation;        // original orientation provided by caller
     244             :     enum Rotation _orientation_solution;    // latest solution
     245             :     bool _is_external;                      // true if compass is external (provided by caller)
     246             :     bool _check_orientation;                // true if orientation should be automatically checked
     247             :     bool _fix_orientation;                  // true if orientation should be fixed if necessary
     248             :     bool _always_45_deg;                    // true if orientation should consider 45deg with equal tolerance
     249             :     float _orientation_confidence;          // measure of confidence in automatic orientation detection
     250             :     CompassSample _last_sample;
     251             : 
     252             :     Status _requested_status;
     253             :     bool   _status_set_requested;
     254             :     bool   _retry_pending;
     255             :     uint32_t _retry_hold_start_ms;      // millis() when the FAILED_* status was published (retry hold timer)
     256             : 
     257             :     bool _new_sample;
     258             : 
     259             :     // Semaphore for state related intermediate structures
     260             :     HAL_Semaphore state_sem;
     261             : 
     262             :     // Semaphore for intermediate structure for point sample collection
     263             :     HAL_Semaphore sample_sem;
     264             : };
     265             : 
     266             : #endif  // COMPASS_CAL_ENABLED

Generated by: LCOV version 1.14