Line data Source code
1 : #pragma once
2 :
3 : #include "AP_Compass_config.h"
4 :
5 : #include <inttypes.h>
6 :
7 : #include <AP_Common/AP_Common.h>
8 : #include <AP_Declination/AP_Declination.h>
9 : #include <AP_HAL/AP_HAL.h>
10 : #include <AP_Math/AP_Math.h>
11 : #include <AP_Param/AP_Param.h>
12 : #include <GCS_MAVLink/GCS_MAVLink.h>
13 : #include <AP_MSP/msp.h>
14 : #include <AP_ExternalAHRS/AP_ExternalAHRS.h>
15 :
16 : #include "AP_Compass_Backend.h"
17 : #include "Compass_PerMotor.h"
18 : #include <AP_Common/TSIndex.h>
19 :
20 : // motor compensation types (for use with motor_comp_enabled)
21 : #define AP_COMPASS_MOT_COMP_DISABLED 0x00
22 : #define AP_COMPASS_MOT_COMP_THROTTLE 0x01
23 : #define AP_COMPASS_MOT_COMP_CURRENT 0x02
24 : #define AP_COMPASS_MOT_COMP_PER_MOTOR 0x03
25 :
26 : #ifndef MAG_BOARD_ORIENTATION
27 : #define MAG_BOARD_ORIENTATION ROTATION_NONE
28 : #endif
29 :
30 : #ifndef COMPASS_MOT_ENABLED
31 : #define COMPASS_MOT_ENABLED 1
32 : #endif
33 :
34 : // define default compass calibration fitness and consistency checks
35 : #define AP_COMPASS_CALIBRATION_FITNESS_DEFAULT 16.0f
36 : #define AP_COMPASS_MAX_XYZ_ANG_DIFF radians(90.0f)
37 : #define AP_COMPASS_MAX_XY_ANG_DIFF radians(60.0f)
38 : #define AP_COMPASS_MAX_XY_LENGTH_DIFF 200.0f
39 :
40 : /**
41 : maximum number of compass instances available on this platform. If more
42 : than 1 then redundant sensors may be available
43 : */
44 : #ifndef HAL_BUILD_AP_PERIPH
45 : #ifndef HAL_COMPASS_MAX_SENSORS
46 : #define HAL_COMPASS_MAX_SENSORS 3
47 : #endif
48 : #if HAL_COMPASS_MAX_SENSORS > 1
49 : #define COMPASS_MAX_UNREG_DEV 5
50 : #else
51 : #define COMPASS_MAX_UNREG_DEV 0
52 : #endif
53 : #else
54 : #ifndef HAL_COMPASS_MAX_SENSORS
55 : #define HAL_COMPASS_MAX_SENSORS 1
56 : #endif
57 : #define COMPASS_MAX_UNREG_DEV 0
58 : #endif
59 :
60 : #define COMPASS_MAX_INSTANCES HAL_COMPASS_MAX_SENSORS
61 : #define COMPASS_MAX_BACKEND HAL_COMPASS_MAX_SENSORS
62 :
63 : #define MAX_CONNECTED_MAGS (COMPASS_MAX_UNREG_DEV+COMPASS_MAX_INSTANCES)
64 :
65 : #include "CompassCalibrator.h"
66 :
67 : class CompassLearn;
68 :
69 : class Compass
70 : {
71 : friend class AP_Compass_Backend;
72 : friend class AP_Compass_DroneCAN;
73 : public:
74 : Compass();
75 :
76 : /* Do not allow copies */
77 : CLASS_NO_COPY(Compass);
78 :
79 : // get singleton instance
80 189603252 : static Compass *get_singleton() {
81 189603252 : return _singleton;
82 : }
83 :
84 : friend class CompassLearn;
85 :
86 : /// Initialize the compass device.
87 : ///
88 : /// @returns True if the compass was initialized OK, false if it was not
89 : /// found or is not functioning.
90 : ///
91 : __INITFUNC__ void init();
92 :
93 : /// Read the compass and update the mag_ variables.
94 : ///
95 : bool read();
96 :
97 : // available returns true if the compass is both enabled and has
98 : // been initialised
99 638204228 : bool available() const { return _enabled && init_done; }
100 :
101 : /// Calculate the tilt-compensated heading_ variables.
102 : ///
103 : /// @param dcm_matrix The current orientation rotation matrix
104 : ///
105 : /// @returns heading in radians
106 : ///
107 2082 : float calculate_heading(const Matrix3f &dcm_matrix) const {
108 2082 : return calculate_heading(dcm_matrix, _first_usable);
109 : }
110 : float calculate_heading(const Matrix3f &dcm_matrix, uint8_t i) const;
111 :
112 : /// Sets offset x/y/z values.
113 : ///
114 : /// @param i compass instance
115 : /// @param offsets Offsets to the raw mag_ values in milligauss.
116 : ///
117 : void set_offsets(uint8_t i, const Vector3f &offsets);
118 :
119 : /// Sets and saves the compass offset x/y/z values.
120 : ///
121 : /// @param i compass instance
122 : /// @param offsets Offsets to the raw mag_ values in milligauss.
123 : ///
124 : void set_and_save_offsets(uint8_t i, const Vector3f &offsets);
125 : #if AP_COMPASS_DIAGONALS_ENABLED
126 : void set_and_save_diagonals(uint8_t i, const Vector3f &diagonals);
127 : void set_and_save_offdiagonals(uint8_t i, const Vector3f &diagonals);
128 : #endif
129 : void set_and_save_scale_factor(uint8_t i, float scale_factor);
130 : void set_and_save_orientation(uint8_t i, Rotation orientation);
131 :
132 : /// Saves the current offset x/y/z values for one or all compasses
133 : ///
134 : /// @param i compass instance
135 : ///
136 : void save_offsets(uint8_t i);
137 : void save_offsets(void);
138 :
139 : // return the number of compass instances
140 254660622 : uint8_t get_count(void) const { return _compass_count; }
141 :
142 : // return the number of enabled sensors
143 : uint8_t get_num_enabled(void) const;
144 :
145 : /// Return the current field as a Vector3f in milligauss
146 295898359 : const Vector3f &get_field(uint8_t i) const { return _get_state(Priority(i)).field; }
147 42966058 : const Vector3f &get_field(void) const { return get_field(_first_usable); }
148 :
149 : /// Return true if we have set a scale factor for a compass
150 : bool have_scale_factor(uint8_t i) const;
151 :
152 : #if COMPASS_MOT_ENABLED
153 : // per-motor calibration access
154 0 : void per_motor_calibration_start(void) {
155 0 : _per_motor.calibration_start();
156 0 : }
157 0 : void per_motor_calibration_update(void) {
158 0 : _per_motor.calibration_update();
159 0 : }
160 0 : void per_motor_calibration_end(void) {
161 0 : _per_motor.calibration_end();
162 0 : }
163 : #endif
164 :
165 : #if COMPASS_CAL_ENABLED
166 : // compass calibrator interface
167 : void cal_update();
168 :
169 : // start_calibration_all will only return false if there are no
170 : // compasses to calibrate.
171 : bool start_calibration_all(bool retry=false, bool autosave=false, float delay_sec=0.0f, bool autoreboot = false);
172 :
173 : void cancel_calibration_all();
174 :
175 139081 : bool compass_cal_requires_reboot() const { return _cal_requires_reboot; }
176 : bool is_calibrating() const;
177 :
178 : #if HAL_MAVLINK_BINDINGS_ENABLED
179 : /*
180 : handle an incoming MAG_CAL command
181 : */
182 : MAV_RESULT handle_mag_cal_command(const mavlink_command_int_t &packet);
183 :
184 : bool send_mag_cal_progress(const class GCS_MAVLINK& link);
185 : bool send_mag_cal_report(const class GCS_MAVLINK& link);
186 : #endif // HAL_MAVLINK_BINDINGS_ENABLED
187 : #endif // COMPASS_CAL_ENABLED
188 :
189 : // indicate which bit in LOG_BITMASK indicates we should log compass readings
190 2094 : void set_log_bit(uint32_t log_bit) { _log_bit = log_bit; }
191 :
192 : void Write_Compass(void);
193 : void Write_Compass_instance(uint64_t time_us, uint8_t mag_instance);
194 :
195 : // check if the compasses are pointing in the same direction
196 : bool consistent() const;
197 :
198 : /// Return the health of a compass
199 : bool healthy(uint8_t i) const;
200 4282113 : bool healthy(void) const { return healthy(_first_usable); }
201 : uint8_t get_healthy_mask() const;
202 :
203 : /// Returns the current offset values
204 : ///
205 : /// @returns The current compass offsets in milligauss.
206 : ///
207 128224121 : const Vector3f &get_offsets(uint8_t i) const { return _get_state(Priority(i)).offset; }
208 133156 : const Vector3f &get_offsets(void) const { return get_offsets(_first_usable); }
209 :
210 : #if AP_COMPASS_DIAGONALS_ENABLED
211 9 : const Vector3f &get_diagonals(uint8_t i) const { return _get_state(Priority(i)).diagonals; }
212 : const Vector3f &get_diagonals(void) const { return get_diagonals(_first_usable); }
213 :
214 9 : const Vector3f &get_offdiagonals(uint8_t i) const { return _get_state(Priority(i)).offdiagonals; }
215 : const Vector3f &get_offdiagonals(void) const { return get_offdiagonals(_first_usable); }
216 : #endif // AP_COMPASS_DIAGONALS_ENABLED
217 :
218 : // learn offsets accessor
219 41199290 : bool learn_offsets_enabled() const { return _learn == LearnType::INFLIGHT; }
220 :
221 : #if AP_COMPASS_LEARN_COPY_FROM_EKF_ENABLED
222 : // if COMPASS_LEARN==COPY_FROM_EKF, save the offsets the EKF has
223 : // learned into the COMPASS_OFS parameters. Called from
224 : // AP_Arming::disarm(); note that this *must* happen before the
225 : // vehicle calls hal.util->set_soft_armed(false).
226 : void save_ekf_learned_offsets();
227 : #endif // AP_COMPASS_LEARN_COPY_FROM_EKF_ENABLED
228 :
229 : /// return true if the compass should be used for yaw calculations
230 : bool use_for_yaw(uint8_t i) const;
231 : bool use_for_yaw(void) const;
232 :
233 : /// Sets the local magnetic field declination.
234 : ///
235 : /// @param radians Local field declination.
236 : /// @param save_to_eeprom true to save to eeprom (false saves only to memory)
237 : ///
238 : void set_declination(float radians, bool save_to_eeprom = true);
239 : float get_declination() const;
240 :
241 41156285 : bool auto_declination_enabled() const { return _auto_declination != 0; }
242 :
243 : // set overall board orientation
244 54325 : void set_board_orientation(enum Rotation orientation) {
245 54325 : _board_orientation = orientation;
246 54325 : }
247 :
248 : // get overall board orientation
249 46666723 : enum Rotation get_board_orientation(void) const {
250 46666723 : return _board_orientation;
251 : }
252 :
253 : #if AP_COMPASS_LEARN_COPY_FROM_EKF_ENABLED
254 : // true if the field published for this instance reaches us in the
255 : // body frame - that is, AP_Compass_Backend::rotate_field() applies
256 : // no rotation to it. An offset computed in the body frame is only
257 : // meaningful for such an instance; see AP_AHRS_SIM::get_mag_offsets().
258 : bool instance_is_unrotated(uint8_t i) const;
259 :
260 : // device id of the compass at this priority index. Used to find
261 : // the simulated sensor a priority index corresponds to; see
262 : // AP_AHRS_SIM::get_mag_offsets(). Zero if there is none.
263 : uint32_t get_dev_id(uint8_t i) const;
264 : #endif
265 :
266 : /// Set the motor compensation type
267 : ///
268 : /// @param comp_type 0 = disabled, 1 = enabled use throttle, 2 = enabled use current
269 : ///
270 : void motor_compensation_type(const uint8_t comp_type);
271 :
272 : /// get the motor compensation value.
273 : uint8_t get_motor_compensation_type() const {
274 : return _motor_comp_type;
275 : }
276 :
277 : /// Set the motor compensation factor x/y/z values.
278 : ///
279 : /// @param i instance of compass
280 : /// @param offsets Offsets multiplied by the throttle value and added to the raw mag_ values.
281 : ///
282 : void set_motor_compensation(uint8_t i, const Vector3f &motor_comp_factor);
283 :
284 : /// get motor compensation factors as a vector
285 : const Vector3f& get_motor_compensation(uint8_t i) const { return _get_state(Priority(i)).motor_compensation; }
286 : const Vector3f& get_motor_compensation(void) const { return get_motor_compensation(_first_usable); }
287 :
288 : /// Saves the current motor compensation x/y/z values.
289 : ///
290 : /// This should be invoked periodically to save the offset values calculated by the motor compensation auto learning
291 : ///
292 : void save_motor_compensation();
293 :
294 : /// Returns the current motor compensation offset values
295 : ///
296 : /// @returns The current compass offsets in milligauss.
297 : ///
298 4247415 : const Vector3f &get_motor_offsets(uint8_t i) const { return _get_state(Priority(i)).motor_offset; }
299 : const Vector3f &get_motor_offsets(void) const { return get_motor_offsets(_first_usable); }
300 :
301 : /// Set the throttle as a percentage from 0.0 to 1.0
302 : /// @param thr_pct throttle expressed as a percentage from 0 to 1.0
303 814014 : void set_throttle(float thr_pct) {
304 814014 : if (_motor_comp_type == AP_COMPASS_MOT_COMP_THROTTLE) {
305 0 : _thr = thr_pct;
306 : }
307 814014 : }
308 :
309 : #if COMPASS_MOT_ENABLED
310 : /// Set the battery voltage for per-motor compensation
311 759512 : void set_voltage(float voltage) {
312 759512 : _per_motor.set_voltage(voltage);
313 759512 : }
314 : #endif
315 :
316 : /// Returns True if the compasses have been configured (i.e. offsets saved)
317 : ///
318 : /// @returns True if compass has been configured
319 : ///
320 : bool configured(uint8_t i);
321 : bool configured(char *failure_msg, uint8_t failure_msg_len);
322 :
323 : // return last update time in microseconds
324 44009756 : uint32_t last_update_usec(void) const { return last_update_usec(_first_usable); }
325 171694790 : uint32_t last_update_usec(uint8_t i) const { return _get_state(Priority(i)).last_update_usec; }
326 :
327 : uint32_t last_update_ms(void) const { return last_update_ms(_first_usable); }
328 : uint32_t last_update_ms(uint8_t i) const { return _get_state(Priority(i)).last_update_ms; }
329 :
330 : static const struct AP_Param::GroupInfo var_info[];
331 :
332 : enum class LearnType {
333 : NONE = 0,
334 : // INTERNAL = 1,
335 : COPY_FROM_EKF = 2,
336 : INFLIGHT = 3,
337 : };
338 :
339 : // return the chosen learning type
340 1596 : LearnType get_learn_type(void) const {
341 1596 : const LearnType learn_type = (LearnType)_learn.get();
342 : #if !AP_COMPASS_LEARN_COPY_FROM_EKF_ENABLED
343 : if (learn_type == LearnType::COPY_FROM_EKF) {
344 : // there is no code compiled in to save the EKF's offsets,
345 : // so report the feature as off rather than letting callers
346 : // believe a learning type is selected which cannot run
347 : return LearnType::NONE;
348 : }
349 : #endif
350 1596 : return learn_type;
351 : }
352 :
353 : // set the learning type
354 1 : void set_learn_type(LearnType type, bool save) {
355 1 : if (save) {
356 1 : _learn.set_and_save(type);
357 : } else {
358 0 : _learn.set(type);
359 : }
360 1 : }
361 :
362 : // return maximum allowed compass offsets
363 133213 : uint16_t get_offsets_max(void) const {
364 133213 : return (uint16_t)_offset_max.get();
365 : }
366 :
367 46650409 : uint8_t get_filter_range() const { return uint8_t(_filter_range.get()); }
368 :
369 : #if AP_COMPASS_CALIBRATION_FIXED_YAW_ENABLED
370 : /*
371 : fast compass calibration given vehicle position and yaw
372 : */
373 : bool mag_cal_fixed_yaw(float yaw_deg, uint8_t compass_mask,
374 : float lat_deg, float lon_deg,
375 : bool force_use=false);
376 : #endif
377 :
378 : #if AP_COMPASS_MSP_ENABLED
379 : void handle_msp(const MSP::msp_compass_data_message_t &pkt);
380 : #endif
381 :
382 : #if AP_COMPASS_EXTERNALAHRS_ENABLED
383 : void handle_external(const AP_ExternalAHRS::mag_data_message_t &pkt);
384 : #endif
385 :
386 : // force save of current calibration as valid
387 : void force_save_calibration(void);
388 :
389 : // get the first compass marked for use by COMPASSx_USE
390 41156288 : uint8_t get_first_usable(void) const { return _first_usable; }
391 :
392 : private:
393 : static Compass *_singleton;
394 :
395 : // Use Priority and StateIndex typesafe index types
396 : // to distinguish between two different type of indexing
397 : // We use StateIndex for access by Backend
398 : // and Priority for access by Frontend
399 : DECLARE_TYPESAFE_INDEX(Priority, uint8_t);
400 : DECLARE_TYPESAFE_INDEX(StateIndex, uint8_t);
401 :
402 : /// Register a new compas driver, allocating an instance number
403 : ///
404 : /// @param dev_id Dev ID of compass to register against
405 : ///
406 : /// @return instance number saved against the dev id or first available empty instance number
407 : bool register_compass(int32_t dev_id, uint8_t& instance) WARN_IF_UNUSED;
408 :
409 : // load backend drivers
410 : __INITFUNC__ void _probe_external_i2c_compasses(void);
411 : __INITFUNC__ void _detect_backends(void);
412 : __INITFUNC__ void probe_i2c_spi_compasses(void);
413 : #if AP_COMPASS_DRONECAN_ENABLED
414 : void probe_dronecan_compasses(void);
415 : #endif
416 :
417 : #if COMPASS_CAL_ENABLED
418 : // compass cal
419 : void _update_calibration_trampoline();
420 : bool _accept_calibration(uint8_t i);
421 : bool _accept_calibration_mask(uint8_t mask);
422 : void _cancel_calibration(uint8_t i);
423 : void _cancel_calibration_mask(uint8_t mask);
424 : uint8_t _get_cal_mask();
425 : bool _start_calibration(uint8_t i, bool retry=false, float delay_sec=0.0f);
426 : bool _start_calibration_mask(uint8_t mask, bool retry=false, bool autosave=false, float delay_sec=0.0f, bool autoreboot=false);
427 : #if HAL_MAVLINK_BINDINGS_ENABLED
428 : Priority next_cal_progress_idx[MAVLINK_COMM_NUM_BUFFERS];
429 : Priority next_cal_report_idx[MAVLINK_COMM_NUM_BUFFERS];
430 : #endif
431 : #endif // COMPASS_CAL_ENABLED
432 :
433 : // see if we already have probed a i2c sensor by bus number and address
434 : bool _i2c_sensor_is_registered(uint8_t bus_num, uint8_t address) const;
435 :
436 : #if AP_COMPASS_CALIBRATION_FIXED_YAW_ENABLED
437 : /*
438 : get mag field with the effects of offsets, diagonals and
439 : off-diagonals removed
440 : */
441 : bool get_uncorrected_field(uint8_t instance, Vector3f &field) const;
442 : #endif
443 :
444 : #if COMPASS_CAL_ENABLED
445 : //keep track of which calibrators have been saved
446 : RestrictIDTypeArray<bool, COMPASS_MAX_INSTANCES, Priority> _cal_saved;
447 : bool _cal_autosave;
448 :
449 : //autoreboot after compass calibration
450 : bool _compass_cal_autoreboot;
451 : bool _cal_requires_reboot;
452 : bool _cal_has_run;
453 : #endif // COMPASS_CAL_ENABLED
454 :
455 : // enum of drivers for COMPASS_DISBLMSK
456 : enum DriverType {
457 : #if AP_COMPASS_HMC5843_ENABLED
458 : DRIVER_HMC5843 =0,
459 : #endif
460 : #if AP_COMPASS_LSM303D_ENABLED
461 : DRIVER_LSM303D =1,
462 : #endif
463 : #if AP_COMPASS_AK8963_ENABLED
464 : DRIVER_AK8963 =2,
465 : #endif
466 : #if AP_COMPASS_BMM150_ENABLED
467 : DRIVER_BMM150 =3,
468 : #endif
469 : #if AP_COMPASS_LSM9DS1_ENABLED
470 : DRIVER_LSM9DS1 =4,
471 : #endif
472 : #if AP_COMPASS_LIS3MDL_ENABLED
473 : DRIVER_LIS3MDL =5,
474 : #endif
475 : #if AP_COMPASS_AK09916_ENABLED
476 : DRIVER_AK09916 =6,
477 : #endif
478 : #if AP_COMPASS_IST8310_ENABLED
479 : DRIVER_IST8310 =7,
480 : #endif
481 : #if AP_COMPASS_ICM20948_ENABLED
482 : DRIVER_ICM20948 =8,
483 : #endif
484 : #if AP_COMPASS_MMC3416_ENABLED
485 : DRIVER_MMC3416 =9,
486 : #endif
487 : #if AP_COMPASS_DRONECAN_ENABLED
488 : DRIVER_UAVCAN =11,
489 : #endif
490 : #if AP_COMPASS_QMC5883L_ENABLED
491 : DRIVER_QMC5883L =12,
492 : #endif
493 : #if AP_COMPASS_SITL_ENABLED
494 : DRIVER_SITL =13,
495 : #endif
496 : #if AP_COMPASS_MAG3110_ENABLED
497 : DRIVER_MAG3110 =14,
498 : #endif
499 : #if AP_COMPASS_IST8308_ENABLED
500 : DRIVER_IST8308 =15,
501 : #endif
502 : #if AP_COMPASS_RM3100_ENABLED
503 : DRIVER_RM3100 =16,
504 : #endif
505 : #if AP_COMPASS_MSP_ENABLED
506 : DRIVER_MSP =17,
507 : #endif
508 : #if AP_COMPASS_EXTERNALAHRS_ENABLED
509 : DRIVER_EXTERNALAHRS =18,
510 : #endif
511 : #if AP_COMPASS_MMC5XX3_ENABLED
512 : DRIVER_MMC5XX3 =19,
513 : #endif
514 : #if AP_COMPASS_QMC5883P_ENABLED
515 : DRIVER_QMC5883P =20,
516 : #endif
517 : #if AP_COMPASS_BMM350_ENABLED
518 : DRIVER_BMM350 =21,
519 : #endif
520 : #if AP_COMPASS_IIS2MDC_ENABLED
521 : DRIVER_IIS2MDC =22,
522 : #endif
523 : // DRIVER_LIS2MDL =23, // DO NOT re-use this ID; same sensor as IIS2MDC
524 : #if AP_COMPASS_AF9838_ENABLED
525 : DRIVER_AF9838 =24,
526 : #endif
527 : };
528 :
529 : bool _driver_enabled(enum DriverType driver_type);
530 : void add_backend(DriverType driver_type, AP_Compass_Backend *backend);
531 :
532 : // helper probe functions
533 : void probe_ak09916_via_icm20948(uint8_t i2c_bus, uint8_t ak09916_addr, uint8_t icm20948_addr, bool external, Rotation rotation);
534 : void probe_ak09916_via_icm20948(uint8_t ins_instance, Rotation rotation);
535 : void probe_ak8963_via_mpu9250(uint8_t imu_instance, Rotation rotation);
536 :
537 : using probe_i2c_dev_probefn_t = AP_Compass_Backend* (*)(AP_HAL::OwnPtr<AP_HAL::Device>, bool, Rotation);
538 : void probe_i2c_dev(DriverType driver_type, probe_i2c_dev_probefn_t probefn, uint8_t i2c_bus, uint8_t i2c_addr, bool external, Rotation rotation);
539 :
540 : using probe_spi_dev_probefn_t = AP_Compass_Backend* (*)(AP_HAL::OwnPtr<AP_HAL::Device>, bool, Rotation);
541 : void probe_spi_dev(DriverType driver_type, probe_spi_dev_probefn_t probefn, const char *name, bool external, Rotation rotation);
542 : // short-lived method which expects a probe function that doesn't
543 : // offer the ability to specify an external rotation
544 : using probe_spi_dev_noexternal_probefn_t = AP_Compass_Backend* (*)(AP_HAL::OwnPtr<AP_HAL::Device>, Rotation);
545 : void probe_spi_dev(DriverType driver_type, probe_spi_dev_noexternal_probefn_t probefn, const char *name, Rotation rotation);
546 :
547 : // backend objects
548 : AP_Compass_Backend *_backends[COMPASS_MAX_BACKEND];
549 : uint8_t _backend_count;
550 :
551 : // whether to enable the compass drivers at all
552 : AP_Int8 _enabled;
553 :
554 : // number of registered compasses.
555 : uint8_t _compass_count;
556 :
557 : // number of unregistered compasses.
558 : uint8_t _unreg_compass_count;
559 :
560 : // settable parameters
561 : AP_Enum<LearnType> _learn;
562 :
563 : // board orientation from AHRS
564 : enum Rotation _board_orientation = ROTATION_NONE;
565 :
566 : // declination in radians
567 : AP_Float _declination;
568 :
569 : // enable automatic declination code
570 : AP_Int8 _auto_declination;
571 :
572 : // stores which bit is used to indicate we should log compass readings
573 : uint32_t _log_bit = -1;
574 :
575 : // motor compensation type
576 : // 0 = disabled, 1 = enabled for throttle, 2 = enabled for current
577 : AP_Int8 _motor_comp_type;
578 :
579 : // automatic compass orientation on calibration
580 : AP_Int8 _rotate_auto;
581 :
582 : // throttle expressed as a percentage from 0 ~ 1.0, used for motor compensation
583 : float _thr;
584 :
585 : struct mag_state {
586 : AP_Int8 external;
587 : bool healthy;
588 : bool registered;
589 : Compass::Priority priority;
590 : AP_Int8 orientation;
591 : AP_Vector3f offset;
592 : #if AP_COMPASS_DIAGONALS_ENABLED
593 : AP_Vector3f diagonals;
594 : AP_Vector3f offdiagonals;
595 : #endif
596 : AP_Float scale_factor;
597 :
598 : // device id detected at init.
599 : // saved to eeprom when offsets are saved allowing ram &
600 : // eeprom values to be compared as consistency check
601 : AP_Int32 dev_id;
602 : // Initialised when compass is detected
603 : int32_t detected_dev_id;
604 : // Initialised at boot from saved devid
605 : int32_t expected_dev_id;
606 :
607 : // factors multiplied by throttle and added to compass outputs
608 : AP_Vector3f motor_compensation;
609 :
610 : // latest compensation added to compass
611 : Vector3f motor_offset;
612 :
613 : // corrected magnetic field strength
614 : Vector3f field;
615 :
616 : // when we last got data
617 : uint32_t last_update_ms;
618 : uint32_t last_update_usec;
619 :
620 : // board specific orientation
621 : enum Rotation rotation;
622 :
623 : // accumulated samples, protected by _sem, used by AP_Compass_Backend
624 : Vector3f accum;
625 : uint32_t accum_count;
626 : // We only copy persistent params
627 : void copy_from(const mag_state& state);
628 : };
629 :
630 : //Create an Array of mag_state to be accessible by StateIndex only
631 : RestrictIDTypeArray<mag_state, COMPASS_MAX_INSTANCES+1, StateIndex> _state;
632 :
633 : //Convert Priority to StateIndex
634 : StateIndex _get_state_id(Priority priority) const;
635 : //Get State Struct by Priority
636 783526280 : const struct mag_state& _get_state(Priority priority) const { return _state[_get_state_id(priority)]; }
637 : //Convert StateIndex to Priority
638 46650409 : Priority _get_priority(StateIndex state_id) { return _state[state_id].priority; }
639 : //Method to detect compass beyond initialisation stage
640 : void _detect_runtime(void);
641 : // This method reorganises devid list to match
642 : // priority list, only call before detection at boot
643 : #if COMPASS_MAX_INSTANCES > 1
644 : void _reorder_compass_params();
645 : #endif
646 : // Update Priority List for Mags, by default, we just
647 : // load them as they come up the first time
648 : Priority _update_priority_list(int32_t dev_id);
649 :
650 : // method to check if the mag with the devid
651 : // is a replacement mag
652 : bool is_replacement_mag(uint32_t dev_id);
653 :
654 : //remove the devid from unreg compass list
655 : void remove_unreg_dev_id(uint32_t devid);
656 :
657 : void _reset_compass_id();
658 : //Create Arrays to be accessible by Priority only
659 : RestrictIDTypeArray<AP_Int8, COMPASS_MAX_INSTANCES, Priority> _use_for_yaw;
660 : #if COMPASS_MAX_INSTANCES > 1
661 : RestrictIDTypeArray<AP_Int32, COMPASS_MAX_INSTANCES, Priority> _priority_did_stored_list;
662 : RestrictIDTypeArray<int32_t, COMPASS_MAX_INSTANCES, Priority> _priority_did_list;
663 : #endif
664 :
665 : AP_Int16 _offset_max;
666 :
667 : // bitmask of options
668 : enum class Option : uint16_t {
669 : CAL_REQUIRE_GPS = (1U<<0),
670 : ALLOW_DRONECAN_AUTO_REPLACEMENT = (1U<<1),
671 : };
672 2150 : bool option_set(Option opt) const { return (_options.get() & uint16_t(opt)) != 0; }
673 : AP_Int16 _options;
674 :
675 : #if COMPASS_CAL_ENABLED
676 : RestrictIDTypeArray<CompassCalibrator*, COMPASS_MAX_INSTANCES, Priority> _calibrator;
677 : #endif
678 :
679 : #if COMPASS_MOT_ENABLED
680 : // per-motor compass compensation
681 : Compass_PerMotor _per_motor{*this};
682 : #endif
683 :
684 : AP_Float _calibration_threshold;
685 :
686 : // mask of driver types to not load. Bit positions match DEVTYPE_ in backend
687 : AP_Int32 _driver_type_mask;
688 :
689 : #if COMPASS_MAX_UNREG_DEV
690 : // Put extra dev ids detected
691 : AP_Int32 extra_dev_id[COMPASS_MAX_UNREG_DEV];
692 : uint32_t _previously_unreg_mag[COMPASS_MAX_UNREG_DEV];
693 : #endif
694 :
695 : AP_Int8 _filter_range;
696 :
697 : CompassLearn *learn;
698 : bool learn_allocated;
699 :
700 : /// Sets the initial location used to get declination
701 : ///
702 : /// @param latitude GPS Latitude.
703 : /// @param longitude GPS Longitude.
704 : ///
705 : void try_set_initial_location();
706 : bool _initial_location_set;
707 :
708 : bool _cal_thread_started;
709 :
710 : #if AP_COMPASS_MSP_ENABLED
711 : uint8_t msp_instance_mask;
712 : #endif
713 : bool init_done;
714 :
715 : bool suppress_devid_save;
716 :
717 : uint8_t _first_usable; // first compass usable based on COMPASSx_USE param
718 : };
719 :
720 : namespace AP {
721 : Compass &compass();
722 : };
|