rome2_p6 imported
Dependencies: mbed
IMU.cpp@5:957580f33e52, 2018-05-18 (annotated)
- Committer:
- Appalco
- Date:
- Fri May 18 13:54:25 2018 +0000
- Revision:
- 5:957580f33e52
- Parent:
- 0:351a2fb21235
fixed tolerance and wayponts
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Appalco | 0:351a2fb21235 | 1 | /* |
Appalco | 0:351a2fb21235 | 2 | * IMU.cpp |
Appalco | 0:351a2fb21235 | 3 | * Copyright (c) 2018, ZHAW |
Appalco | 0:351a2fb21235 | 4 | * All rights reserved. |
Appalco | 0:351a2fb21235 | 5 | */ |
Appalco | 0:351a2fb21235 | 6 | |
Appalco | 0:351a2fb21235 | 7 | #include <cmath> |
Appalco | 0:351a2fb21235 | 8 | #include "IMU.h" |
Appalco | 0:351a2fb21235 | 9 | |
Appalco | 0:351a2fb21235 | 10 | using namespace std; |
Appalco | 0:351a2fb21235 | 11 | |
Appalco | 0:351a2fb21235 | 12 | const float IMU::PERIOD = 0.001f; // period of filter task, given in [s] |
Appalco | 0:351a2fb21235 | 13 | const float IMU::PI = 3.14159265f; // the constant PI |
Appalco | 0:351a2fb21235 | 14 | const float IMU::LOWPASS_FILTER_FREQUENCY = 6.3f; // frequency of lowpass filter, given in [rad/s] |
Appalco | 0:351a2fb21235 | 15 | |
Appalco | 0:351a2fb21235 | 16 | /** |
Appalco | 0:351a2fb21235 | 17 | * Creates an IMU object. |
Appalco | 0:351a2fb21235 | 18 | * @param spi a reference to an spi controller to use. |
Appalco | 0:351a2fb21235 | 19 | * @param csG the chip select output for the gyro sensor. |
Appalco | 0:351a2fb21235 | 20 | * @param csXM the chip select output for the accelerometer and the magnetometer. |
Appalco | 0:351a2fb21235 | 21 | */ |
Appalco | 0:351a2fb21235 | 22 | IMU::IMU(SPI& spi, DigitalOut& csG, DigitalOut& csXM) : spi(spi), csG(csG), csXM(csXM) { |
Appalco | 0:351a2fb21235 | 23 | |
Appalco | 0:351a2fb21235 | 24 | // initialize SPI interface |
Appalco | 0:351a2fb21235 | 25 | |
Appalco | 0:351a2fb21235 | 26 | spi.format(8, 3); |
Appalco | 0:351a2fb21235 | 27 | spi.frequency(1000000); |
Appalco | 0:351a2fb21235 | 28 | |
Appalco | 0:351a2fb21235 | 29 | // reset chip select lines to logical high |
Appalco | 0:351a2fb21235 | 30 | |
Appalco | 0:351a2fb21235 | 31 | csG = 1; |
Appalco | 0:351a2fb21235 | 32 | csXM = 1; |
Appalco | 0:351a2fb21235 | 33 | |
Appalco | 0:351a2fb21235 | 34 | // initialize gyro |
Appalco | 0:351a2fb21235 | 35 | |
Appalco | 0:351a2fb21235 | 36 | writeRegister(csG, CTRL_REG1_G, 0x0F); // enable gyro in all 3 axis |
Appalco | 0:351a2fb21235 | 37 | |
Appalco | 0:351a2fb21235 | 38 | // initialize accelerometer |
Appalco | 0:351a2fb21235 | 39 | |
Appalco | 0:351a2fb21235 | 40 | writeRegister(csXM, CTRL_REG0_XM, 0x00); |
Appalco | 0:351a2fb21235 | 41 | writeRegister(csXM, CTRL_REG1_XM, 0x5F); |
Appalco | 0:351a2fb21235 | 42 | writeRegister(csXM, CTRL_REG2_XM, 0x00); |
Appalco | 0:351a2fb21235 | 43 | writeRegister(csXM, CTRL_REG3_XM, 0x04); |
Appalco | 0:351a2fb21235 | 44 | |
Appalco | 0:351a2fb21235 | 45 | // initialize magnetometer |
Appalco | 0:351a2fb21235 | 46 | |
Appalco | 0:351a2fb21235 | 47 | writeRegister(csXM, CTRL_REG5_XM, 0x94); |
Appalco | 0:351a2fb21235 | 48 | writeRegister(csXM, CTRL_REG6_XM, 0x00); |
Appalco | 0:351a2fb21235 | 49 | writeRegister(csXM, CTRL_REG7_XM, 0x00); |
Appalco | 0:351a2fb21235 | 50 | writeRegister(csXM, CTRL_REG4_XM, 0x04); |
Appalco | 0:351a2fb21235 | 51 | writeRegister(csXM, INT_CTRL_REG_M, 0x09); |
Appalco | 0:351a2fb21235 | 52 | |
Appalco | 0:351a2fb21235 | 53 | // initialize local variables |
Appalco | 0:351a2fb21235 | 54 | |
Appalco | 0:351a2fb21235 | 55 | magnetometerXMin = 1000.0f; |
Appalco | 0:351a2fb21235 | 56 | magnetometerXMax = -1000.0f; |
Appalco | 0:351a2fb21235 | 57 | magnetometerYMin = 1000.0f; |
Appalco | 0:351a2fb21235 | 58 | magnetometerYMax = -1000.0f; |
Appalco | 0:351a2fb21235 | 59 | |
Appalco | 0:351a2fb21235 | 60 | magnetometerXFilter.setPeriod(PERIOD); |
Appalco | 0:351a2fb21235 | 61 | magnetometerXFilter.setFrequency(LOWPASS_FILTER_FREQUENCY); |
Appalco | 0:351a2fb21235 | 62 | magnetometerXFilter.reset(readMagnetometerX()); |
Appalco | 0:351a2fb21235 | 63 | |
Appalco | 0:351a2fb21235 | 64 | magnetometerYFilter.setPeriod(PERIOD); |
Appalco | 0:351a2fb21235 | 65 | magnetometerYFilter.setFrequency(LOWPASS_FILTER_FREQUENCY); |
Appalco | 0:351a2fb21235 | 66 | magnetometerYFilter.reset(readMagnetometerY()); |
Appalco | 0:351a2fb21235 | 67 | |
Appalco | 0:351a2fb21235 | 68 | heading = 0.0f; |
Appalco | 0:351a2fb21235 | 69 | |
Appalco | 0:351a2fb21235 | 70 | // start periodic task |
Appalco | 0:351a2fb21235 | 71 | |
Appalco | 0:351a2fb21235 | 72 | ticker.attach(callback(this, &IMU::run), PERIOD); |
Appalco | 0:351a2fb21235 | 73 | } |
Appalco | 0:351a2fb21235 | 74 | |
Appalco | 0:351a2fb21235 | 75 | /** |
Appalco | 0:351a2fb21235 | 76 | * Deletes the IMU object. |
Appalco | 0:351a2fb21235 | 77 | */ |
Appalco | 0:351a2fb21235 | 78 | IMU::~IMU() {} |
Appalco | 0:351a2fb21235 | 79 | |
Appalco | 0:351a2fb21235 | 80 | /** |
Appalco | 0:351a2fb21235 | 81 | * This private method allows to write a register value. |
Appalco | 0:351a2fb21235 | 82 | * @param cs the chip select output to use, either csG or csXM. |
Appalco | 0:351a2fb21235 | 83 | * @param address the 7 bit address of the register. |
Appalco | 0:351a2fb21235 | 84 | * @param value the value to write into the register. |
Appalco | 0:351a2fb21235 | 85 | */ |
Appalco | 0:351a2fb21235 | 86 | void IMU::writeRegister(DigitalOut& cs, char address, char value) { |
Appalco | 0:351a2fb21235 | 87 | |
Appalco | 0:351a2fb21235 | 88 | cs = 0; |
Appalco | 0:351a2fb21235 | 89 | |
Appalco | 0:351a2fb21235 | 90 | spi.write(0x7F & address); |
Appalco | 0:351a2fb21235 | 91 | spi.write(value & 0xFF); |
Appalco | 0:351a2fb21235 | 92 | |
Appalco | 0:351a2fb21235 | 93 | cs = 1; |
Appalco | 0:351a2fb21235 | 94 | } |
Appalco | 0:351a2fb21235 | 95 | |
Appalco | 0:351a2fb21235 | 96 | /** |
Appalco | 0:351a2fb21235 | 97 | * This private method allows to read a register value. |
Appalco | 0:351a2fb21235 | 98 | * @param cs the chip select output to use, either csG or csXM. |
Appalco | 0:351a2fb21235 | 99 | * @param address the 7 bit address of the register. |
Appalco | 0:351a2fb21235 | 100 | * @return the value read from the register. |
Appalco | 0:351a2fb21235 | 101 | */ |
Appalco | 0:351a2fb21235 | 102 | char IMU::readRegister(DigitalOut& cs, char address) { |
Appalco | 0:351a2fb21235 | 103 | |
Appalco | 0:351a2fb21235 | 104 | cs = 0; |
Appalco | 0:351a2fb21235 | 105 | |
Appalco | 0:351a2fb21235 | 106 | spi.write(0x80 | address); |
Appalco | 0:351a2fb21235 | 107 | int value = spi.write(0xFF); |
Appalco | 0:351a2fb21235 | 108 | |
Appalco | 0:351a2fb21235 | 109 | cs = 1; |
Appalco | 0:351a2fb21235 | 110 | |
Appalco | 0:351a2fb21235 | 111 | return (char)(value & 0xFF); |
Appalco | 0:351a2fb21235 | 112 | } |
Appalco | 0:351a2fb21235 | 113 | |
Appalco | 0:351a2fb21235 | 114 | /** |
Appalco | 0:351a2fb21235 | 115 | * Reads the gyroscope about the x-axis. |
Appalco | 0:351a2fb21235 | 116 | * @return the rotational speed about the x-axis given in [rad/s]. |
Appalco | 0:351a2fb21235 | 117 | */ |
Appalco | 0:351a2fb21235 | 118 | float IMU::readGyroX() { |
Appalco | 0:351a2fb21235 | 119 | |
Appalco | 0:351a2fb21235 | 120 | char low = readRegister(csG, OUT_X_L_G); |
Appalco | 0:351a2fb21235 | 121 | char high = readRegister(csG, OUT_X_H_G); |
Appalco | 0:351a2fb21235 | 122 | |
Appalco | 0:351a2fb21235 | 123 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 124 | |
Appalco | 0:351a2fb21235 | 125 | return (float)value/32768.0f*245.0f*PI/180.0f; |
Appalco | 0:351a2fb21235 | 126 | } |
Appalco | 0:351a2fb21235 | 127 | |
Appalco | 0:351a2fb21235 | 128 | /** |
Appalco | 0:351a2fb21235 | 129 | * Reads the gyroscope about the y-axis. |
Appalco | 0:351a2fb21235 | 130 | * @return the rotational speed about the y-axis given in [rad/s]. |
Appalco | 0:351a2fb21235 | 131 | */ |
Appalco | 0:351a2fb21235 | 132 | float IMU::readGyroY() { |
Appalco | 0:351a2fb21235 | 133 | |
Appalco | 0:351a2fb21235 | 134 | char low = readRegister(csG, OUT_Y_L_G); |
Appalco | 0:351a2fb21235 | 135 | char high = readRegister(csG, OUT_Y_H_G); |
Appalco | 0:351a2fb21235 | 136 | |
Appalco | 0:351a2fb21235 | 137 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 138 | |
Appalco | 0:351a2fb21235 | 139 | return (float)value/32768.0f*245.0f*PI/180.0f; |
Appalco | 0:351a2fb21235 | 140 | } |
Appalco | 0:351a2fb21235 | 141 | |
Appalco | 0:351a2fb21235 | 142 | /** |
Appalco | 0:351a2fb21235 | 143 | * Reads the gyroscope about the z-axis. |
Appalco | 0:351a2fb21235 | 144 | * @return the rotational speed about the z-axis given in [rad/s]. |
Appalco | 0:351a2fb21235 | 145 | */ |
Appalco | 0:351a2fb21235 | 146 | float IMU::readGyroZ() { |
Appalco | 0:351a2fb21235 | 147 | |
Appalco | 0:351a2fb21235 | 148 | char low = readRegister(csG, OUT_Z_L_G); |
Appalco | 0:351a2fb21235 | 149 | char high = readRegister(csG, OUT_Z_H_G); |
Appalco | 0:351a2fb21235 | 150 | |
Appalco | 0:351a2fb21235 | 151 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 152 | |
Appalco | 0:351a2fb21235 | 153 | return (float)value/32768.0f*245.0f*PI/180.0f; |
Appalco | 0:351a2fb21235 | 154 | } |
Appalco | 0:351a2fb21235 | 155 | |
Appalco | 0:351a2fb21235 | 156 | /** |
Appalco | 0:351a2fb21235 | 157 | * Reads the acceleration in x-direction. |
Appalco | 0:351a2fb21235 | 158 | * @return the acceleration in x-direction, given in [m/s2]. |
Appalco | 0:351a2fb21235 | 159 | */ |
Appalco | 0:351a2fb21235 | 160 | float IMU::readAccelerationX() { |
Appalco | 0:351a2fb21235 | 161 | |
Appalco | 0:351a2fb21235 | 162 | char low = readRegister(csXM, OUT_X_L_A); |
Appalco | 0:351a2fb21235 | 163 | char high = readRegister(csXM, OUT_X_H_A); |
Appalco | 0:351a2fb21235 | 164 | |
Appalco | 0:351a2fb21235 | 165 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 166 | |
Appalco | 0:351a2fb21235 | 167 | return (float)value/32768.0f*2.0f*9.81f; |
Appalco | 0:351a2fb21235 | 168 | } |
Appalco | 0:351a2fb21235 | 169 | |
Appalco | 0:351a2fb21235 | 170 | /** |
Appalco | 0:351a2fb21235 | 171 | * Reads the acceleration in y-direction. |
Appalco | 0:351a2fb21235 | 172 | * @return the acceleration in y-direction, given in [m/s2]. |
Appalco | 0:351a2fb21235 | 173 | */ |
Appalco | 0:351a2fb21235 | 174 | float IMU::readAccelerationY() { |
Appalco | 0:351a2fb21235 | 175 | |
Appalco | 0:351a2fb21235 | 176 | char low = readRegister(csXM, OUT_Y_L_A); |
Appalco | 0:351a2fb21235 | 177 | char high = readRegister(csXM, OUT_Y_H_A); |
Appalco | 0:351a2fb21235 | 178 | |
Appalco | 0:351a2fb21235 | 179 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 180 | |
Appalco | 0:351a2fb21235 | 181 | return (float)value/32768.0f*2.0f*9.81f; |
Appalco | 0:351a2fb21235 | 182 | } |
Appalco | 0:351a2fb21235 | 183 | |
Appalco | 0:351a2fb21235 | 184 | /** |
Appalco | 0:351a2fb21235 | 185 | * Reads the acceleration in z-direction. |
Appalco | 0:351a2fb21235 | 186 | * @return the acceleration in z-direction, given in [m/s2]. |
Appalco | 0:351a2fb21235 | 187 | */ |
Appalco | 0:351a2fb21235 | 188 | float IMU::readAccelerationZ() { |
Appalco | 0:351a2fb21235 | 189 | |
Appalco | 0:351a2fb21235 | 190 | char low = readRegister(csXM, OUT_Z_L_A); |
Appalco | 0:351a2fb21235 | 191 | char high = readRegister(csXM, OUT_Z_H_A); |
Appalco | 0:351a2fb21235 | 192 | |
Appalco | 0:351a2fb21235 | 193 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 194 | |
Appalco | 0:351a2fb21235 | 195 | return (float)value/32768.0f*2.0f*9.81f; |
Appalco | 0:351a2fb21235 | 196 | } |
Appalco | 0:351a2fb21235 | 197 | |
Appalco | 0:351a2fb21235 | 198 | /** |
Appalco | 0:351a2fb21235 | 199 | * Reads the magnetic field in x-direction. |
Appalco | 0:351a2fb21235 | 200 | * @return the magnetic field in x-direction, given in [Gauss]. |
Appalco | 0:351a2fb21235 | 201 | */ |
Appalco | 0:351a2fb21235 | 202 | float IMU::readMagnetometerX() { |
Appalco | 0:351a2fb21235 | 203 | |
Appalco | 0:351a2fb21235 | 204 | char low = readRegister(csXM, OUT_X_L_M); |
Appalco | 0:351a2fb21235 | 205 | char high = readRegister(csXM, OUT_X_H_M); |
Appalco | 0:351a2fb21235 | 206 | |
Appalco | 0:351a2fb21235 | 207 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 208 | |
Appalco | 0:351a2fb21235 | 209 | return (float)value/32768.0f*2.0f; |
Appalco | 0:351a2fb21235 | 210 | } |
Appalco | 0:351a2fb21235 | 211 | |
Appalco | 0:351a2fb21235 | 212 | /** |
Appalco | 0:351a2fb21235 | 213 | * Reads the magnetic field in x-direction. |
Appalco | 0:351a2fb21235 | 214 | * @return the magnetic field in x-direction, given in [Gauss]. |
Appalco | 0:351a2fb21235 | 215 | */ |
Appalco | 0:351a2fb21235 | 216 | float IMU::readMagnetometerY() { |
Appalco | 0:351a2fb21235 | 217 | |
Appalco | 0:351a2fb21235 | 218 | char low = readRegister(csXM, OUT_Y_L_M); |
Appalco | 0:351a2fb21235 | 219 | char high = readRegister(csXM, OUT_Y_H_M); |
Appalco | 0:351a2fb21235 | 220 | |
Appalco | 0:351a2fb21235 | 221 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 222 | |
Appalco | 0:351a2fb21235 | 223 | return (float)value/32768.0f*2.0f; |
Appalco | 0:351a2fb21235 | 224 | } |
Appalco | 0:351a2fb21235 | 225 | |
Appalco | 0:351a2fb21235 | 226 | /** |
Appalco | 0:351a2fb21235 | 227 | * Reads the magnetic field in x-direction. |
Appalco | 0:351a2fb21235 | 228 | * @return the magnetic field in x-direction, given in [Gauss]. |
Appalco | 0:351a2fb21235 | 229 | */ |
Appalco | 0:351a2fb21235 | 230 | float IMU::readMagnetometerZ() { |
Appalco | 0:351a2fb21235 | 231 | |
Appalco | 0:351a2fb21235 | 232 | char low = readRegister(csXM, OUT_Z_L_M); |
Appalco | 0:351a2fb21235 | 233 | char high = readRegister(csXM, OUT_Z_H_M); |
Appalco | 0:351a2fb21235 | 234 | |
Appalco | 0:351a2fb21235 | 235 | short value = (short)(((unsigned short)high << 8) | (unsigned short)low); |
Appalco | 0:351a2fb21235 | 236 | |
Appalco | 0:351a2fb21235 | 237 | return (float)value/32768.0f*2.0f; |
Appalco | 0:351a2fb21235 | 238 | } |
Appalco | 0:351a2fb21235 | 239 | |
Appalco | 0:351a2fb21235 | 240 | /** |
Appalco | 0:351a2fb21235 | 241 | * Reads the compass heading about the z-axis. |
Appalco | 0:351a2fb21235 | 242 | * @return the compass heading in the range -PI to +PI, given in [rad]. |
Appalco | 0:351a2fb21235 | 243 | */ |
Appalco | 0:351a2fb21235 | 244 | float IMU::readHeading() { |
Appalco | 0:351a2fb21235 | 245 | |
Appalco | 0:351a2fb21235 | 246 | return heading; |
Appalco | 0:351a2fb21235 | 247 | } |
Appalco | 0:351a2fb21235 | 248 | |
Appalco | 0:351a2fb21235 | 249 | /** |
Appalco | 0:351a2fb21235 | 250 | * This method is called periodically by the ticker object and contains the |
Appalco | 0:351a2fb21235 | 251 | * calculation and filtering of the heading information. |
Appalco | 0:351a2fb21235 | 252 | */ |
Appalco | 0:351a2fb21235 | 253 | void IMU::run() { |
Appalco | 0:351a2fb21235 | 254 | |
Appalco | 0:351a2fb21235 | 255 | // read actual measurements from magnetometer registers |
Appalco | 0:351a2fb21235 | 256 | |
Appalco | 0:351a2fb21235 | 257 | float magnetometerX = magnetometerXFilter.filter(readMagnetometerX()); |
Appalco | 0:351a2fb21235 | 258 | float magnetometerY = magnetometerYFilter.filter(readMagnetometerY()); |
Appalco | 0:351a2fb21235 | 259 | |
Appalco | 0:351a2fb21235 | 260 | // adjust the minimum and maximum limits, if needed |
Appalco | 0:351a2fb21235 | 261 | |
Appalco | 0:351a2fb21235 | 262 | if (magnetometerXMin > magnetometerX) magnetometerXMin = magnetometerX; |
Appalco | 0:351a2fb21235 | 263 | if (magnetometerXMax < magnetometerX) magnetometerXMax = magnetometerX; |
Appalco | 0:351a2fb21235 | 264 | if (magnetometerYMin > magnetometerY) magnetometerYMin = magnetometerY; |
Appalco | 0:351a2fb21235 | 265 | if (magnetometerYMax < magnetometerY) magnetometerYMax = magnetometerY; |
Appalco | 0:351a2fb21235 | 266 | |
Appalco | 0:351a2fb21235 | 267 | // calculate adjusted magnetometer values (gain and offset compensation) |
Appalco | 0:351a2fb21235 | 268 | |
Appalco | 0:351a2fb21235 | 269 | if (magnetometerXMin < magnetometerXMax) magnetometerX = (magnetometerX-magnetometerXMin)/(magnetometerXMax-magnetometerXMin)-0.5f; |
Appalco | 0:351a2fb21235 | 270 | if (magnetometerYMin < magnetometerYMax) magnetometerY = (magnetometerY-magnetometerYMin)/(magnetometerYMax-magnetometerYMin)-0.5f; |
Appalco | 0:351a2fb21235 | 271 | |
Appalco | 0:351a2fb21235 | 272 | // calculate heading with atan2 from x and y magnetometer measurements |
Appalco | 0:351a2fb21235 | 273 | |
Appalco | 0:351a2fb21235 | 274 | heading = atan2(magnetometerX, magnetometerY); |
Appalco | 0:351a2fb21235 | 275 | } |
Appalco | 0:351a2fb21235 | 276 |