A quick and dirty demo of the Xadow M0 acceleromoeter values displayed on the Xadow OLED 0.96" (using the SSD1308 128x64 OLED Driver with I2C interface library).

Dependencies:   mbed SSD1308_128x64_I2C_opt XadowGPS BMP180 ADXL345_I2C MPU9250 USBDevice

Committer:
ruevs
Date:
Fri Mar 01 09:48:20 2019 +0000
Revision:
9:310663c014d8
Parent:
8:4e8991196bb8
Implement online magnetometer calibration - offset and scale.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ruevs 2:7abdbccdf0c8 1 #define __STDC_LIMIT_MACROS 1
ruevs 2:7abdbccdf0c8 2 #include <stdint.h>
seeed 0:b017c907d53d 3
ruevs 2:7abdbccdf0c8 4 #include "ADXL345_I2C.h"
ruevs 2:7abdbccdf0c8 5 #include "SSD1308.h"
ruevs 5:50051611b5bd 6 #include "MPU9250.h"
ruevs 5:50051611b5bd 7 #include "BMP180.h"
ruevs 2:7abdbccdf0c8 8
ruevs 5:50051611b5bd 9 #define DEBUG
seeed 0:b017c907d53d 10
seeed 0:b017c907d53d 11 #ifdef DEBUG
seeed 0:b017c907d53d 12 #include "USBSerial.h" // To use USB virtual serial, a driver is needed, check http://mbed.org/handbook/USBSerial
seeed 0:b017c907d53d 13 #define LOG(args...) pc.printf(args)
seeed 0:b017c907d53d 14 USBSerial pc;
seeed 0:b017c907d53d 15 #else
seeed 0:b017c907d53d 16 #define LOG(args...)
seeed 0:b017c907d53d 17 #endif
seeed 0:b017c907d53d 18
ruevs 2:7abdbccdf0c8 19 #define MAX_ACC_AXIS 3
seeed 0:b017c907d53d 20 ADXL345_I2C accelerometer(P0_5, P0_4);
seeed 0:b017c907d53d 21
ruevs 2:7abdbccdf0c8 22 // Xhadow - OLED 128x64 is connected with I2C
ruevs 2:7abdbccdf0c8 23 I2C i2c(P0_5, P0_4); // SDA, SCL
ruevs 2:7abdbccdf0c8 24 SSD1308 oled = SSD1308(i2c, SSD1308_SA0);
ruevs 5:50051611b5bd 25 SSD1308 oled2 = SSD1308(i2c, SSD1308_SA1);
ruevs 5:50051611b5bd 26
ruevs 5:50051611b5bd 27 // MPU9250 9DOF IMU - accelerometer, gyroscope, magnetometer access class
ruevs 5:50051611b5bd 28 MPU9250 mpu9250(i2c);
ruevs 5:50051611b5bd 29
ruevs 5:50051611b5bd 30 // BMP180 pressure and temperature sensor access class
ruevs 5:50051611b5bd 31 BMP180 bmp180(&i2c);
ruevs 2:7abdbccdf0c8 32
ruevs 2:7abdbccdf0c8 33 AnalogIn AD00(P0_11);
ruevs 2:7abdbccdf0c8 34 AnalogIn AD01(P0_12);
ruevs 2:7abdbccdf0c8 35 AnalogIn ChargerStatus(P0_13); // ADC input from VCC through a 200K/200K divider with extara 100K pull down on !DONE and 49.9K on !CHRG
ruevs 2:7abdbccdf0c8 36
ruevs 2:7abdbccdf0c8 37 DigitalOut blue_led(P0_20, 0);
ruevs 2:7abdbccdf0c8 38 DigitalOut white_led(P0_23, 1);
ruevs 2:7abdbccdf0c8 39 DigitalOut Bus3V3En(P0_14, 1); // Pin that controls the BUS-3V3 (3.3V) regulator output to the Xadow Bus
ruevs 2:7abdbccdf0c8 40
ruevs 2:7abdbccdf0c8 41 InterruptIn test_int(P0_7);
ruevs 2:7abdbccdf0c8 42
ruevs 2:7abdbccdf0c8 43 void test_pin_int(void)
ruevs 2:7abdbccdf0c8 44 {
ruevs 2:7abdbccdf0c8 45 white_led = !white_led;
ruevs 2:7abdbccdf0c8 46 Bus3V3En = !Bus3V3En;
ruevs 2:7abdbccdf0c8 47 }
ruevs 2:7abdbccdf0c8 48
ruevs 5:50051611b5bd 49 void MPU9250Test()
ruevs 5:50051611b5bd 50 {
ruevs 5:50051611b5bd 51 Timer t;
ruevs 5:50051611b5bd 52 float sum = 0;
ruevs 5:50051611b5bd 53 uint32_t sumCount = 0;
ruevs 5:50051611b5bd 54
ruevs 5:50051611b5bd 55 char buffer[14];
ruevs 5:50051611b5bd 56
ruevs 5:50051611b5bd 57 uint8_t whoami;
ruevs 5:50051611b5bd 58
ruevs 5:50051611b5bd 59 //___ Set up I2C: use fast (400 kHz) I2C ___
ruevs 5:50051611b5bd 60 i2c.frequency(400000);
ruevs 5:50051611b5bd 61
ruevs 5:50051611b5bd 62 wait(10); // to allow terminal to cooect on PC
ruevs 5:50051611b5bd 63
ruevs 5:50051611b5bd 64 while(1) {
ruevs 5:50051611b5bd 65 if (bmp180.init() != 0) {
ruevs 5:50051611b5bd 66 LOG("Error communicating with BMP180r\n");
ruevs 5:50051611b5bd 67 } else {
ruevs 7:4931dbfbc042 68 LOG("Initialized BMP180\r\n");
ruevs 5:50051611b5bd 69 break;
ruevs 5:50051611b5bd 70 }
ruevs 5:50051611b5bd 71 wait(1);
ruevs 5:50051611b5bd 72 }
ruevs 5:50051611b5bd 73
ruevs 5:50051611b5bd 74 LOG("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);
ruevs 5:50051611b5bd 75
ruevs 5:50051611b5bd 76 t.start(); // Timer ON
ruevs 5:50051611b5bd 77
ruevs 5:50051611b5bd 78 // Read the WHO_AM_I register, this is a good test of communication
ruevs 5:50051611b5bd 79 whoami = mpu9250.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);
ruevs 5:50051611b5bd 80
ruevs 5:50051611b5bd 81 LOG("I AM 0x%x\r\n", whoami); LOG("I SHOULD BE 0x71\r\n");
ruevs 5:50051611b5bd 82 if (I2Cstate != 0) // error on I2C
ruevs 5:50051611b5bd 83 LOG("I2C failure while reading WHO_AM_I register");
ruevs 5:50051611b5bd 84
ruevs 5:50051611b5bd 85 if (whoami == 0x71) // WHO_AM_I should always be 0x71
ruevs 5:50051611b5bd 86 {
ruevs 5:50051611b5bd 87 LOG("MPU9250 WHO_AM_I is 0x%x\r\n", whoami);
ruevs 5:50051611b5bd 88 LOG("MPU9250 is online...\r\n");
ruevs 5:50051611b5bd 89 sprintf(buffer, "0x%x", whoami);
ruevs 5:50051611b5bd 90 wait(1);
ruevs 5:50051611b5bd 91
ruevs 5:50051611b5bd 92 mpu9250.resetMPU9250(); // Reset registers to default in preparation for device calibration
ruevs 5:50051611b5bd 93
ruevs 5:50051611b5bd 94 mpu9250.MPU9250SelfTest(SelfTest); // Start by performing self test and reporting values (accelerometer and gyroscope self test)
ruevs 5:50051611b5bd 95 LOG("x-axis self test: acceleration trim within : %f % of factory value\r\n", SelfTest[0]);
ruevs 5:50051611b5bd 96 LOG("y-axis self test: acceleration trim within : %f % of factory value\r\n", SelfTest[1]);
ruevs 5:50051611b5bd 97 LOG("z-axis self test: acceleration trim within : %f % of factory value\r\n", SelfTest[2]);
ruevs 5:50051611b5bd 98 LOG("x-axis self test: gyration trim within : %f % of factory value\r\n", SelfTest[3]);
ruevs 5:50051611b5bd 99 LOG("y-axis self test: gyration trim within : %f % of factory value\r\n", SelfTest[4]);
ruevs 5:50051611b5bd 100 LOG("z-axis self test: gyration trim within : %f % of factory value\r\n", SelfTest[5]);
ruevs 5:50051611b5bd 101
ruevs 5:50051611b5bd 102 mpu9250.calibrateMPU9250(gyroBias, accelBias); // Calibrate gyro and accelerometer, load biases in bias registers
ruevs 5:50051611b5bd 103 LOG("x gyro bias = %f\r\n", gyroBias[0]);
ruevs 5:50051611b5bd 104 LOG("y gyro bias = %f\r\n", gyroBias[1]);
ruevs 5:50051611b5bd 105 LOG("z gyro bias = %f\r\n", gyroBias[2]);
ruevs 5:50051611b5bd 106 LOG("x accel bias = %f\r\n", accelBias[0]);
ruevs 5:50051611b5bd 107 LOG("y accel bias = %f\r\n", accelBias[1]);
ruevs 5:50051611b5bd 108 LOG("z accel bias = %f\r\n", accelBias[2]);
ruevs 5:50051611b5bd 109 wait(2);
ruevs 5:50051611b5bd 110
ruevs 5:50051611b5bd 111 // Initialize device for active mode read of acclerometer, gyroscope, and temperature
ruevs 5:50051611b5bd 112 mpu9250.initMPU9250();
ruevs 5:50051611b5bd 113 LOG("MPU9250 initialized for active data mode....\r\n");
ruevs 5:50051611b5bd 114
ruevs 5:50051611b5bd 115 // Initialize device for active mode read of magnetometer, 16 bit resolution, 100Hz.
ruevs 5:50051611b5bd 116 mpu9250.initAK8963(magCalibration);
ruevs 5:50051611b5bd 117 LOG("AK8963 initialized for active data mode....\r\n");
ruevs 5:50051611b5bd 118 LOG("Accelerometer full-scale range = %f g\r\n", 2.0f*(float)(1<<Ascale));
ruevs 5:50051611b5bd 119 LOG("Gyroscope full-scale range = %f deg/s\r\n", 250.0f*(float)(1<<Gscale));
ruevs 5:50051611b5bd 120 if(Mscale == 0) LOG("Magnetometer resolution = 14 bits\r\n");
ruevs 5:50051611b5bd 121 if(Mscale == 1) LOG("Magnetometer resolution = 16 bits\r\n");
ruevs 5:50051611b5bd 122 if(Mmode == 2) LOG("Magnetometer ODR = 8 Hz\r\n");
ruevs 5:50051611b5bd 123 if(Mmode == 6) LOG("Magnetometer ODR = 100 Hz\r\n");
ruevs 5:50051611b5bd 124 wait(1);
ruevs 5:50051611b5bd 125 }
ruevs 5:50051611b5bd 126
ruevs 5:50051611b5bd 127 else // Connection failure
ruevs 5:50051611b5bd 128 {
ruevs 5:50051611b5bd 129 LOG("Could not connect to MPU9250: \r\n");
ruevs 5:50051611b5bd 130 LOG("%#x \n", whoami);
ruevs 5:50051611b5bd 131 sprintf(buffer, "WHO_AM_I 0x%x", whoami);
ruevs 5:50051611b5bd 132 while(1) ; // Loop forever if communication doesn't happen
ruevs 5:50051611b5bd 133 }
ruevs 5:50051611b5bd 134
ruevs 5:50051611b5bd 135 mpu9250.getAres(); // Get accelerometer sensitivity
ruevs 5:50051611b5bd 136 mpu9250.getGres(); // Get gyro sensitivity
ruevs 5:50051611b5bd 137 mpu9250.getMres(); // Get magnetometer sensitivity
ruevs 5:50051611b5bd 138 LOG("Accelerometer sensitivity is %f LSB/g \r\n", 1.0f/aRes);
ruevs 5:50051611b5bd 139 LOG("Gyroscope sensitivity is %f LSB/deg/s \r\n", 1.0f/gRes);
ruevs 5:50051611b5bd 140 LOG("Magnetometer sensitivity is %f LSB/G \r\n", 1.0f/mRes);
ruevs 9:310663c014d8 141 /*
ruevs 5:50051611b5bd 142 magbias[0] = +470.; // User environmental x-axis correction in milliGauss, should be automatically calculated
ruevs 5:50051611b5bd 143 magbias[1] = +120.; // User environmental x-axis correction in milliGauss
ruevs 5:50051611b5bd 144 magbias[2] = +125.; // User environmental x-axis correction in milliGauss
ruevs 9:310663c014d8 145 */
ruevs 5:50051611b5bd 146
ruevs 5:50051611b5bd 147 while(1) {
ruevs 5:50051611b5bd 148
ruevs 5:50051611b5bd 149 // If intPin goes high, all data registers have new data
ruevs 5:50051611b5bd 150 if(mpu9250.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01) { // On interrupt, check if data ready interrupt
ruevs 5:50051611b5bd 151
ruevs 5:50051611b5bd 152 mpu9250.readAccelData(accelCount); // Read the x/y/z adc values
ruevs 5:50051611b5bd 153 // Now we'll calculate the accleration value into actual g's
ruevs 5:50051611b5bd 154 if (I2Cstate != 0) //error on I2C
ruevs 5:50051611b5bd 155 LOG("I2C error ocurred while reading accelerometer data. I2Cstate = %d \r\n", I2Cstate);
ruevs 5:50051611b5bd 156 else{ // I2C read or write ok
ruevs 5:50051611b5bd 157 I2Cstate = 1;
ruevs 5:50051611b5bd 158 ax = (float)accelCount[0]*aRes - accelBias[0]; // get actual g value, this depends on scale being set
ruevs 5:50051611b5bd 159 ay = (float)accelCount[1]*aRes - accelBias[1];
ruevs 5:50051611b5bd 160 az = (float)accelCount[2]*aRes - accelBias[2];
ruevs 5:50051611b5bd 161 }
ruevs 5:50051611b5bd 162
ruevs 5:50051611b5bd 163 mpu9250.readGyroData(gyroCount); // Read the x/y/z adc values
ruevs 5:50051611b5bd 164 // Calculate the gyro value into actual degrees per second
ruevs 5:50051611b5bd 165 if (I2Cstate != 0) //error on I2C
ruevs 5:50051611b5bd 166 LOG("I2C error ocurred while reading gyrometer data. I2Cstate = %d \r\n", I2Cstate);
ruevs 5:50051611b5bd 167 else{ // I2C read or write ok
ruevs 5:50051611b5bd 168 I2Cstate = 1;
ruevs 5:50051611b5bd 169 gx = (float)gyroCount[0]*gRes - gyroBias[0]; // get actual gyro value, this depends on scale being set
ruevs 5:50051611b5bd 170 gy = (float)gyroCount[1]*gRes - gyroBias[1];
ruevs 5:50051611b5bd 171 gz = (float)gyroCount[2]*gRes - gyroBias[2];
ruevs 5:50051611b5bd 172 }
ruevs 5:50051611b5bd 173
ruevs 5:50051611b5bd 174 mpu9250.readMagData(magCount); // Read the x/y/z adc values
ruevs 5:50051611b5bd 175 // Calculate the magnetometer values in milliGauss
ruevs 5:50051611b5bd 176 // Include factory calibration per data sheet and user environmental corrections
ruevs 5:50051611b5bd 177 if (I2Cstate != 0) //error on I2C
ruevs 5:50051611b5bd 178 LOG("I2C error ocurred while reading magnetometer data. I2Cstate = %d \r\n", I2Cstate);
ruevs 5:50051611b5bd 179 else{ // I2C read or write ok
ruevs 5:50051611b5bd 180 I2Cstate = 1;
ruevs 9:310663c014d8 181 /* Online magnetometer calibration */
ruevs 9:310663c014d8 182 float magAverageXYZRange = 0;
ruevs 9:310663c014d8 183 for(int i=0;i<3;++i) {
ruevs 9:310663c014d8 184 if (magCount[i]<minMagCount[i]) {
ruevs 9:310663c014d8 185 minMagCount[i] = magCount[i];
ruevs 9:310663c014d8 186 magbias[i] = (minMagCount[i]+maxMagCount[i])*mRes*magCalibration[1]/2.;
ruevs 9:310663c014d8 187 }
ruevs 9:310663c014d8 188 if (magCount[i]>maxMagCount[i]) {
ruevs 9:310663c014d8 189 maxMagCount[i] = magCount[i];
ruevs 9:310663c014d8 190 magbias[i] = (minMagCount[i]+maxMagCount[i])*mRes*magCalibration[1]/2.;
ruevs 9:310663c014d8 191 }
ruevs 9:310663c014d8 192 magAverageXYZRange += maxMagCount[i]-minMagCount[i];
ruevs 9:310663c014d8 193 }
ruevs 9:310663c014d8 194
ruevs 9:310663c014d8 195 magAverageXYZRange /= 3.;
ruevs 9:310663c014d8 196
ruevs 9:310663c014d8 197 for(int i=0;i<3;++i) {
ruevs 9:310663c014d8 198 magScale[i] = magAverageXYZRange / (maxMagCount[i]-minMagCount[i]);
ruevs 9:310663c014d8 199 }
ruevs 9:310663c014d8 200
ruevs 9:310663c014d8 201 mx = (float)magCount[0]*mRes*magCalibration[0]*magScale[0] - magbias[0]; // get actual magnetometer value, this depends on scale being set
ruevs 9:310663c014d8 202 my = (float)magCount[1]*mRes*magCalibration[1]*magScale[1] - magbias[1];
ruevs 9:310663c014d8 203 mz = (float)magCount[2]*mRes*magCalibration[2]*magScale[2] - magbias[2];
ruevs 5:50051611b5bd 204 }
ruevs 5:50051611b5bd 205
ruevs 5:50051611b5bd 206 mpu9250.getCompassOrientation(orientation);
ruevs 5:50051611b5bd 207 }
ruevs 5:50051611b5bd 208
ruevs 5:50051611b5bd 209 Now = t.read_us();
ruevs 5:50051611b5bd 210 deltat = (float)((Now - lastUpdate)/1000000.0f) ; // set integration time by time elapsed since last filter update
ruevs 5:50051611b5bd 211 lastUpdate = Now;
ruevs 5:50051611b5bd 212 sum += deltat;
ruevs 5:50051611b5bd 213 sumCount++;
ruevs 5:50051611b5bd 214
ruevs 8:4e8991196bb8 215 // Sensors x (y)-axis of the accelerometer/gyro is aligned with the y (x)-axis of the magnetometer;
ruevs 8:4e8991196bb8 216 // the magnetometer z-axis (+ down) is misaligned with z-axis (+ up) of accelerometer and gyro!
ruevs 8:4e8991196bb8 217 // We have to make some allowance for this orientation mismatch in feeding the output to the quaternion filter.
ruevs 8:4e8991196bb8 218 // We will assume that +y accel/gyro is North, then x accel/gyro is East. So if we want te quaternions properly aligned
ruevs 8:4e8991196bb8 219 // we need to feed into the madgwick function Ay, Ax, -Az, Gy, Gx, -Gz, Mx, My, and Mz. But because gravity is by convention
ruevs 8:4e8991196bb8 220 // positive down, we need to invert the accel data, so we pass -Ay, -Ax, Az, Gy, Gx, -Gz, Mx, My, and Mz into the Madgwick
ruevs 8:4e8991196bb8 221 // function to get North along the accel +y-axis, East along the accel +x-axis, and Down along the accel -z-axis.
ruevs 8:4e8991196bb8 222 // This orientation choice can be modified to allow any convenient (non-NED) orientation convention.
ruevs 8:4e8991196bb8 223 // This is ok by aircraft orientation standards!
ruevs 5:50051611b5bd 224 // Pass gyro rate as rad/s
ruevs 8:4e8991196bb8 225 // mpu9250.MadgwickQuaternionUpdate(-ay, -ax, az, gy*PI/180.0f, gx*PI/180.0f, -gz*PI/180.0f, mx, my, mz);
ruevs 8:4e8991196bb8 226 mpu9250.MahonyQuaternionUpdate(-ay, -ax, az, gy*PI/180.0f, gx*PI/180.0f, -gz*PI/180.0f, mx, my, mz);
ruevs 5:50051611b5bd 227
ruevs 9:310663c014d8 228 white_led= !white_led;
ruevs 5:50051611b5bd 229
ruevs 5:50051611b5bd 230 // Serial print and/or display at 1.5 s rate independent of data rates
ruevs 5:50051611b5bd 231 delt_t = t.read_ms() - count;
ruevs 5:50051611b5bd 232 if (delt_t > 1500) { // update LCD once per half-second independent of read rate
ruevs 7:4931dbfbc042 233 LOG("\033[2J"); // ANSI clear screen ESC[2J
ruevs 5:50051611b5bd 234 LOG("ax = %f", 1000*ax);
ruevs 5:50051611b5bd 235 LOG(" ay = %f", 1000*ay);
ruevs 5:50051611b5bd 236 LOG(" az = %f mg\r\n", 1000*az);
ruevs 5:50051611b5bd 237 LOG("gx = %f", gx);
ruevs 5:50051611b5bd 238 LOG(" gy = %f", gy);
ruevs 5:50051611b5bd 239 LOG(" gz = %f deg/s\r\n", gz);
ruevs 5:50051611b5bd 240 LOG("mx = %f", mx);
ruevs 5:50051611b5bd 241 LOG(" my = %f", my);
ruevs 5:50051611b5bd 242 LOG(" mz = %f mG\r\n", mz);
ruevs 9:310663c014d8 243 LOG("minmx = %i", minMagCount[0]);
ruevs 9:310663c014d8 244 LOG(" minmy = %i", minMagCount[1]);
ruevs 9:310663c014d8 245 LOG(" minmz = %i\r\n", minMagCount[2]);
ruevs 9:310663c014d8 246 LOG("maxmx = %i", maxMagCount[0]);
ruevs 9:310663c014d8 247 LOG(" maxmy = %i", maxMagCount[1]);
ruevs 9:310663c014d8 248 LOG(" maxmz = %i\r\n", maxMagCount[2]);
ruevs 9:310663c014d8 249 LOG("magbiasx = %f", magbias[0]);
ruevs 9:310663c014d8 250 LOG(" magbiasy = %f", magbias[1]);
ruevs 9:310663c014d8 251 LOG(" magbiasz = %f mG\r\n", magbias[2]);
ruevs 9:310663c014d8 252 LOG("magscalex = %f", magScale[0]);
ruevs 9:310663c014d8 253 LOG(" magscaley = %f", magScale[1]);
ruevs 9:310663c014d8 254 LOG(" magscalez = %f mG\r\n", magScale[2]);
ruevs 5:50051611b5bd 255
ruevs 5:50051611b5bd 256
ruevs 5:50051611b5bd 257 tempCount = mpu9250.readTempData(); // Read the adc values
ruevs 5:50051611b5bd 258 if (I2Cstate != 0) //error on I2C
ruevs 5:50051611b5bd 259 LOG("I2C error ocurred while reading sensor temp. I2Cstate = %d \r\n", I2Cstate);
ruevs 5:50051611b5bd 260 else{ // I2C read or write ok
ruevs 5:50051611b5bd 261 I2Cstate = 1;
ruevs 5:50051611b5bd 262 temperature = ((float) tempCount) / 333.87f + 21.0f; // Temperature in degrees Centigrade
ruevs 5:50051611b5bd 263 LOG(" temperature = %f C\r\n", temperature);
ruevs 5:50051611b5bd 264 }
ruevs 5:50051611b5bd 265 LOG("q0 = %f\r\n", q[0]);
ruevs 5:50051611b5bd 266 LOG("q1 = %f\r\n", q[1]);
ruevs 5:50051611b5bd 267 LOG("q2 = %f\r\n", q[2]);
ruevs 5:50051611b5bd 268 LOG("q3 = %f\r\n", q[3]);
ruevs 5:50051611b5bd 269
ruevs 5:50051611b5bd 270 LOG("Compass orientation: %f\r\n", orientation[0]);
ruevs 5:50051611b5bd 271
ruevs 5:50051611b5bd 272
ruevs 5:50051611b5bd 273
ruevs 5:50051611b5bd 274
ruevs 5:50051611b5bd 275 // Define output variables from updated quaternion---these are Tait-Bryan angles, commonly used in aircraft orientation.
ruevs 5:50051611b5bd 276 // In this coordinate system, the positive z-axis is down toward Earth.
ruevs 5:50051611b5bd 277 // Yaw is the angle between Sensor x-axis and Earth magnetic North (or true North if corrected for local declination, looking down on the sensor positive yaw is counterclockwise.
ruevs 5:50051611b5bd 278 // Pitch is angle between sensor x-axis and Earth ground plane, toward the Earth is positive, up toward the sky is negative.
ruevs 5:50051611b5bd 279 // Roll is angle between sensor y-axis and Earth ground plane, y-axis up is positive roll.
ruevs 5:50051611b5bd 280 // These arise from the definition of the homogeneous rotation matrix constructed from quaternions.
ruevs 5:50051611b5bd 281 // Tait-Bryan angles as well as Euler angles are non-commutative; that is, the get the correct orientation the rotations must be
ruevs 5:50051611b5bd 282 // applied in the correct order which for this configuration is yaw, pitch, and then roll.
ruevs 5:50051611b5bd 283 // For more see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles which has additional links.
ruevs 5:50051611b5bd 284
ruevs 5:50051611b5bd 285 yaw = atan2(2.0f * (q[1] * q[2] + q[0] * q[3]), q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3]);
ruevs 5:50051611b5bd 286 pitch = -asin(2.0f * (q[1] * q[3] - q[0] * q[2]));
ruevs 5:50051611b5bd 287 roll = atan2(2.0f * (q[0] * q[1] + q[2] * q[3]), q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3]);
ruevs 5:50051611b5bd 288 pitch *= 180.0f / PI;
ruevs 5:50051611b5bd 289 yaw *= 180.0f / PI;
ruevs 5:50051611b5bd 290 yaw -= 13.8f; // Declination at Danville, California is 13 degrees 48 minutes and 47 seconds on 2014-04-04
ruevs 5:50051611b5bd 291 roll *= 180.0f / PI;
ruevs 5:50051611b5bd 292
ruevs 5:50051611b5bd 293
ruevs 5:50051611b5bd 294 LOG("Yaw, Pitch, Roll: %f %f %f\r\n", yaw, pitch, roll);
ruevs 5:50051611b5bd 295 LOG("average rate = %f\r\n", (float) sumCount/sum);
ruevs 5:50051611b5bd 296
ruevs 5:50051611b5bd 297
ruevs 5:50051611b5bd 298
ruevs 5:50051611b5bd 299 myled= !myled;
ruevs 5:50051611b5bd 300 count = t.read_ms();
ruevs 5:50051611b5bd 301
ruevs 5:50051611b5bd 302 if(count > 1<<21) {
ruevs 5:50051611b5bd 303 t.start(); // start the timer over again if ~30 minutes has passed
ruevs 5:50051611b5bd 304 count = 0;
ruevs 5:50051611b5bd 305 deltat= 0;
ruevs 5:50051611b5bd 306 lastUpdate = t.read_us();
ruevs 5:50051611b5bd 307 }
ruevs 5:50051611b5bd 308 sum = 0;
ruevs 5:50051611b5bd 309 sumCount = 0;
ruevs 5:50051611b5bd 310
ruevs 5:50051611b5bd 311 //BMP180
ruevs 5:50051611b5bd 312 bmp180.startTemperature();
ruevs 5:50051611b5bd 313 wait_ms(5); // Wait for conversion to complete
ruevs 5:50051611b5bd 314 float temp;
ruevs 5:50051611b5bd 315 if(bmp180.getTemperature(&temp) != 0) {
ruevs 5:50051611b5bd 316 LOG("Error getting temperature\n");
ruevs 5:50051611b5bd 317 continue;
ruevs 5:50051611b5bd 318 }
ruevs 5:50051611b5bd 319
ruevs 5:50051611b5bd 320 bmp180.startPressure(BMP180::ULTRA_LOW_POWER);
ruevs 5:50051611b5bd 321 wait_ms(10); // Wait for conversion to complete
ruevs 5:50051611b5bd 322 int pressure;
ruevs 5:50051611b5bd 323 if(bmp180.getPressure(&pressure) != 0) {
ruevs 5:50051611b5bd 324 LOG("Error getting pressure\n");
ruevs 5:50051611b5bd 325 continue;
ruevs 5:50051611b5bd 326 }
ruevs 5:50051611b5bd 327
ruevs 5:50051611b5bd 328 LOG("Pressure = %d Pa Temperature = %f C\r\n", pressure, temp);
ruevs 5:50051611b5bd 329
ruevs 5:50051611b5bd 330 }
ruevs 5:50051611b5bd 331 }
ruevs 5:50051611b5bd 332 }
ruevs 5:50051611b5bd 333
seeed 0:b017c907d53d 334 int main()
seeed 0:b017c907d53d 335 {
ruevs 2:7abdbccdf0c8 336 int readings[MAX_ACC_AXIS] = {0, 0, 0};
ruevs 2:7abdbccdf0c8 337 int MAXreadings[MAX_ACC_AXIS] = {INT16_MIN, INT16_MIN, INT16_MIN};
ruevs 2:7abdbccdf0c8 338 int MINreadings[MAX_ACC_AXIS] = {INT16_MAX, INT16_MAX, INT16_MAX};
ruevs 2:7abdbccdf0c8 339
ruevs 2:7abdbccdf0c8 340 char display_buf[17];
ruevs 2:7abdbccdf0c8 341
ruevs 2:7abdbccdf0c8 342 test_int.rise(test_pin_int);
seeed 0:b017c907d53d 343
ruevs 5:50051611b5bd 344 MPU9250Test();
ruevs 5:50051611b5bd 345
seeed 0:b017c907d53d 346 LOG("Starting ADXL345 test...\n");
seeed 0:b017c907d53d 347 LOG("Device ID is: 0x%02x\n", accelerometer.getDeviceID());
ruevs 2:7abdbccdf0c8 348
ruevs 5:50051611b5bd 349 /* // Simple OLED speed test
ruevs 5:50051611b5bd 350 oled.fillDisplay(0xAA);
ruevs 5:50051611b5bd 351 oled.writeBigChar(1,0,'6');
ruevs 5:50051611b5bd 352
ruevs 5:50051611b5bd 353 uint8_t cnt=0;
ruevs 5:50051611b5bd 354 int cycl=0;
ruevs 5:50051611b5bd 355 while(1){
ruevs 5:50051611b5bd 356 snprintf(display_buf, sizeof(display_buf), "%5i", cnt++);
ruevs 5:50051611b5bd 357 oled.writeString(0, 0, display_buf);
ruevs 5:50051611b5bd 358 if (0==cnt) {
ruevs 5:50051611b5bd 359 ++cycl;
ruevs 5:50051611b5bd 360 snprintf(display_buf, sizeof(display_buf), "%5i", cycl);
ruevs 5:50051611b5bd 361 oled.writeString(1, 0, display_buf);
ruevs 5:50051611b5bd 362 }
ruevs 5:50051611b5bd 363 }
ruevs 5:50051611b5bd 364 */
ruevs 5:50051611b5bd 365 oled2.writeString(0, 0, "OLED 2:");
ruevs 5:50051611b5bd 366 oled2.writeString(1, 0, "GEEKCREIT");
ruevs 5:50051611b5bd 367 oled2.writeString(2, 0, "Banggood 0x7A");
ruevs 5:50051611b5bd 368
ruevs 2:7abdbccdf0c8 369 oled.writeString(0, 0, "Accelerometer:");
ruevs 2:7abdbccdf0c8 370 oled.writeString(1, 0, " Curr Min Max");
seeed 0:b017c907d53d 371
seeed 0:b017c907d53d 372 //Go into standby mode to configure the device.
seeed 0:b017c907d53d 373 accelerometer.setPowerControl(0x00);
seeed 0:b017c907d53d 374
seeed 0:b017c907d53d 375 //Full resolution, +/-16g, 4mg/LSB.
seeed 0:b017c907d53d 376 accelerometer.setDataFormatControl(0x0B);
seeed 0:b017c907d53d 377
seeed 0:b017c907d53d 378 //3.2kHz data rate.
seeed 0:b017c907d53d 379 accelerometer.setDataRate(ADXL345_3200HZ);
seeed 0:b017c907d53d 380
seeed 0:b017c907d53d 381 //Measurement mode.
seeed 0:b017c907d53d 382 accelerometer.setPowerControl(0x08);
seeed 0:b017c907d53d 383
seeed 0:b017c907d53d 384 while (1) {
seeed 0:b017c907d53d 385 accelerometer.getOutput(readings);
ruevs 2:7abdbccdf0c8 386
ruevs 2:7abdbccdf0c8 387 for (int i=0; i<MAX_ACC_AXIS; ++i) {
ruevs 2:7abdbccdf0c8 388 if ((int16_t)readings[i] > (int16_t)MAXreadings[i]) {
ruevs 2:7abdbccdf0c8 389 MAXreadings[i] = readings[i];
ruevs 2:7abdbccdf0c8 390 }
ruevs 2:7abdbccdf0c8 391 if ((int16_t)readings[i] < (int16_t)MINreadings[i]) {
ruevs 2:7abdbccdf0c8 392 MINreadings[i] = readings[i];
ruevs 2:7abdbccdf0c8 393 }
ruevs 2:7abdbccdf0c8 394
ruevs 2:7abdbccdf0c8 395 snprintf(display_buf, sizeof(display_buf), "%c%5i%5i%5i",
ruevs 2:7abdbccdf0c8 396 'X'+i, (int16_t)readings[i], (int16_t)MINreadings[i], (int16_t)MAXreadings[i] );
ruevs 2:7abdbccdf0c8 397 oled.writeString(2+i, 0, display_buf);
ruevs 2:7abdbccdf0c8 398 LOG("%c:%i|%i|%i\r\n", 'X'+i, (int16_t)readings[i], (int16_t)MINreadings[i], (int16_t)MAXreadings[i] );
ruevs 2:7abdbccdf0c8 399 }
ruevs 2:7abdbccdf0c8 400
ruevs 2:7abdbccdf0c8 401 /* snprintf(display_buf, sizeof(display_buf), "Ch: %u", ChargerStatus.read_u16());
ruevs 2:7abdbccdf0c8 402 oled.writeString(2+MAX_ACC_AXIS, 0, display_buf);
ruevs 2:7abdbccdf0c8 403
ruevs 2:7abdbccdf0c8 404 snprintf(display_buf, sizeof(display_buf), "Ch: %f", 3.3*(float)ChargerStatus.read_u16()/UINT16_MAX);
ruevs 2:7abdbccdf0c8 405 oled.writeString(2+MAX_ACC_AXIS+1, 0, display_buf);
ruevs 2:7abdbccdf0c8 406 */
ruevs 2:7abdbccdf0c8 407 snprintf(display_buf, sizeof(display_buf), "Bat:%.2fV", 3.3*ChargerStatus);
ruevs 2:7abdbccdf0c8 408 oled.writeString(2+MAX_ACC_AXIS+2, 0, display_buf);
ruevs 2:7abdbccdf0c8 409
ruevs 2:7abdbccdf0c8 410 LOG("Ch: %f\r\n", ChargerStatus.read());
ruevs 2:7abdbccdf0c8 411 LOG("Chu: %u\r\n", ChargerStatus.read_u16());
ruevs 2:7abdbccdf0c8 412 LOG("A0: %f\r\n", (float)AD00.read());
ruevs 2:7abdbccdf0c8 413 LOG("A1: %f\r\n", AD01.read());
ruevs 2:7abdbccdf0c8 414
ruevs 2:7abdbccdf0c8 415 blue_led = !blue_led;
ruevs 2:7abdbccdf0c8 416 // white_led = !white_led; // toggled by pin P0_7 interrupt
ruevs 2:7abdbccdf0c8 417
ruevs 2:7abdbccdf0c8 418 // deepsleep(); // Deep sleep until external interrupt // The wakeup pin on Xadow is on the sme buton at RESET - no good.
seeed 0:b017c907d53d 419
seeed 0:b017c907d53d 420 wait(1);
seeed 0:b017c907d53d 421 }
seeed 0:b017c907d53d 422
seeed 0:b017c907d53d 423 }