From d5cab1140a1c77cc724d9b77b07c6f32294ac30b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 5 Jun 2017 13:03:28 +1000 Subject: [PATCH] AP_InertialSensor: added simple_accel_cal() this is useful for mass market vehicles where a full 3D accel cal is too complex. --- .../AP_InertialSensor/AP_InertialSensor.cpp | 162 ++++++++++++++++++ .../AP_InertialSensor/AP_InertialSensor.h | 4 + 2 files changed, 166 insertions(+) diff --git a/libraries/AP_InertialSensor/AP_InertialSensor.cpp b/libraries/AP_InertialSensor/AP_InertialSensor.cpp index 460460bc5d..eae434d421 100644 --- a/libraries/AP_InertialSensor/AP_InertialSensor.cpp +++ b/libraries/AP_InertialSensor/AP_InertialSensor.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "AP_InertialSensor.h" #include "AP_InertialSensor_BMI160.h" @@ -1746,3 +1747,164 @@ bool AP_InertialSensor::get_primary_accel_cal_sample_avg(uint8_t sample_num, Vec ret.rotate(_board_orientation); return true; } + +/* + perform a simple 1D accel calibration, returning mavlink result code + */ +uint8_t AP_InertialSensor::simple_accel_cal(AP_AHRS &ahrs) +{ + uint8_t num_accels = MIN(get_accel_count(), INS_MAX_INSTANCES); + Vector3f last_average[INS_MAX_INSTANCES]; + Vector3f new_accel_offset[INS_MAX_INSTANCES]; + Vector3f saved_offsets[INS_MAX_INSTANCES]; + Vector3f saved_scaling[INS_MAX_INSTANCES]; + bool converged[INS_MAX_INSTANCES]; + const float accel_convergence_limit = 0.05; + Vector3f rotated_gravity(0, 0, -GRAVITY_MSS); + + // exit immediately if calibration is already in progress + if (_calibrating) { + return MAV_RESULT_TEMPORARILY_REJECTED; + } + + // record we are calibrating + _calibrating = true; + + // flash leds to tell user to keep the IMU still + AP_Notify::flags.initialising = true; + + hal.console->printf("Simple accel cal"); + + /* + we do the accel calibration with no board rotation. This avoids + having to rotate readings during the calibration + */ + enum Rotation saved_orientation = _board_orientation; + _board_orientation = ROTATION_NONE; + + // get the rotated gravity vector which will need to be applied to the offsets + rotated_gravity.rotate_inverse(saved_orientation); + + // save existing accel offsets + for (uint8_t k=0; kdelay(5); + update(); + } + + // the strategy is to average 50 points over 0.5 seconds, then do it + // again and see if the 2nd average is within a small margin of + // the first + + uint8_t num_converged = 0; + + // we try to get a good calibration estimate for up to 10 seconds + // if the accels are stable, we should get it in 1 second + for (int16_t j = 0; j <= 10*4 && num_converged < num_accels; j++) { + Vector3f accel_sum[INS_MAX_INSTANCES], accel_avg[INS_MAX_INSTANCES], accel_diff[INS_MAX_INSTANCES]; + float diff_norm[INS_MAX_INSTANCES]; + uint8_t i; + + memset(diff_norm, 0, sizeof(diff_norm)); + + hal.console->printf("*"); + + for (uint8_t k=0; kdelay(5); + } + + for (uint8_t k=0; k 0 && diff_norm[k] < accel_convergence_limit) { + last_average[k] = (accel_avg[k] * 0.5f) + (last_average[k] * 0.5f); + if (!converged[k] || last_average[k].length() < new_accel_offset[k].length()) { + new_accel_offset[k] = last_average[k]; + } + if (!converged[k]) { + converged[k] = true; + num_converged++; + } + } else { + last_average[k] = accel_avg[k]; + } + } + } + + uint8_t result = MAV_RESULT_ACCEPTED; + + // see if we've passed + for (uint8_t k=0; kprintf("\nPASSED\n"); + for (uint8_t k=0; kprintf("\nFAILED\n"); + // restore old values + for (uint8_t k=0; k