|
|
@ -312,11 +312,11 @@ static calibrate_return mag_calibration_worker(detect_orientation_return orienta |
|
|
|
Vector3f new_samples[MAX_MAGS] {}; |
|
|
|
Vector3f new_samples[MAX_MAGS] {}; |
|
|
|
|
|
|
|
|
|
|
|
for (uint8_t cur_mag = 0; cur_mag < MAX_MAGS; cur_mag++) { |
|
|
|
for (uint8_t cur_mag = 0; cur_mag < MAX_MAGS; cur_mag++) { |
|
|
|
sensor_mag_s mag; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (worker_data->calibration[cur_mag].device_id() != 0) { |
|
|
|
if (worker_data->calibration[cur_mag].device_id() != 0) { |
|
|
|
if (mag_sub[cur_mag].update(&mag)) { |
|
|
|
bool updated = false; |
|
|
|
|
|
|
|
sensor_mag_s mag; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (mag_sub[cur_mag].update(&mag)) { |
|
|
|
if (worker_data->append_to_existing_calibration) { |
|
|
|
if (worker_data->append_to_existing_calibration) { |
|
|
|
// keep and update the existing calibration when we are not doing a full 6-axis calibration
|
|
|
|
// keep and update the existing calibration when we are not doing a full 6-axis calibration
|
|
|
|
const Matrix3f &scale = worker_data->calibration[cur_mag].scale(); |
|
|
|
const Matrix3f &scale = worker_data->calibration[cur_mag].scale(); |
|
|
@ -335,14 +335,15 @@ static calibrate_return mag_calibration_worker(detect_orientation_return orienta |
|
|
|
worker_data->calibration_counter_total[cur_mag], |
|
|
|
worker_data->calibration_counter_total[cur_mag], |
|
|
|
worker_data->calibration_sides * worker_data->calibration_points_perside); |
|
|
|
worker_data->calibration_sides * worker_data->calibration_points_perside); |
|
|
|
|
|
|
|
|
|
|
|
if (reject) { |
|
|
|
if (!reject) { |
|
|
|
rejected = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
new_samples[cur_mag] = Vector3f{mag.x, mag.y, mag.z}; |
|
|
|
new_samples[cur_mag] = Vector3f{mag.x, mag.y, mag.z}; |
|
|
|
|
|
|
|
updated = true; |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
// require an update for all valid mags
|
|
|
|
|
|
|
|
if (!updated) { |
|
|
|
rejected = true; |
|
|
|
rejected = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -522,6 +523,7 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_ma |
|
|
|
// enough to reliably estimate both scales and offsets with 2 sides only (even if the existing calibration
|
|
|
|
// enough to reliably estimate both scales and offsets with 2 sides only (even if the existing calibration
|
|
|
|
// is already close)
|
|
|
|
// is already close)
|
|
|
|
bool sphere_fit_only = worker_data.calibration_sides <= 2; |
|
|
|
bool sphere_fit_only = worker_data.calibration_sides <= 2; |
|
|
|
|
|
|
|
bool sphere_fit_success = false; |
|
|
|
{ |
|
|
|
{ |
|
|
|
float fitness = 1.0e30f; |
|
|
|
float fitness = 1.0e30f; |
|
|
|
float sphere_lambda = 1.0f; |
|
|
|
float sphere_lambda = 1.0f; |
|
|
@ -535,6 +537,16 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_ma |
|
|
|
&diag[cur_mag](0), &diag[cur_mag](1), &diag[cur_mag](2), |
|
|
|
&diag[cur_mag](0), &diag[cur_mag](1), &diag[cur_mag](2), |
|
|
|
&offdiag[cur_mag](0), &offdiag[cur_mag](1), &offdiag[cur_mag](2)); |
|
|
|
&offdiag[cur_mag](0), &offdiag[cur_mag](1), &offdiag[cur_mag](2)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ret == PX4_OK) { |
|
|
|
|
|
|
|
sphere_fit_success = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// stop here if fit has previously succeeded
|
|
|
|
|
|
|
|
if (sphere_fit_success) { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PX4_DEBUG("Mag: %d (%d/%d) sphere fit ret=%d, fitness: %.5f, lambda: %.5f, radius: %.3f, offset: [%.3f, %.3f %.3f]", |
|
|
|
PX4_DEBUG("Mag: %d (%d/%d) sphere fit ret=%d, fitness: %.5f, lambda: %.5f, radius: %.3f, offset: [%.3f, %.3f %.3f]", |
|
|
|
cur_mag, i, max_iterations, ret, (double)fitness, (double)sphere_lambda, (double)sphere_radius[cur_mag], |
|
|
|
cur_mag, i, max_iterations, ret, (double)fitness, (double)sphere_lambda, (double)sphere_radius[cur_mag], |
|
|
|
(double)sphere[cur_mag](0), (double)sphere[cur_mag](1), (double)sphere[cur_mag](2)); |
|
|
|
(double)sphere[cur_mag](0), (double)sphere[cur_mag](1), (double)sphere[cur_mag](2)); |
|
|
@ -543,6 +555,8 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_ma |
|
|
|
PX4_INFO("Mag: %d sphere fitness: %.5f radius: %.4f", cur_mag, (double)fitness, (double)sphere_radius[cur_mag]); |
|
|
|
PX4_INFO("Mag: %d sphere fitness: %.5f radius: %.4f", cur_mag, (double)fitness, (double)sphere_radius[cur_mag]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool ellipsoid_fit_success = false; |
|
|
|
|
|
|
|
|
|
|
|
if (!sphere_fit_only) { |
|
|
|
if (!sphere_fit_only) { |
|
|
|
float fitness = 1.0e30f; |
|
|
|
float fitness = 1.0e30f; |
|
|
|
float ellipsoid_lambda = 1.0f; |
|
|
|
float ellipsoid_lambda = 1.0f; |
|
|
@ -556,6 +570,16 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_ma |
|
|
|
&diag[cur_mag](0), &diag[cur_mag](1), &diag[cur_mag](2), |
|
|
|
&diag[cur_mag](0), &diag[cur_mag](1), &diag[cur_mag](2), |
|
|
|
&offdiag[cur_mag](0), &offdiag[cur_mag](1), &offdiag[cur_mag](2)); |
|
|
|
&offdiag[cur_mag](0), &offdiag[cur_mag](1), &offdiag[cur_mag](2)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ret == PX4_OK) { |
|
|
|
|
|
|
|
ellipsoid_fit_success = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// stop here if fit has previously succeeded
|
|
|
|
|
|
|
|
if (ellipsoid_fit_success) { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PX4_DEBUG("Mag: %d (%d/%d) ellipsoid fit ret=%d, fitness: %.5f, lambda: %.5f, radius: %.3f, offset: [%.3f, %.3f %.3f]", |
|
|
|
PX4_DEBUG("Mag: %d (%d/%d) ellipsoid fit ret=%d, fitness: %.5f, lambda: %.5f, radius: %.3f, offset: [%.3f, %.3f %.3f]", |
|
|
|
cur_mag, i, max_iterations, ret, (double)fitness, (double)ellipsoid_lambda, (double)sphere_radius[cur_mag], |
|
|
|
cur_mag, i, max_iterations, ret, (double)fitness, (double)ellipsoid_lambda, (double)sphere_radius[cur_mag], |
|
|
|
(double)sphere[cur_mag](0), (double)sphere[cur_mag](1), (double)sphere[cur_mag](2)); |
|
|
|
(double)sphere[cur_mag](0), (double)sphere[cur_mag](1), (double)sphere[cur_mag](2)); |
|
|
@ -564,6 +588,12 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_ma |
|
|
|
PX4_INFO("Mag: %d ellipsoid fitness: %.5f", cur_mag, (double)fitness); |
|
|
|
PX4_INFO("Mag: %d ellipsoid fitness: %.5f", cur_mag, (double)fitness); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!sphere_fit_success && !ellipsoid_fit_success) { |
|
|
|
|
|
|
|
calibration_log_emergency(mavlink_log_pub, "Retry calibration (unable to fit mag #%u)", cur_mag); |
|
|
|
|
|
|
|
result = calibrate_return_error; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
result = check_calibration_result(sphere[cur_mag](0), sphere[cur_mag](1), sphere[cur_mag](2), |
|
|
|
result = check_calibration_result(sphere[cur_mag](0), sphere[cur_mag](1), sphere[cur_mag](2), |
|
|
|
sphere_radius[cur_mag], |
|
|
|
sphere_radius[cur_mag], |
|
|
|
diag[cur_mag](0), diag[cur_mag](1), diag[cur_mag](2), |
|
|
|
diag[cur_mag](0), diag[cur_mag](1), diag[cur_mag](2), |
|
|
@ -577,54 +607,47 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_ma |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Print uncalibrated data points
|
|
|
|
|
|
|
|
if (result == calibrate_return_ok) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// DO NOT REMOVE! Critical validation data!
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
#if 0 |
|
|
|
printf("RAW DATA:\n--------------------\n"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// DO NOT REMOVE! Critical validation data!
|
|
|
|
|
|
|
|
if (result == calibrate_return_ok) { |
|
|
|
|
|
|
|
// Print uncalibrated data points
|
|
|
|
for (uint8_t cur_mag = 0; cur_mag < MAX_MAGS; cur_mag++) { |
|
|
|
for (uint8_t cur_mag = 0; cur_mag < MAX_MAGS; cur_mag++) { |
|
|
|
|
|
|
|
|
|
|
|
if (worker_data.calibration_counter_total[cur_mag] == 0) { |
|
|
|
if (worker_data.calibration_counter_total[cur_mag] == 0) { |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
printf("RAW: MAG %u with %u samples:\n", cur_mag, worker_data.calibration_counter_total[cur_mag]); |
|
|
|
printf("MAG %u with %u samples:\n", cur_mag, worker_data.calibration_counter_total[cur_mag]); |
|
|
|
|
|
|
|
printf("RAW -> CALIBRATED\n"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float scale_data[9] { |
|
|
|
|
|
|
|
diag[cur_mag](0), offdiag[cur_mag](0), offdiag[cur_mag](1), |
|
|
|
|
|
|
|
offdiag[cur_mag](0), diag[cur_mag](1), offdiag[cur_mag](2), |
|
|
|
|
|
|
|
offdiag[cur_mag](1), offdiag[cur_mag](2), diag[cur_mag](2) |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Matrix3f scale{scale_data}; |
|
|
|
|
|
|
|
const Vector3f &offset = sphere[cur_mag]; |
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < worker_data.calibration_counter_total[cur_mag]; i++) { |
|
|
|
for (size_t i = 0; i < worker_data.calibration_counter_total[cur_mag]; i++) { |
|
|
|
float x = worker_data.x[cur_mag][i]; |
|
|
|
float x = worker_data.x[cur_mag][i]; |
|
|
|
float y = worker_data.y[cur_mag][i]; |
|
|
|
float y = worker_data.y[cur_mag][i]; |
|
|
|
float z = worker_data.z[cur_mag][i]; |
|
|
|
float z = worker_data.z[cur_mag][i]; |
|
|
|
printf("%8.4f, %8.4f, %8.4f\n", (double)x, (double)y, (double)z); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf(">>>>>>>\n"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf("CALIBRATED DATA:\n--------------------\n"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (uint8_t cur_mag = 0; cur_mag < MAX_MAGS; cur_mag++) { |
|
|
|
// apply calibration
|
|
|
|
|
|
|
|
const Vector3f cal{scale *(Vector3f{x, y, z} - offset)}; |
|
|
|
|
|
|
|
|
|
|
|
if (worker_data.calibration_counter_total[cur_mag] == 0) { |
|
|
|
printf("[%.3f, %.3f, %.3f] -> [%.3f, %.3f, %.3f]\n", |
|
|
|
continue; |
|
|
|
(double)x, (double)y, (double)z, |
|
|
|
} |
|
|
|
(double)cal(0), (double)cal(1), (double)cal(2)); |
|
|
|
|
|
|
|
|
|
|
|
printf("Calibrated: MAG %u with %u samples:\n", cur_mag, worker_data.calibration_counter_total[cur_mag]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < worker_data.calibration_counter_total[cur_mag]; i++) { |
|
|
|
|
|
|
|
float x = worker_data.x[cur_mag][i] - sphere[cur_mag](0); |
|
|
|
|
|
|
|
float y = worker_data.y[cur_mag][i] - sphere[cur_mag](1); |
|
|
|
|
|
|
|
float z = worker_data.z[cur_mag][i] - sphere[cur_mag](2); |
|
|
|
|
|
|
|
printf("%8.4f, %8.4f, %8.4f\n", (double)x, (double)y, (double)z); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
printf("SPHERE RADIUS: %8.4f\n", (double)sphere_radius[cur_mag]); |
|
|
|
printf("SPHERE RADIUS: %8.4f\n", (double)sphere_radius[cur_mag]); |
|
|
|
printf(">>>>>>>\n"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#endif // DO NOT REMOVE! Critical validation data!
|
|
|
|
#endif // DO NOT REMOVE! Critical validation data!
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Attempt to automatically determine external mag rotations
|
|
|
|
// Attempt to automatically determine external mag rotations
|
|
|
|