45 #include <px4_platform_common/defines.h> 46 #include <px4_platform_common/posix.h> 47 #include <px4_platform_common/time.h> 91 unsigned int calibration_counter_total[
max_mags];
119 (void)sprintf(str,
"EKF2_MAGBIAS_X");
122 if (result != PX4_OK) {
123 PX4_ERR(
"unable to reset %s", str);
126 (void)sprintf(str,
"EKF2_MAGBIAS_Y");
129 if (result != PX4_OK) {
130 PX4_ERR(
"unable to reset %s", str);
133 (void)sprintf(str,
"EKF2_MAGBIAS_Z");
136 if (result != PX4_OK) {
137 PX4_ERR(
"unable to reset %s", str);
140 for (
size_t i = 0; i <
max_mags; i++) {
146 for (
unsigned cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
149 (void)sprintf(str,
"CAL_MAG%u_ID", cur_mag);
152 if (result != PX4_OK) {
158 (void)sprintf(str,
"CAL_MAG%u_XOFF", cur_mag);
161 if (result != PX4_OK) {
162 PX4_ERR(
"unable to reset %s", str);
165 (void)sprintf(str,
"CAL_MAG%u_YOFF", cur_mag);
168 if (result != PX4_OK) {
169 PX4_ERR(
"unable to reset %s", str);
172 (void)sprintf(str,
"CAL_MAG%u_ZOFF", cur_mag);
175 if (result != PX4_OK) {
176 PX4_ERR(
"unable to reset %s", str);
179 (void)sprintf(str,
"CAL_MAG%u_XSCALE", cur_mag);
182 if (result != PX4_OK) {
183 PX4_ERR(
"unable to reset %s", str);
186 (void)sprintf(str,
"CAL_MAG%u_YSCALE", cur_mag);
189 if (result != PX4_OK) {
190 PX4_ERR(
"unable to reset %s", str);
193 (void)sprintf(str,
"CAL_MAG%u_ZSCALE", cur_mag);
196 if (result != PX4_OK) {
197 PX4_ERR(
"unable to reset %s", str);
220 if (result != PX4_OK) {
225 if (result == PX4_OK) {
228 if (result != PX4_OK) {
240 if (result == PX4_OK) {
270 static bool reject_sample(
float sx,
float sy,
float sz,
float x[],
float y[],
float z[],
unsigned count,
275 for (
size_t i = 0; i < count; i++) {
276 float dx = sx - x[i];
277 float dy = sy - y[i];
278 float dz = sz - z[i];
279 float dist = sqrtf(dx * dx + dy * dy + dz * dz);
281 if (dist < min_sample_dist) {
298 float diag_x,
float diag_y,
float diag_z,
299 float offdiag_x,
float offdiag_y,
float offdiag_z,
302 float must_be_finite[] = {offset_x, offset_y, offset_z,
304 diag_x, diag_y, diag_z,
305 offdiag_x, offdiag_y, offdiag_z
308 float should_be_not_huge[] = {offset_x, offset_y, offset_z};
309 float should_be_positive[] = {sphere_radius, diag_x, diag_y, diag_z};
312 const int num_finite =
sizeof(must_be_finite) /
sizeof(*must_be_finite);
314 for (
unsigned i = 0; i < num_finite; ++i) {
315 if (!PX4_ISFINITE(must_be_finite[i])) {
317 "ERROR: Retry calibration (sphere NaN, #%zu)", cur_mag);
323 const int num_not_huge =
sizeof(should_be_not_huge) /
sizeof(*should_be_not_huge);
325 for (
unsigned i = 0; i < num_not_huge; ++i) {
328 (
internal[cur_mag]) ?
"autopilot, internal" :
"GPS unit, external");
334 const int num_positive =
sizeof(should_be_positive) /
sizeof(*should_be_positive);
336 for (
unsigned i = 0; i < num_positive; ++i) {
337 if (should_be_positive[i] <= 0.0
f) {
339 (
internal[cur_mag]) ?
"autopilot, internal" :
"GPS unit, external");
351 unsigned int calibration_counter_side;
372 float gyro_x_integral = 0.0f;
373 float gyro_y_integral = 0.0f;
374 float gyro_z_integral = 0.0f;
376 const float gyro_int_thresh_rad = 0.5f;
380 while (fabsf(gyro_x_integral) < gyro_int_thresh_rad &&
381 fabsf(gyro_y_integral) < gyro_int_thresh_rad &&
382 fabsf(gyro_z_integral) < gyro_int_thresh_rad) {
394 warnx(
"int: %8.4f, %8.4f, %8.4f", (
double)gyro_x_integral, (
double)gyro_y_integral, (
double)gyro_z_integral);
400 px4_pollfd_struct_t fds[1];
401 fds[0].fd = sub_gyro;
402 fds[0].events = POLLIN;
405 int poll_ret =
px4_poll(fds, fd_count, 1000);
415 float delta_t = (gyro.timestamp - last_gyro) / 1e6f;
416 gyro_x_integral += gyro.x * delta_t;
417 gyro_y_integral += gyro.y * delta_t;
418 gyro_z_integral += gyro.z * delta_t;
421 last_gyro = gyro.timestamp;
428 unsigned poll_errcount = 0;
430 calibration_counter_side = 0;
433 calibration_counter_side < worker_data->calibration_points_perside) {
444 for (
size_t cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
446 fds[fd_count].fd = worker_data->
sub_mag[cur_mag];
447 fds[fd_count].events = POLLIN;
452 int poll_ret =
px4_poll(fds, fd_count, 1000);
457 bool rejected =
false;
459 for (
size_t cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
463 if (worker_data->
sub_mag[cur_mag] >= 0) {
470 worker_data->
x[cur_mag], worker_data->
y[cur_mag], worker_data->
z[cur_mag],
484 for (
size_t cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
489 calibration_counter_side++;
492 (unsigned)((100 /
calibration_sides) * ((float)calibration_counter_side / (
float)
498 "[cal] %s side calibration: progress <%u>",
543 int32_t cal_mask = (1 << 6) - 1;
550 if ((cal_mask & (1 << i)) > 0) {
560 "[cal] %s side done, rotate to a different side",
566 for (
size_t cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
568 worker_data.
sub_mag[cur_mag] = -1;
571 worker_data.
x[cur_mag] =
nullptr;
572 worker_data.
y[cur_mag] =
nullptr;
573 worker_data.
z[cur_mag] =
nullptr;
585 if (orb_mag_count > max_mags) {
589 for (
size_t cur_mag = 0; cur_mag < orb_mag_count && cur_mag <
max_mags; cur_mag++) {
590 worker_data.
x[cur_mag] =
static_cast<float *
>(malloc(
sizeof(
float) * calibration_points_maxcount));
591 worker_data.
y[cur_mag] =
static_cast<float *
>(malloc(
sizeof(
float) * calibration_points_maxcount));
592 worker_data.
z[cur_mag] =
static_cast<float *
>(malloc(
sizeof(
float) * calibration_points_maxcount));
594 if (worker_data.
x[cur_mag] ==
nullptr || worker_data.
y[cur_mag] ==
nullptr || worker_data.
z[cur_mag] ==
nullptr) {
605 for (
unsigned cur_mag = 0; cur_mag < orb_mag_count && cur_mag <
max_mags; cur_mag++) {
608 bool found_cur_mag =
false;
610 for (
unsigned i = 0; i < orb_mag_count && !found_cur_mag; i++) {
622 if (report.device_id == (uint32_t)
device_ids[cur_mag]) {
624 found_cur_mag =
true;
634 found_cur_mag =
true;
639 if (!found_cur_mag) {
665 for (
unsigned cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
691 for (
unsigned cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
692 if (worker_data.
sub_mag[cur_mag] >= 0) {
710 for (
unsigned cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
711 sphere_x[cur_mag] = 0.0f;
712 sphere_y[cur_mag] = 0.0f;
713 sphere_z[cur_mag] = 0.0f;
714 sphere_radius[cur_mag] = 0.2f;
715 diag_x[cur_mag] = 1.0f;
716 diag_y[cur_mag] = 1.0f;
717 diag_z[cur_mag] = 1.0f;
718 offdiag_x[cur_mag] = 0.0f;
719 offdiag_y[cur_mag] = 0.0f;
720 offdiag_z[cur_mag] = 0.0f;
725 for (
unsigned cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
732 &sphere_x[cur_mag], &sphere_y[cur_mag], &sphere_z[cur_mag],
733 &sphere_radius[cur_mag],
734 &diag_x[cur_mag], &diag_y[cur_mag], &diag_z[cur_mag],
735 &offdiag_x[cur_mag], &offdiag_y[cur_mag], &offdiag_z[cur_mag]);
738 sphere_radius[cur_mag],
739 diag_x[cur_mag], diag_y[cur_mag], diag_z[cur_mag],
740 offdiag_x[cur_mag], offdiag_y[cur_mag], offdiag_z[cur_mag],
741 mavlink_log_pub, cur_mag);
796 for (
size_t cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
797 free(worker_data.
x[cur_mag]);
798 free(worker_data.
y[cur_mag]);
799 free(worker_data.
z[cur_mag]);
804 for (
unsigned cur_mag = 0; cur_mag <
max_mags; cur_mag++) {
833 mscale.
x_offset = sphere_x[cur_mag];
834 mscale.
y_offset = sphere_y[cur_mag];
835 mscale.
z_offset = sphere_z[cur_mag];
836 mscale.
x_scale = diag_x[cur_mag];
837 mscale.
y_scale = diag_y[cur_mag];
838 mscale.
z_scale = diag_z[cur_mag];
864 (void)sprintf(str,
"CAL_MAG%u_ID", cur_mag);
866 (void)sprintf(str,
"CAL_MAG%u_XOFF", cur_mag);
868 (void)sprintf(str,
"CAL_MAG%u_YOFF", cur_mag);
870 (void)sprintf(str,
"CAL_MAG%u_ZOFF", cur_mag);
875 (void)sprintf(str,
"CAL_MAG%u_XSCALE", cur_mag);
877 (void)sprintf(str,
"CAL_MAG%u_YSCALE", cur_mag);
879 (void)sprintf(str,
"CAL_MAG%u_ZSCALE", cur_mag);
#define CAL_ERROR_SENSOR_MSG
#define MAGIOCGSCALE
copy the mag scaling constants to the structure pointed to by (arg)
static orb_advert_t * mavlink_log_pub
static constexpr unsigned int calibraton_duration_seconds
The total duration the routine is allowed to take.
#define MAGIOCGEXTERNAL
determine if mag is external or onboard
Accelerometer driver interface.
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
unsigned int calibration_interval_perside_seconds
Gyroscope driver interface.
static unsigned progress_percentage(mag_worker_data_t *worker_data)
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
__EXPORT int param_set_no_notification(param_t param, const void *val)
Set the value of a parameter, but do not notify the system about the change.
Common calibration messages.
detect_orientation_return
Barometer calibration routine.
int orb_priority(int handle, int32_t *priority)
int orb_set_interval(int handle, unsigned interval)
__EXPORT int param_set(param_t param, const void *val)
Set the value of a parameter.
calibrate_return calibrate_from_orientation(orb_advert_t *mavlink_log_pub, int cancel_sub, bool side_data_collected[detect_orientation_side_count], calibration_from_orientation_worker_t calibration_worker, void *worker_data, bool lenient_still_position)
Perform calibration sequence which require a rest orientation detection prior to calibration.
mag scaling factors; Vout = (Vin * Vscale) + Voffset
#define CAL_ERROR_RESET_CAL_MSG
int ellipsoid_fit_least_squares(const float x[], const float y[], const float z[], unsigned int size, int max_iterations, float delta, float *offset_x, float *offset_y, float *offset_z, float *sphere_radius, float *diag_x, float *diag_y, float *diag_z, float *offdiag_x, float *offdiag_y, float *offdiag_z)
High-resolution timer with callouts and timekeeping.
static unsigned _last_mag_progress
unsigned int calibration_counter_total[max_mags]
Global flash based parameter store.
static calibrate_return mag_calibration_worker(detect_orientation_return orientation, int cancel_sub, void *data)
orb_advert_t * mavlink_log_pub
void calibrate_cancel_unsubscribe(int cmd_sub)
Called to cancel the subscription to the cancel command.
int orb_subscribe(const struct orb_metadata *meta)
uint64_t calibration_interval_perside_useconds
bool side_data_collected[detect_orientation_side_count]
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
const char * detect_orientation_str(enum detect_orientation_return orientation)
Returns the human readable string representation of the orientation.
Commander helper functions definitions.
#define MAGIOCSSCALE
set the mag scaling constants to the structure pointed to by (arg)
#define MAG_BASE_DEVICE_PATH
#define MAGIOCCALIBRATE
perform self-calibration, update scale factors to canonical units
unsigned int calibration_points_perside
static unsigned int calibration_sides
The total number of sides.
static constexpr unsigned max_mags
calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub)
#define CAL_ERROR_APPLY_CAL_MSG
int orb_unsubscribe(int handle)
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
#define CAL_QGC_STARTED_MSG
#define CAL_ERROR_SET_PARAMS_MSG
int do_mag_calibration(orb_advert_t *mavlink_log_pub)
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
int32_t device_id_primary
static constexpr float MAG_MAX_OFFSET_LEN
The maximum measurement range is ~1.9 Ga, the earth field is ~0.6 Ga, so an offset larger than ~1...
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Driver for the PX4 audio alarm port, /dev/tone_alarm.
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
int orb_group_count(const struct orb_metadata *meta)
Get the number of published instances of a topic group.
__EXPORT param_t param_find(const char *name)
Look up a parameter by name.
__EXPORT void param_notify_changes(void)
Notify the system about parameter changes.
bool calibrate_cancel_check(orb_advert_t *mavlink_log_pub, int cancel_sub)
Used to periodically check for a cancel command.
int orb_subscribe_multi(const struct orb_metadata *meta, unsigned instance)
static calibrate_return check_calibration_result(float offset_x, float offset_y, float offset_z, float sphere_radius, float diag_x, float diag_y, float diag_z, float offdiag_x, float offdiag_y, float offdiag_z, orb_advert_t *mavlink_log_pub, size_t cur_mag)
Data passed to calibration worker routine.
#define calibration_log_critical(_pub, _text,...)
static constexpr unsigned int calibration_total_points
The total points per magnetometer.
static bool reject_sample(float sx, float sy, float sz, float x[], float y[], float z[], unsigned count, unsigned max_count)
#define calibration_log_emergency(_pub, _text,...)
static const unsigned detect_orientation_side_count
static const char * sensor_name
#define CAL_QGC_PROGRESS_MSG
#define CAL_QGC_FAILED_MSG
int calibrate_cancel_subscribe()
Called at the beginning of calibration in order to subscribe to the cancel command.
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
#define calibration_log_info(_pub, _text,...)
int32_t device_ids[max_mags]
static constexpr float mag_sphere_radius