Browse Source

AP_InertialSensor: changes after review with Tridge.

sanity checking added to accelerometer calibration routine.
user feedback is sent using gcs_send_text_fmt instead of Serial.printf.
moved ins parameters to new eeprom number to avoid conflicts with older parameters.
other small changes including renaming of functions and parameters.
mission-4.1.18
rmackay9 12 years ago
parent
commit
d9b4407e64
  1. 3
      ArduCopter/Parameters.h
  2. 2
      ArduCopter/setup.pde
  3. 3
      ArduPlane/Parameters.h
  4. 2
      ArduPlane/setup.pde
  5. 126
      libraries/AP_InertialSensor/AP_InertialSensor.cpp
  6. 20
      libraries/AP_InertialSensor/AP_InertialSensor.h
  7. 2
      libraries/AP_InertialSensor/AP_InertialSensor_MPU6000.cpp
  8. 4
      libraries/AP_InertialSensor/AP_InertialSensor_MPU6000.h
  9. 2
      libraries/AP_InertialSensor/AP_InertialSensor_Oilpan.cpp
  10. 4
      libraries/AP_InertialSensor/AP_InertialSensor_Oilpan.h
  11. 2
      libraries/AP_InertialSensor/AP_InertialSensor_Stub.cpp
  12. 5
      libraries/AP_InertialSensor/AP_InertialSensor_Stub.h

3
ArduCopter/Parameters.h

@ -52,7 +52,8 @@ public:
// //
k_param_format_version = 0, k_param_format_version = 0,
k_param_software_type, k_param_software_type,
k_param_ins, k_param_ins_old, // *** Deprecated, remove with next eeprom number change
k_param_ins, // libraries/AP_InertialSensor variables
// simulation // simulation
k_param_sitl = 10, k_param_sitl = 10,

2
ArduCopter/setup.pde

@ -258,7 +258,7 @@ static int8_t
setup_accel_scale(uint8_t argc, const Menu::arg *argv) setup_accel_scale(uint8_t argc, const Menu::arg *argv)
{ {
ins.init(AP_InertialSensor::COLD_START, delay, flash_leds, &timer_scheduler); ins.init(AP_InertialSensor::COLD_START, delay, flash_leds, &timer_scheduler);
ins.calibrate_accel(delay, flash_leds); ins.calibrate_accel(delay, flash_leds, gcs_send_text_fmt);
report_ins(); report_ins();
return(0); return(0);
} }

3
ArduPlane/Parameters.h

@ -68,7 +68,7 @@ public:
k_param_reset_switch_chan, k_param_reset_switch_chan,
k_param_manual_level, k_param_manual_level,
k_param_land_pitch_cd, k_param_land_pitch_cd,
k_param_ins, k_param_ins_old, // *** Deprecated, remove with next eeprom number change
k_param_stick_mixing, k_param_stick_mixing,
k_param_reset_mission_chan, k_param_reset_mission_chan,
k_param_land_flare_alt, k_param_land_flare_alt,
@ -77,6 +77,7 @@ public:
k_param_rudder_steer, k_param_rudder_steer,
k_param_throttle_nudge, k_param_throttle_nudge,
k_param_alt_offset, k_param_alt_offset,
k_param_ins, // libraries/AP_InertialSensor variables
// 110: Telemetry control // 110: Telemetry control
// //

2
ArduPlane/setup.pde

@ -303,7 +303,7 @@ static int8_t
setup_accel_scale(uint8_t argc, const Menu::arg *argv) setup_accel_scale(uint8_t argc, const Menu::arg *argv)
{ {
ins.init(AP_InertialSensor::COLD_START, delay, flash_leds, &timer_scheduler); ins.init(AP_InertialSensor::COLD_START, delay, flash_leds, &timer_scheduler);
ins.calibrate_accel(delay, flash_leds); ins.calibrate_accel(delay, flash_leds, gcs_send_text_fmt);
report_ins(); report_ins();
return(0); return(0);
} }

126
libraries/AP_InertialSensor/AP_InertialSensor.cpp

