Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
IMU.cpp
00001 /** 00002 * @author Eric Van den Bulck 00003 * 00004 * @section LICENSE 00005 * 00006 * Copyright (c) 2010 ARM Limited 00007 * 00008 * @section DESCRIPTION 00009 * 00010 * Pololu MinIMU-9 v2 sensor: 00011 * L3GD20 three-axis digital output gyroscope. 00012 * LSM303 three-axis digital accelerometer and magnetometer 00013 * 00014 * Information to build this library: 00015 * 1. The Arduino libraries for this sensor from the Pololu and Adafruit websites, available at gitbub. 00016 * https://github.com/adafruit/Adafruit_L3GD20 00017 * https://github.com/pololu/L3G/tree/master/L3G 00018 * 2. The Rasberry Pi code at https://github.com/idavidstory/goPiCopter/tree/master/io/sensors 00019 * https://github.com/idavidstory/goPiCopter/tree/master/io/sensors 00020 * 3. Information on how to write libraries: http://mbed.org/cookbook/Writing-a-Library 00021 * 4. Information on I2C control: http://mbed.org/users/mbed_official/code/mbed/ 00022 * 5. The Youtube videos from Brian Douglas (3 x 15') at http://www.youtube.com/playlist?list=PLUMWjy5jgHK30fkGrufluENJqZmLZkmqI 00023 * http://www.x-io.co.uk/open-source-imu-and-ahrs-algorithms/ 00024 * Reading an IMU Without Kalman: The Complementary Filter: http://www.pieter-jan.com/node/11 00025 * setup info on the minIMU-9 v2 on http://forum.pololu.com/viewtopic.php?f=3&t=4801&start=30 00026 */ 00027 00028 #include "mbed.h" 00029 #include "IMU.h" 00030 00031 IMU::IMU(PinName sda, PinName scl) : _i2c(sda, scl) { 00032 _i2c.frequency(400000); /* 400kHz, fast mode. */ 00033 } 00034 00035 char IMU::init(void) /* returns error upon a non-zero return */ 00036 { 00037 char ack, rx, tx[2]; 00038 double pi, a, A; 00039 00040 // 1. Initialize selected registers: 2c.read and i2c.write return 0 on success (ack) 00041 // -------------------------------- 00042 // 00043 // 1.a Enable L3DG20 gyrosensor and set operational mode: 00044 // CTRL_REG1: set to 0x1F = 0001-1111 --> enable sensor, DR= 95Hz, LPF-Cut-off-freq=25Hz. 00045 // CTRL_REG1: set to 0x5F = 0101-1111 --> enable sensor, DR=190Hz, LPF-Cut-off-freq=25Hz. 00046 // CTRL_REG4: left at default = 0x00 --> Full Scale = 250 degrees/second --> Sensitivity = 0.00875 dps/digit. 00047 address = L3GD20_ADDR; 00048 tx[0] = L3GD20_CTRL_REG1; // address contrl_register 1 00049 tx[1] = 0x1F; // 00-01-1-111 enable sensor and set operational mode. 00050 ack = _i2c.write(address, tx, 2); 00051 ack |= _i2c.write(address, tx, 1); 00052 ack |= _i2c.read(address+1, &rx, 1); if (rx != 0x1F) ack |= 1; 00053 // 00054 // 1.b Enable LSM303 accelerometer and set operational mode: 00055 // CTRL_REG1: set to 0x37 = 0011 0111 --> DR = 25Hz & enable sensor 00056 // CTRL_REG1: set to 0x47 = 0100 0111 --> DR = 50Hz & enable sensor 00057 // CTRL_REG1: set to 0x57 = 0101 0111 --> DR = 100Hz & enable sensor 00058 // CTRL_REG1: set to 0x77 = 0111 0111 --> DR = 200Hz & enable sensor 00059 // CTRL_REG4: set to 0x08 = 0000 1000 --> Full Scale = +/- 2G & high resolution --> Sensitivity = 0.001G/digit. 00060 address = LSM303_A_ADDR; 00061 tx[0] = LSM303_A_CTRL_REG1; 00062 tx[1] = 0x57; // --> 200 Hz Data rate speed - p.24/42 of datasheet 00063 ack |= _i2c.write(address, tx, 2); 00064 ack |= _i2c.write(address, tx, 1); 00065 ack |= _i2c.read(address+1, &rx, 1); if (rx != 0x57) ack |= 1; 00066 tx[0] = LSM303_A_CTRL_REG4; 00067 tx[1] = 0x08; // 0000 1000 enable high resolution mode + selects default 2G scale. p.26/42 00068 ack |= _i2c.write(address, tx ,2); 00069 ack |= _i2c.write(address, tx, 1); 00070 ack |= _i2c.read(address+1, &rx, 1); if (rx != 0x08) ack |= 1; 00071 // 00072 // 1.c enable LSM303 magnetometer and set operational mode: 00073 // CRA_REG is reset from 0x10 to 0x14 = 00010100 --> 30 Hz data output rate. 00074 // CRA_REG is reset from 0x10 to 0x18 = 00011000 --> 75 Hz data output rate. 00075 // CRA_REG is reset from 0x10 to 0x1C = 00011100 --> 220 Hz data output rate. 00076 // CRB_REG is kept at default = 00100000 = 0x20 --> range +/- 1.3 Gauss, Gain = 1100/980(Z) LSB/Gauss. 00077 // MR_REG is reset from 0x03 to 0x00 -> continuos conversion mode in stead of sleep mode. 00078 address = LSM303_M_ADDR; 00079 tx[0] = LSM303_M_CRA_REG; 00080 tx[1] = 0x18; // --> 75 Hz minimum output rate - p.36/42 of datasheet 00081 ack |= _i2c.write(address, tx, 2); 00082 ack |= _i2c.write(address, tx, 1); 00083 ack |= _i2c.read(address+1, &rx, 1); if (rx != 0x18) ack |= 1; 00084 tx[0] = LSM303_M_MR_REG; 00085 tx[1] = 0x00; // 0000 0000 --> continuous-conversion mode 25 Hz Data rate speed - p.24/42 of datasheet 00086 ack |= _i2c.write(address, tx, 2); 00087 ack |= _i2c.write(address, tx, 1); 00088 ack |= _i2c.read(address+1, &rx, 1); if (rx != 0x00) ack |= 1; 00089 00090 // 2. Initialize calibration constants with predetermined values. 00091 // acceleration: 00092 // My calibration values, vs. the website http://rwsarduino.blogspot.be/2013/01/inertial-orientation-sensing.html 00093 00094 /* my predetermined static bias counts */ 00095 L3GD20_biasX = (int16_t) 90; /* digit counts */ 00096 L3GD20_biasY = (int16_t) -182; 00097 L3GD20_biasZ = (int16_t) -10; 00098 00099 /* reference gravity acceleration */ 00100 g_0 = 9.815; 00101 00102 /* filter parameters: assume 50 Hz sampling rare and 2nd orcer Butterworth filter with fc = 6Hz. */ 00103 pi = 3.1415926536; 00104 A = tan(pi*6/50); a = 1 + sqrt(2.0)*A + A*A; 00105 FF[1] = 2*(A*A-1)/a; 00106 FF[2] = (1-sqrt(2.0)*A+A*A)/a; 00107 FF[0] = (1+FF[1]+FF[2])/4; 00108 00109 return ack; 00110 } 00111 00112 char IMU::readData(float *d) 00113 { 00114 char ack, reg, D[6]; 00115 int16_t W[3]; 00116 00117 // report the data in rad/s 00118 // gyro data are 16 bit readings per axis, stored: X_l, X_h, Y_l, Y_h, Z_l, Z_h 00119 // #define L3GD20_SENSITIVITY_250DPS 0.00875 --- #define L3GD20_DPS_TO_RADS 0.017453293 00120 address = L3GD20_ADDR; 00121 reg = L3GD20_OUT_X_L | 0x80; // set address auto-increment bit 00122 ack = _i2c.write(address,®,1); ack |= _i2c.read(address+1,D,6); 00123 W[0] = (int16_t) (D[1] << 8 | D[0]); 00124 W[1] = (int16_t) (D[3] << 8 | D[2]); 00125 W[2] = (int16_t) (D[5] << 8 | D[4]); 00126 *(d+0) = (float) 0.971*(W[0]-L3GD20_biasX)*L3GD20_SENSITIVITY_250DPS*L3GD20_DPS_TO_RADS; 00127 *(d+1) = (float) 0.998*(W[1]-L3GD20_biasY)*L3GD20_SENSITIVITY_250DPS*L3GD20_DPS_TO_RADS; 00128 *(d+2) = (float) 1.002*(W[2]-L3GD20_biasZ)*L3GD20_SENSITIVITY_250DPS*L3GD20_DPS_TO_RADS; 00129 00130 // Accelerometer data are stored as 12 bit readings, left justified per axis. 00131 // The data needs to be shifted 4 digits to the right! This is not general, only for the A measurement. 00132 address = LSM303_A_ADDR; 00133 reg = LSM303_A_OUT_X_L | 0x80; // set address auto-increment bit 00134 ack |= _i2c.write(address,®,1); ack |= _i2c.read(address+1,D,6); 00135 W[0] = ((int16_t) (D[1] << 8 | D[0])) >> 4; 00136 W[1] = ((int16_t) (D[3] << 8 | D[2])) >> 4; 00137 W[2] = ((int16_t) (D[5] << 8 | D[4])) >> 4; 00138 *(d+3) = (float) g_0*0.991*(W[0]+34)/1000; 00139 *(d+4) = (float) g_0*0.970*(W[1]+2)/1000; 00140 *(d+5) = (float) g_0*0.983*(W[2]+28)/1000; 00141 // GN = 001 00142 // Magnetometer; are stored as 12 bit readings, right justified per axis. 00143 address = LSM303_M_ADDR; 00144 reg = LSM303_M_OUT_X_H | 0x80; // set address auto-increment bit 00145 ack |= _i2c.write(address,®,1); ack |= _i2c.read(address+1,D,6); 00146 W[0] = ((int16_t) (D[0] << 8 | D[1])); 00147 W[1] = ((int16_t) (D[4] << 8 | D[5])); 00148 W[2] = ((int16_t) (D[2] << 8 | D[3])); 00149 *(d+6) = (float) 2.813*(W[0]-264)/1100; 00150 *(d+7) = (float) 2.822*(W[1]- 98)/1100; 00151 *(d+8) = (float) 2.880*(W[2]-305)/980; 00152 00153 return ack; 00154 } 00155 00156 void IMU::filterData(float *d, double *D) 00157 // 2nd order Butterworth filter. Filter coefficients FF computed in function init. 00158 { 00159 for (int i=0; i<9; ++i) { 00160 // *(FD+9*i+2) = *(FD+9*i+1); *(FD+9*i+1) = *(FD+9*i); *(FD+9*i) = (double) d[i]; 00161 FD[2][i] = FD[1][i]; FD[1][i] = FD[0][i]; FD[0][i] = (double) d[i]; 00162 FD[5][i] = FD[4][i]; FD[4][i] = FD[3][i]; 00163 FD[3][i] = FF[0]*(FD[0][i] + 2*FD[1][i] + FD[2][i]) - FF[1]*FD[4][i] - FF[2]*FD[5][i]; 00164 D[i] = FD[3][i]; 00165 } 00166 // D[0] = FD[0][2]; D[1] = FD[1][2]; D[2] = FD[2][2]; 00167 }
Generated on Wed Jul 13 2022 22:54:55 by
1.7.2