@@ -78,7 +78,7 @@ int device_prio_max = 0;
78
78
int32_t device_id_primary = 0 ;
79
79
static unsigned _last_mag_progress = 0 ;
80
80
81
- calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub);
81
+ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_mask );
82
82
83
83
// / Data passed to calibration worker routine
84
84
typedef struct {
@@ -143,6 +143,15 @@ int do_mag_calibration(orb_advert_t *mavlink_log_pub)
143
143
144
144
_last_mag_progress = 0 ;
145
145
146
+ // Collect: As defined by configuration
147
+ // start with a full mask, all six bits set
148
+ int32_t cal_mask = (1 << 6 ) - 1 ;
149
+ param_get (param_find (" CAL_MAG_SIDES" ), &cal_mask);
150
+
151
+ // keep and update the existing calibration when we are not doing a full 6-axis calibration
152
+ const bool append_to_existing_calibration = cal_mask < ((1 << 6 ) - 1 );
153
+ (void )append_to_existing_calibration;
154
+
146
155
for (unsigned cur_mag = 0 ; cur_mag < max_mags; cur_mag++) {
147
156
#ifdef __PX4_NUTTX
148
157
// Reset mag id to mag not available
@@ -214,11 +223,13 @@ int do_mag_calibration(orb_advert_t *mavlink_log_pub)
214
223
device_ids[cur_mag] = px4_ioctl (fd, DEVIOCGDEVICEID, 0 );
215
224
internal[cur_mag] = (px4_ioctl (fd, MAGIOCGEXTERNAL, 0 ) <= 0 );
216
225
217
- // Reset mag scale & offset
218
- result = px4_ioctl (fd, MAGIOCSSCALE, (long unsigned int )&mscale_null);
226
+ if (!append_to_existing_calibration) {
227
+ // Reset mag scale & offset
228
+ result = px4_ioctl (fd, MAGIOCSSCALE, (long unsigned int )&mscale_null);
219
229
220
- if (result != PX4_OK) {
221
- calibration_log_critical (mavlink_log_pub, CAL_ERROR_RESET_CAL_MSG, cur_mag);
230
+ if (result != PX4_OK) {
231
+ calibration_log_critical (mavlink_log_pub, CAL_ERROR_RESET_CAL_MSG, cur_mag);
232
+ }
222
233
}
223
234
224
235
@@ -228,7 +239,7 @@ int do_mag_calibration(orb_advert_t *mavlink_log_pub)
228
239
229
240
// Calibrate all mags at the same time
230
241
if (result == PX4_OK) {
231
- switch (mag_calibrate_all (mavlink_log_pub)) {
242
+ switch (mag_calibrate_all (mavlink_log_pub, cal_mask )) {
232
243
case calibrate_return_cancelled:
233
244
// Cancel message already displayed, we're done here
234
245
result = PX4_ERROR;
@@ -516,7 +527,7 @@ static calibrate_return mag_calibration_worker(detect_orientation_return orienta
516
527
return result;
517
528
}
518
529
519
- calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub)
530
+ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_mask )
520
531
{
521
532
calibrate_return result = calibrate_return_ok;
522
533
@@ -528,11 +539,6 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub)
528
539
worker_data.calibration_interval_perside_seconds = calibraton_duration_seconds / detect_orientation_side_count;
529
540
worker_data.calibration_interval_perside_useconds = worker_data.calibration_interval_perside_seconds * 1000 * 1000 ;
530
541
531
- // Collect: As defined by configuration
532
- // start with a full mask, all six bits set
533
- int32_t cal_mask = (1 << 6 ) - 1 ;
534
- param_get (param_find (" CAL_MAG_SIDES" ), &cal_mask);
535
-
536
542
calibration_sides = 0 ;
537
543
538
544
for (unsigned i = 0 ; i < (sizeof (worker_data.side_data_collected ) / sizeof (worker_data.side_data_collected [0 ])); i++) {
@@ -716,13 +722,16 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub)
716
722
if (device_ids[cur_mag] != 0 ) {
717
723
// Mag in this slot is available and we should have values for it to calibrate
718
724
725
+ // Estimate only the offsets if two-sided calibration is selected, as the problem is not constrained
726
+ // enough to reliably estimate both scales and offsets with 2 sides only (even if the existing calibration
727
+ // is already close)
728
+ bool sphere_fit_only = calibration_sides <= 2 ;
719
729
ellipsoid_fit_least_squares (worker_data.x [cur_mag], worker_data.y [cur_mag], worker_data.z [cur_mag],
720
- worker_data.calibration_counter_total [cur_mag],
721
- 100 , 0 .0f ,
730
+ worker_data.calibration_counter_total [cur_mag], 100 ,
722
731
&sphere_x[cur_mag], &sphere_y[cur_mag], &sphere_z[cur_mag],
723
732
&sphere_radius[cur_mag],
724
733
&diag_x[cur_mag], &diag_y[cur_mag], &diag_z[cur_mag],
725
- &offdiag_x[cur_mag], &offdiag_y[cur_mag], &offdiag_z[cur_mag]);
734
+ &offdiag_x[cur_mag], &offdiag_y[cur_mag], &offdiag_z[cur_mag], sphere_fit_only );
726
735
727
736
result = check_calibration_result (sphere_x[cur_mag], sphere_y[cur_mag], sphere_z[cur_mag],
728
737
sphere_radius[cur_mag],
@@ -793,15 +802,11 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub)
793
802
794
803
for (unsigned cur_mag = 0 ; cur_mag < max_mags; cur_mag++) {
795
804
if (device_ids[cur_mag] != 0 ) {
796
- struct mag_calibration_s mscale;
797
- mscale.x_scale = 1.0 ;
798
- mscale.y_scale = 1.0 ;
799
- mscale.z_scale = 1.0 ;
805
+ mag_calibration_s mscale;
800
806
801
807
#ifdef __PX4_NUTTX
802
808
int fd_mag = -1 ;
803
809
804
- // Set new scale
805
810
(void )sprintf (str, " %s%u" , MAG_BASE_DEVICE_PATH, cur_mag);
806
811
fd_mag = px4_open (str, 0 );
807
812
@@ -810,30 +815,40 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub)
810
815
result = calibrate_return_error;
811
816
}
812
817
818
+ #endif
819
+
813
820
if (result == calibrate_return_ok) {
821
+
822
+ #ifdef __PX4_NUTTX
823
+
824
+ // Read existing calibration
814
825
if (px4_ioctl (fd_mag, MAGIOCGSCALE, (long unsigned int )&mscale) != PX4_OK) {
815
- calibration_log_critical (mavlink_log_pub, " ERROR: failed to get current calibration #%u " , cur_mag );
826
+ calibration_log_critical (mavlink_log_pub, CAL_ERROR_READ_CAL_MSG );
816
827
result = calibrate_return_error;
817
828
}
818
- }
819
829
820
- #endif
830
+ // Update calibration
831
+ // The formula for applying the calibration is:
832
+ // mag_value = (mag_readout - (offset_existing + offset_new/scale_existing)) * scale_existing * scale_new
833
+ mscale.x_offset = mscale.x_offset + sphere_x[cur_mag] / mscale.x_scale ;
834
+ mscale.y_offset = mscale.y_offset + sphere_y[cur_mag] / mscale.y_scale ;
835
+ mscale.z_offset = mscale.z_offset + sphere_z[cur_mag] / mscale.z_scale ;
836
+ mscale.x_scale = mscale.x_scale * diag_x[cur_mag];
837
+ mscale.y_scale = mscale.y_scale * diag_y[cur_mag];
838
+ mscale.z_scale = mscale.z_scale * diag_z[cur_mag];
821
839
822
- if (result == calibrate_return_ok) {
840
+ if (px4_ioctl (fd_mag, MAGIOCSSCALE, (long unsigned int )&mscale) != PX4_OK) {
841
+ calibration_log_critical (mavlink_log_pub, CAL_ERROR_APPLY_CAL_MSG);
842
+ result = calibrate_return_error;
843
+ }
844
+
845
+ #else
823
846
mscale.x_offset = sphere_x[cur_mag];
824
847
mscale.y_offset = sphere_y[cur_mag];
825
848
mscale.z_offset = sphere_z[cur_mag];
826
849
mscale.x_scale = diag_x[cur_mag];
827
850
mscale.y_scale = diag_y[cur_mag];
828
851
mscale.z_scale = diag_z[cur_mag];
829
-
830
- #ifdef __PX4_NUTTX
831
-
832
- if (px4_ioctl (fd_mag, MAGIOCSSCALE, (long unsigned int )&mscale) != PX4_OK) {
833
- calibration_log_critical (mavlink_log_pub, CAL_ERROR_APPLY_CAL_MSG);
834
- result = calibrate_return_error;
835
- }
836
-
837
852
#endif
838
853
}
839
854
0 commit comments