CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

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