@ -4,11 +4,7 @@
#include "AP_InertialSensor.h" #include "AP_InertialSensor.h"
#include <SPI.h> #include <SPI.h>
#if defined(ARDUINO) && ARDUINO >= 100 #include <AP_Common.h>
#include "Arduino.h"
#else
#include <wiring.h>
#endif
#define FLASH_LEDS(on) do { if (flash_leds_cb != NULL) flash_leds_cb(on); } while (0) #define FLASH_LEDS(on) do { if (flash_leds_cb != NULL) flash_leds_cb(on); } while (0)
@ -17,9 +13,9 @@
// Class level parameters // Class level parameters
const AP_Param::GroupInfo AP_InertialSensor::var_info[] PROGMEM = { const AP_Param::GroupInfo AP_InertialSensor::var_info[] PROGMEM = {
AP_GROUPINFO("PRODUCT_ID", 0, AP_InertialSensor, _product_id, 0), AP_GROUPINFO("PRODUCT_ID", 0, AP_InertialSensor, _product_id, 0),
AP_GROUPINFO("ACCSCA", 1, AP_InertialSensor, _accel_scale, 0), AP_GROUPINFO("ACCSCAL", 1, AP_InertialSensor, _accel_scale, 0),
AP_GROUPINFO("ACCOFF", 2, AP_InertialSensor, _accel_offset, 0), AP_GROUPINFO("ACCOFFS", 2, AP_InertialSensor, _accel_offset, 0),
AP_GROUPINFO("GYROFF", 3, AP_InertialSensor, _gyro_offset, 0), AP_GROUPINFO("GYROFFS", 3, AP_InertialSensor, _gyro_offset, 0),
AP_GROUPEND AP_GROUPEND
}; };
@ -33,7 +29,7 @@ AP_InertialSensor::init( Start_style style,
void (*flash_leds_cb)(bool on), void (*flash_leds_cb)(bool on),
AP_PeriodicProcess * scheduler ) AP_PeriodicProcess * scheduler )
{ {
_product_id = _init(scheduler); _product_id = _init_sensor(scheduler);
// check scaling // check scaling
Vector3f accel_scale = _accel_scale.get(); Vector3f accel_scale = _accel_scale.get();
@ -42,33 +38,19 @@ AP_InertialSensor::init( Start_style style,
_accel_scale.set(accel_scale); _accel_scale.set(accel_scale);
} }
// if we are warm-starting, load the calibration data from EEPROM and go if (WARM_START != style) {
if (WARM_START == style) { // do cold-start calibration for gyro only
load_parameters();
} else {
// do cold-start calibration for both accel and gyro
_init_gyro(delay_cb, flash_leds_cb); _init_gyro(delay_cb, flash_leds_cb);
// save calibration
save_parameters();
} }
} }
// save parameters to eeprom // save parameters to eeprom
void AP_InertialSensor::load_parameters() void AP_InertialSensor::_save_parameters()
{
_product_id.load();
_accel_scale.load();
_accel_offset.load();
}
// save parameters to eeprom
void AP_InertialSensor::save_parameters()
{ {
_product_id.save(); _product_id.save();
_accel_scale.save(); _accel_scale.save();
_accel_offset.save(); _accel_offset.save();
_gyro_offset.save();
} }
void void
@ -77,7 +59,7 @@ AP_InertialSensor::init_gyro(void (*delay_cb)(unsigned long t), void (*flash_led
_init_gyro(delay_cb, flash_leds_cb); _init_gyro(delay_cb, flash_leds_cb);
// save calibration // save calibration
save_parameters(); _save_parameters();
} }
void void
@ -170,13 +152,13 @@ AP_InertialSensor::init_accel(void (*delay_cb)(unsigned long t), void (*flash_le
_init_accel(delay_cb, flash_leds_cb); _init_accel(delay_cb, flash_leds_cb);
// save calibration // save calibration
save_parameters(); _save_parameters();
} }
void void
AP_InertialSensor::_init_accel(void (*delay_cb)(unsigned long t), void (*flash_leds_cb)(bool on)) AP_InertialSensor::_init_accel(void (*delay_cb)(unsigned long t), void (*flash_leds_cb)(bool on))
{ {
int16_t flashcount = 0; int8_t flashcount = 0;
Vector3f ins_accel; Vector3f ins_accel;
Vector3f prev; Vector3f prev;
Vector3f accel_offset; Vector3f accel_offset;
@ -184,7 +166,7 @@ AP_InertialSensor::_init_accel(void (*delay_cb)(unsigned long t), void (*flash_l
float max_offset; float max_offset;
// cold start // cold start
delay_cb(500); delay_cb(100);
Serial.printf_P(PSTR("Init Accel")); Serial.printf_P(PSTR("Init Accel"));
@ -209,7 +191,7 @@ AP_InertialSensor::_init_accel(void (*delay_cb)(unsigned long t), void (*flash_l
accel_offset = ins_accel; accel_offset = ins_accel;
// We take some readings... // We take some readings...
for(int16_t i = 0; i < 50; i++) { for(int8_t i = 0; i < 50; i++) {
delay_cb(20); delay_cb(20);
update(); update();
@ -250,49 +232,56 @@ AP_InertialSensor::_init_accel(void (*delay_cb)(unsigned long t), void (*flash_l
} }
// perform accelerometer calibration including providing user instructions and feedback // perform accelerometer calibration including providing user instructions and feedback
void AP_InertialSensor::calibrate_accel(void (*callback)(unsigned long t), void (*flash_leds_cb)(bool on)) void AP_InertialSensor::calibrate_accel(void (*delay_cb)(unsigned long t), void (*flash_leds_cb)(bool on), void (*send_msg)(const prog_char_t *, ...))
{ {
Vector3f samples[6]; Vector3f samples[6];
Vector3f new_offsets; Vector3f new_offsets;
Vector3f new_scaling; Vector3f new_scaling;
Vector3f orig_offset;
Vector3f orig_scale;
// backup original offsets and scaling
orig_offset = _accel_offset.get();
orig_scale = _accel_scale.get();
// clear accelerometer offsets and scaling // clear accelerometer offsets and scaling
_accel_offset = Vector3f(0,0,0); _accel_offset = Vector3f(0,0,0);
_accel_scale = Vector3f(1,1,1); _accel_scale = Vector3f(1,1,1);
// capture data from 6 positions // capture data from 6 positions
for(int16_t i=0; i<6; i++ ) { for (int8_t i=0; i<6; i++) {
const prog_char_t *msg;
// display message to user // display message to user
Serial.print_P(PSTR("Place APM ")); switch ( i ) {
switch( i ) {
case 0: case 0:
Serial.print_P(PSTR("level")); msg = PSTR("level");
break; break;
case 1: case 1:
Serial.print_P(PSTR("on it's left side")); msg = PSTR("on it's left side");
break; break;
case 2: case 2:
Serial.print_P(PSTR("on it's right side")); msg = PSTR("on it's right side");
break; break;
case 3: case 3:
Serial.print_P(PSTR("nose down")); msg = PSTR("nose down");
break; break;
case 4: case 4:
Serial.print_P(PSTR("nose up")); msg = PSTR("nose up");
break; break;
case 5: case 5:
Serial.print_P(PSTR("on it's back")); msg = PSTR("on it's back");
break;
default:
// should never happen
break; break;
} }
Serial.print_P(PSTR(" and press any key.\n")); if (send_msg == NULL) {
Serial.printf_P(PSTR("USER: Place APM %S and press any key.\n"), msg);
}else{
send_msg(PSTR("USER: Place APM %S and press any key.\n"), msg);
}
// wait for user input // wait for user input
while( !Serial.available() ) { while( !Serial.available() ) {
delay(20); delay_cb(20);
} }
// clear unput buffer // clear unput buffer
while( Serial.available() ) { while( Serial.available() ) {
@ -304,7 +293,7 @@ void AP_InertialSensor::calibrate_accel(void (*callback)(unsigned long t), void
// wait until we have 32 samples // wait until we have 32 samples
while( num_samples_available() < 32 * SAMPLE_UNIT ) { while( num_samples_available() < 32 * SAMPLE_UNIT ) {
delay(1); delay_cb(1);
} }
// read samples from ins // read samples from ins
@ -312,20 +301,33 @@ void AP_InertialSensor::calibrate_accel(void (*callback)(unsigned long t), void
// capture sample // capture sample
samples[i] = get_accel(); samples[i] = get_accel();
// display sample
Serial.printf_P(PSTR("Acc X:%4.2f\tY:%4.2f\tZ:%4.2f\n"),samples[i].x,samples[i].y,samples[i].z);
} }
// run the calibration routine // run the calibration routine
if( _calibrate_accel(samples, new_offsets, new_scaling) ) { if( _calibrate_accel(samples, new_offsets, new_scaling) ) {
if (send_msg == NULL) {
Serial.printf_P(PSTR("Calibration successful\n"));
}else{
send_msg(PSTR("Calibration successful\n"));
}
// set and save calibration
_accel_offset.set(new_offsets); _accel_offset.set(new_offsets);
_accel_scale.set(new_scaling); _accel_scale.set(new_scaling);
// save calibration _save_parameters();
save_parameters();
}else{ }else{
Serial.printf_P(PSTR("Accel calibration failed")); if (send_msg == NULL) {
Serial.printf_P(PSTR("Calibration failed\n"));
}else{
send_msg(PSTR("Calibration failed\n"));
}
// restore original scaling and offsets
_accel_offset.set(orig_offset);
_accel_scale.set(orig_scale);
} }
delay_cb(100);
} }
// _calibrate_model - perform low level accel calibration // _calibrate_model - perform low level accel calibration
@ -344,6 +346,7 @@ bool AP_InertialSensor::_calibrate_accel( Vector3f accel_sample[6], Vector3f& ac
float delta[6]; float delta[6];
float ds[6]; float ds[6];
float JS[6][6]; float JS[6][6];
bool success = true;
// reset // reset
beta[0] = beta[1] = beta[2] = 0; beta[0] = beta[1] = beta[2] = 0;
@ -384,8 +387,17 @@ bool AP_InertialSensor::_calibrate_accel( Vector3f accel_sample[6], Vector3f& ac
accel_offsets.y = beta[1] * accel_scale.y; accel_offsets.y = beta[1] * accel_scale.y;
accel_offsets.z = beta[2] * accel_scale.z; accel_offsets.z = beta[2] * accel_scale.z;
// always return success // sanity check scale
return true; if( accel_scale.is_nan() || fabs(accel_scale.x-1.0) > 0.1 || fabs(accel_scale.y-1.0) > 1.1 || fabs(accel_scale.z-1.0) > 1.1 ) {
success = false;
}
// sanity check offsets (2.0 is roughly 2/10th of a G, 5.0 is roughly half a G)
if( accel_offsets.is_nan() || fabs(accel_offsets.x) > 2.0 || fabs(accel_offsets.y) > 2.0 || fabs(accel_offsets.z) > 5.0 ) {
success = false;
}
// return success or failure
return success;
} }
void AP_InertialSensor::_calibrate_update_matrices(float dS[6], float JS[6][6], float beta[6], float data[3]) void AP_InertialSensor::_calibrate_update_matrices(float dS[6], float JS[6][6], float beta[6], float data[3])
@ -460,4 +472,4 @@ void AP_InertialSensor::_calibrate_find_delta(float dS[6], float JS[6][6], float
for( i=0; i<6; i++ ) { for( i=0; i<6; i++ ) {
delta[i] = dS[i]; delta[i] = dS[i];
} }
} }

20
libraries/AP_InertialSensor/AP_InertialSensor.h

@ -47,10 +47,12 @@ public:
/// @note This should not be called unless ::init has previously /// @note This should not be called unless ::init has previously
/// been called, as ::init may perform other work. /// been called, as ::init may perform other work.
/// ///
virtual void init_accel(void (*callback)(unsigned long t), void (*flash_leds_cb)(bool on)); virtual void init_accel(void (*delay_cb)(unsigned long t), void (*flash_leds_cb)(bool on));
// perform accelerometer calibration including providing user instructions and feedback // perform accelerometer calibration including providing user instructions and feedback
virtual void calibrate_accel(void (*callback)(unsigned long t), void (*flash_leds_cb)(bool on)); virtual void calibrate_accel(void (*delay_cb)(unsigned long t),
void (*flash_leds_cb)(bool on) = NULL,
void (*send_msg)(const prog_char_t *, ...) = NULL);
/// Perform cold-start initialisation for just the gyros. /// Perform cold-start initialisation for just the gyros.
/// ///
@ -82,10 +84,6 @@ public:
// get accel scale // get accel scale
Vector3f get_accel_scale() { return _accel_scale; } Vector3f get_accel_scale() { return _accel_scale; }
// sensor specific init to be overwritten by descendant classes
// To-Do: should be combined with init above?
virtual uint16_t _init( AP_PeriodicProcess * scheduler ) = 0;
/* Update the sensor data, so that getters are nonblocking. /* Update the sensor data, so that getters are nonblocking.
* Returns a bool of whether data was updated or not. * Returns a bool of whether data was updated or not.
*/ */
@ -133,6 +131,9 @@ public:
protected: protected:
// sensor specific init to be overwritten by descendant classes
virtual uint16_t _init_sensor( AP_PeriodicProcess * scheduler ) = 0;
// no-save implementations of accel and gyro initialisation routines // no-save implementations of accel and gyro initialisation routines
virtual void _init_accel(void (*delay_cb)(unsigned long t), virtual void _init_accel(void (*delay_cb)(unsigned long t),
void (*flash_leds_cb)(bool on) = NULL); void (*flash_leds_cb)(bool on) = NULL);
@ -140,16 +141,13 @@ protected:
void (*flash_leds_cb)(bool on) = NULL); void (*flash_leds_cb)(bool on) = NULL);
// _calibrate_accel - perform low level accel calibration // _calibrate_accel - perform low level accel calibration
virtual bool _calibrate_accel(Vector3f accel_sample[6], Vector3f& accel_offsets, Vector3f& accel_scale ); virtual bool _calibrate_accel(Vector3f accel_sample[6], Vector3f& accel_offsets, Vector3f& accel_scale);
virtual void _calibrate_update_matrices(float dS[6], float JS[6][6], float beta[6], float data[3]); virtual void _calibrate_update_matrices(float dS[6], float JS[6][6], float beta[6], float data[3]);
virtual void _calibrate_reset_matrices(float dS[6], float JS[6][6]); virtual void _calibrate_reset_matrices(float dS[6], float JS[6][6]);
virtual void _calibrate_find_delta(float dS[6], float JS[6][6], float delta[6]); virtual void _calibrate_find_delta(float dS[6], float JS[6][6], float delta[6]);
// load parameters from eeprom
void load_parameters();
// save parameters to eeprom // save parameters to eeprom
void save_parameters(); void _save_parameters();
// Most recent accelerometer reading obtained by ::update // Most recent accelerometer reading obtained by ::update
Vector3f _accel; Vector3f _accel;

2
libraries/AP_InertialSensor/AP_InertialSensor_MPU6000.cpp

@ -210,7 +210,7 @@ AP_InertialSensor_MPU6000::AP_InertialSensor_MPU6000()
_dmp_initialised = false; _dmp_initialised = false;
} }
uint16_t AP_InertialSensor_MPU6000::_init( AP_PeriodicProcess * scheduler ) uint16_t AP_InertialSensor_MPU6000::_init_sensor( AP_PeriodicProcess * scheduler )
{ {
if (_initialised) return _mpu6000_product_id; if (_initialised) return _mpu6000_product_id;
_initialised = true; _initialised = true;

4
libraries/AP_InertialSensor/AP_InertialSensor_MPU6000.h

@ -22,7 +22,6 @@ public:
AP_InertialSensor_MPU6000(); AP_InertialSensor_MPU6000();
uint16_t _init( AP_PeriodicProcess * scheduler );
static void dmp_init(); // Initialise MPU6000's DMP static void dmp_init(); // Initialise MPU6000's DMP
static void dmp_reset(); // Reset the DMP (required for changes in gains or offsets to take effect) static void dmp_reset(); // Reset the DMP (required for changes in gains or offsets to take effect)
@ -52,6 +51,9 @@ public:
// get_delta_time returns the time period in seconds overwhich the sensor data was collected // get_delta_time returns the time period in seconds overwhich the sensor data was collected
uint32_t get_delta_time_micros(); uint32_t get_delta_time_micros();
protected:
uint16_t _init_sensor( AP_PeriodicProcess * scheduler );
private: private:
static void read(uint32_t); static void read(uint32_t);

2
libraries/AP_InertialSensor/AP_InertialSensor_Oilpan.cpp

@ -41,7 +41,7 @@ AP_InertialSensor_Oilpan::AP_InertialSensor_Oilpan( AP_ADC * adc ) :
{ {
} }
uint16_t AP_InertialSensor_Oilpan::_init( AP_PeriodicProcess * scheduler) uint16_t AP_InertialSensor_Oilpan::_init_sensor( AP_PeriodicProcess * scheduler)
{ {
_adc->Init(scheduler); _adc->Init(scheduler);

4
libraries/AP_InertialSensor/AP_InertialSensor_Oilpan.h

@ -17,7 +17,6 @@ public:
AP_InertialSensor_Oilpan( AP_ADC * adc ); AP_InertialSensor_Oilpan( AP_ADC * adc );
/* Concrete implementation of AP_InertialSensor functions: */ /* Concrete implementation of AP_InertialSensor functions: */
uint16_t _init(AP_PeriodicProcess * scheduler);
bool update(); bool update();
bool new_data_available(); bool new_data_available();
float gx(); float gx();
@ -34,6 +33,9 @@ public:
// get number of samples read from the sensors // get number of samples read from the sensors
uint16_t num_samples_available(); uint16_t num_samples_available();
protected:
uint16_t _init_sensor(AP_PeriodicProcess * scheduler);
private: private:
AP_ADC * _adc; AP_ADC * _adc;

2
libraries/AP_InertialSensor/AP_InertialSensor_Stub.cpp

@ -2,7 +2,7 @@
#include "AP_InertialSensor_Stub.h" #include "AP_InertialSensor_Stub.h"
uint16_t AP_InertialSensor_Stub::_init( AP_PeriodicProcess * scheduler ) { uint16_t AP_InertialSensor_Stub::_init_sensor( AP_PeriodicProcess * scheduler ) {
return AP_PRODUCT_ID_NONE; return AP_PRODUCT_ID_NONE;
} }

5
libraries/AP_InertialSensor/AP_InertialSensor_Stub.h

@ -16,8 +16,6 @@ public:
AP_InertialSensor_Stub() { AP_InertialSensor_Stub() {
} }
uint16_t _init( AP_PeriodicProcess * scheduler );
/* Concrete implementation of AP_InertialSensor functions: */ /* Concrete implementation of AP_InertialSensor functions: */
bool update(); bool update();
bool new_data_available(); bool new_data_available();
@ -32,6 +30,9 @@ public:
uint32_t get_last_sample_time_micros(); uint32_t get_last_sample_time_micros();
float get_gyro_drift_rate(); float get_gyro_drift_rate();
uint16_t num_samples_available(); uint16_t num_samples_available();
protected:
uint16_t _init_sensor( AP_PeriodicProcess * scheduler );
}; };
#endif // __AP_INERTIAL_SENSOR_STUB_H__ #endif // __AP_INERTIAL_SENSOR_STUB_H__

Loading…
Cancel
Save