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.
Dependencies: mbed
IMU.cpp
00001 /* 00002 * IMU.cpp 00003 * Copyright (c) 2018, ZHAW 00004 * All rights reserved. 00005 */ 00006 00007 #include <cmath> 00008 #include "IMU.h" 00009 00010 using namespace std; 00011 00012 const float IMU::PERIOD = 0.001f; // period of filter task, given in [s] 00013 const float IMU::PI = 3.14159265f; // the constant PI 00014 const float IMU::LOWPASS_FILTER_FREQUENCY = 6.3f; // frequency of lowpass filter, given in [rad/s] 00015 00016 /** 00017 * Creates an IMU object. 00018 * @param spi a reference to an spi controller to use. 00019 * @param csG the chip select output for the gyro sensor. 00020 * @param csXM the chip select output for the accelerometer and the magnetometer. 00021 */ 00022 IMU::IMU(SPI& spi, DigitalOut& csG, DigitalOut& csXM) : spi(spi), csG(csG), csXM(csXM) { 00023 00024 // initialize SPI interface 00025 00026 spi.format(8, 3); 00027 spi.frequency(1000000); 00028 00029 // reset chip select lines to logical high 00030 00031 csG = 1; 00032 csXM = 1; 00033 00034 // initialize gyro 00035 00036 writeRegister(csG, CTRL_REG1_G, 0x0F); // enable gyro in all 3 axis 00037 00038 // initialize accelerometer 00039 00040 writeRegister(csXM, CTRL_REG0_XM, 0x00); 00041 writeRegister(csXM, CTRL_REG1_XM, 0x5F); 00042 writeRegister(csXM, CTRL_REG2_XM, 0x00); 00043 writeRegister(csXM, CTRL_REG3_XM, 0x04); 00044 00045 // initialize magnetometer 00046 00047 writeRegister(csXM, CTRL_REG5_XM, 0x94); 00048 writeRegister(csXM, CTRL_REG6_XM, 0x00); 00049 writeRegister(csXM, CTRL_REG7_XM, 0x00); 00050 writeRegister(csXM, CTRL_REG4_XM, 0x04); 00051 writeRegister(csXM, INT_CTRL_REG_M, 0x09); 00052 00053 // initialize local variables 00054 00055 magnetometerXMin = 1000.0f; 00056 magnetometerXMax = -1000.0f; 00057 magnetometerYMin = 1000.0f; 00058 magnetometerYMax = -1000.0f; 00059 00060 magnetometerXFilter.setPeriod(PERIOD); 00061 magnetometerXFilter.setFrequency(LOWPASS_FILTER_FREQUENCY); 00062 magnetometerXFilter.reset(readMagnetometerX()); 00063 00064 magnetometerYFilter.setPeriod(PERIOD); 00065 magnetometerYFilter.setFrequency(LOWPASS_FILTER_FREQUENCY); 00066 magnetometerYFilter.reset(readMagnetometerY()); 00067 00068 heading = 0.0f; 00069 00070 // start periodic task 00071 00072 ticker.attach(callback(this, &IMU::run), PERIOD); 00073 } 00074 00075 /** 00076 * Deletes the IMU object. 00077 */ 00078 IMU::~IMU() {} 00079 00080 /** 00081 * This private method allows to write a register value. 00082 * @param cs the chip select output to use, either csG or csXM. 00083 * @param address the 7 bit address of the register. 00084 * @param value the value to write into the register. 00085 */ 00086 void IMU::writeRegister(DigitalOut& cs, char address, char value) { 00087 00088 cs = 0; 00089 00090 spi.write(0x7F & address); 00091 spi.write(value & 0xFF); 00092 00093 cs = 1; 00094 } 00095 00096 /** 00097 * This private method allows to read a register value. 00098 * @param cs the chip select output to use, either csG or csXM. 00099 * @param address the 7 bit address of the register. 00100 * @return the value read from the register. 00101 */ 00102 char IMU::readRegister(DigitalOut& cs, char address) { 00103 00104 cs = 0; 00105 00106 spi.write(0x80 | address); 00107 int value = spi.write(0xFF); 00108 00109 cs = 1; 00110 00111 return (char)(value & 0xFF); 00112 } 00113 00114 /** 00115 * Reads the gyroscope about the x-axis. 00116 * @return the rotational speed about the x-axis given in [rad/s]. 00117 */ 00118 float IMU::readGyroX() { 00119 00120 char low = readRegister(csG, OUT_X_L_G); 00121 char high = readRegister(csG, OUT_X_H_G); 00122 00123 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00124 00125 return (float)value/32768.0f*245.0f*PI/180.0f; 00126 } 00127 00128 /** 00129 * Reads the gyroscope about the y-axis. 00130 * @return the rotational speed about the y-axis given in [rad/s]. 00131 */ 00132 float IMU::readGyroY() { 00133 00134 char low = readRegister(csG, OUT_Y_L_G); 00135 char high = readRegister(csG, OUT_Y_H_G); 00136 00137 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00138 00139 return (float)value/32768.0f*245.0f*PI/180.0f; 00140 } 00141 00142 /** 00143 * Reads the gyroscope about the z-axis. 00144 * @return the rotational speed about the z-axis given in [rad/s]. 00145 */ 00146 float IMU::readGyroZ() { 00147 00148 char low = readRegister(csG, OUT_Z_L_G); 00149 char high = readRegister(csG, OUT_Z_H_G); 00150 00151 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00152 00153 return (float)value/32768.0f*245.0f*PI/180.0f; 00154 } 00155 00156 /** 00157 * Reads the acceleration in x-direction. 00158 * @return the acceleration in x-direction, given in [m/s2]. 00159 */ 00160 float IMU::readAccelerationX() { 00161 00162 char low = readRegister(csXM, OUT_X_L_A); 00163 char high = readRegister(csXM, OUT_X_H_A); 00164 00165 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00166 00167 return (float)value/32768.0f*2.0f*9.81f; 00168 } 00169 00170 /** 00171 * Reads the acceleration in y-direction. 00172 * @return the acceleration in y-direction, given in [m/s2]. 00173 */ 00174 float IMU::readAccelerationY() { 00175 00176 char low = readRegister(csXM, OUT_Y_L_A); 00177 char high = readRegister(csXM, OUT_Y_H_A); 00178 00179 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00180 00181 return (float)value/32768.0f*2.0f*9.81f; 00182 } 00183 00184 /** 00185 * Reads the acceleration in z-direction. 00186 * @return the acceleration in z-direction, given in [m/s2]. 00187 */ 00188 float IMU::readAccelerationZ() { 00189 00190 char low = readRegister(csXM, OUT_Z_L_A); 00191 char high = readRegister(csXM, OUT_Z_H_A); 00192 00193 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00194 00195 return (float)value/32768.0f*2.0f*9.81f; 00196 } 00197 00198 /** 00199 * Reads the magnetic field in x-direction. 00200 * @return the magnetic field in x-direction, given in [Gauss]. 00201 */ 00202 float IMU::readMagnetometerX() { 00203 00204 char low = readRegister(csXM, OUT_X_L_M); 00205 char high = readRegister(csXM, OUT_X_H_M); 00206 00207 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00208 00209 return (float)value/32768.0f*2.0f; 00210 } 00211 00212 /** 00213 * Reads the magnetic field in x-direction. 00214 * @return the magnetic field in x-direction, given in [Gauss]. 00215 */ 00216 float IMU::readMagnetometerY() { 00217 00218 char low = readRegister(csXM, OUT_Y_L_M); 00219 char high = readRegister(csXM, OUT_Y_H_M); 00220 00221 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00222 00223 return (float)value/32768.0f*2.0f; 00224 } 00225 00226 /** 00227 * Reads the magnetic field in x-direction. 00228 * @return the magnetic field in x-direction, given in [Gauss]. 00229 */ 00230 float IMU::readMagnetometerZ() { 00231 00232 char low = readRegister(csXM, OUT_Z_L_M); 00233 char high = readRegister(csXM, OUT_Z_H_M); 00234 00235 short value = (short)(((unsigned short)high << 8) | (unsigned short)low); 00236 00237 return (float)value/32768.0f*2.0f; 00238 } 00239 00240 /** 00241 * Reads the compass heading about the z-axis. 00242 * @return the compass heading in the range -PI to +PI, given in [rad]. 00243 */ 00244 float IMU::readHeading() { 00245 00246 return heading; 00247 } 00248 00249 /** 00250 * This method is called periodically by the ticker object and contains the 00251 * calculation and filtering of the heading information. 00252 */ 00253 void IMU::run() { 00254 00255 // read actual measurements from magnetometer registers 00256 00257 float magnetometerX = magnetometerXFilter.filter(readMagnetometerX()); 00258 float magnetometerY = magnetometerYFilter.filter(readMagnetometerY()); 00259 00260 // adjust the minimum and maximum limits, if needed 00261 00262 if (magnetometerXMin > magnetometerX) magnetometerXMin = magnetometerX; 00263 if (magnetometerXMax < magnetometerX) magnetometerXMax = magnetometerX; 00264 if (magnetometerYMin > magnetometerY) magnetometerYMin = magnetometerY; 00265 if (magnetometerYMax < magnetometerY) magnetometerYMax = magnetometerY; 00266 00267 // calculate adjusted magnetometer values (gain and offset compensation) 00268 00269 if (magnetometerXMin < magnetometerXMax) magnetometerX = (magnetometerX-magnetometerXMin)/(magnetometerXMax-magnetometerXMin)-0.5f; 00270 if (magnetometerYMin < magnetometerYMax) magnetometerY = (magnetometerY-magnetometerYMin)/(magnetometerYMax-magnetometerYMin)-0.5f; 00271 00272 // calculate heading with atan2 from x and y magnetometer measurements 00273 00274 heading = atan2(magnetometerX, magnetometerY); 00275 } 00276
Generated on Sun Jul 23 2023 17:17:31 by
 1.7.2
 1.7.2