Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2194 - 1
/*
2
MPU6050 lib 0x02
3
 
4
copyright (c) Davide Gironi, 2012
5
 
6
Released under GPLv3.
7
Please refer to LICENSE file for licensing information.
8
*/
9
 
10
 
11
#include <stdlib.h>
12
#include <string.h>
13
#include <avr/io.h>
14
#include <avr/pgmspace.h>
15
#include <avr/interrupt.h>
16
#include <util/delay.h>
17
 
18
#include "mpu6050.h"
19
 
20
#if MPU6050_GETATTITUDE == 1 || MPU6050_GETATTITUDE == 2
21
#include <math.h>  //include libm
22
#endif
23
 
24
//path to i2c fleury lib
25
#include "i2cmaster.h"
26
 
27
volatile uint8_t buffer[14];
28
 
29
/*
30
 * read bytes from chip register
31
 */
32
int8_t mpu6050_readBytes(uint8_t regAddr, uint8_t length, uint8_t *data) {
33
        uint8_t i = 0;
34
        int8_t count = 0;
35
        if(length > 0) {
36
                //request register
37
                i2c_start(MPU6050_ADDR | I2C_WRITE);
38
                i2c_write(regAddr);
39
                _delay_us(10);
40
                //read data
41
                i2c_start(MPU6050_ADDR | I2C_READ);
42
                for(i=0; i<length; i++) {
43
                        count++;
44
                        if(i==length-1)
45
                                data[i] = i2c_readNak();
46
                        else
47
                                data[i] = i2c_readAck();
48
                }
49
                i2c_stop();
50
        }
51
        return count;
52
}
53
 
54
/*
55
 * read 1 byte from chip register
56
 */
57
int8_t mpu6050_readByte(uint8_t regAddr, uint8_t *data) {
58
    return mpu6050_readBytes(regAddr, 1, data);
59
}
60
 
61
/*
62
 * write bytes to chip register
63
 */
64
void mpu6050_writeBytes(uint8_t regAddr, uint8_t length, uint8_t* data) {
65
        if(length > 0) {
66
                //write data
67
                i2c_start(MPU6050_ADDR | I2C_WRITE);
68
                i2c_write(regAddr); //reg
69
                for (uint8_t i = 0; i < length; i++) {
70
                        i2c_write((uint8_t) data[i]);
71
                }
72
                i2c_stop();
73
        }
74
}
75
 
76
/*
77
 * write 1 byte to chip register
78
 */
79
void mpu6050_writeByte(uint8_t regAddr, uint8_t data) {
80
    return mpu6050_writeBytes(regAddr, 1, &data);
81
}
82
 
83
/*
84
 * read bits from chip register
85
 */
86
int8_t mpu6050_readBits(uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data) {
87
    // 01101001 read byte
88
    // 76543210 bit numbers
89
    //    xxx   args: bitStart=4, length=3
90
    //    010   masked
91
    //   -> 010 shifted
92
    int8_t count = 0;
93
    if(length > 0) {
94
                uint8_t b;
95
                if ((count = mpu6050_readByte(regAddr, &b)) != 0) {
96
                        uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
97
                        b &= mask;
98
                        b >>= (bitStart - length + 1);
99
                        *data = b;
100
                }
101
    }
102
    return count;
103
}
104
 
105
/*
106
 * read 1 bit from chip register
107
 */
108
int8_t mpu6050_readBit(uint8_t regAddr, uint8_t bitNum, uint8_t *data) {
109
    uint8_t b;
110
    uint8_t count = mpu6050_readByte(regAddr, &b);
111
    *data = b & (1 << bitNum);
112
    return count;
113
}
114
 
115
/*
116
 * write bit/bits to chip register
117
 */
118
void mpu6050_writeBits(uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) {
119
    //      010 value to write
120
    // 76543210 bit numbers
121
    //    xxx   args: bitStart=4, length=3
122
    // 00011100 mask byte
123
    // 10101111 original value (sample)
124
    // 10100011 original & ~mask
125
    // 10101011 masked | value
126
        if(length > 0) {
127
                uint8_t b = 0;
128
                if (mpu6050_readByte(regAddr, &b) != 0) { //get current data
129
                        uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
130
                        data <<= (bitStart - length + 1); // shift data into correct position
131
                        data &= mask; // zero all non-important bits in data
132
                        b &= ~(mask); // zero all important bits in existing byte
133
                        b |= data; // combine data with existing byte
134
                        mpu6050_writeByte(regAddr, b);
135
                }
136
        }
137
}
138
 
139
/*
140
 * write one bit to chip register
141
 */
142
void mpu6050_writeBit(uint8_t regAddr, uint8_t bitNum, uint8_t data) {
143
    uint8_t b;
144
    mpu6050_readByte(regAddr, &b);
145
    b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
146
    mpu6050_writeByte(regAddr, b);
147
}
148
 
149
#if MPU6050_GETATTITUDE == 2
150
/*
151
 * write word/words to chip register
152
 */
153
void mpu6050_writeWords(uint8_t regAddr, uint8_t length, uint16_t* data) {
154
        if(length > 0) {
155
                uint8_t i = 0;
156
                //write data
157
                i2c_start(MPU6050_ADDR | I2C_WRITE);
158
                i2c_write(regAddr); //reg
159
                for (i = 0; i < length * 2; i++) {
160
                        i2c_write((uint8_t)(data[i++] >> 8)); // send MSB
161
                        i2c_write((uint8_t)data[i]);          // send LSB
162
                }
163
                i2c_stop();
164
        }
165
}
166
 
167
/*
168
 * set a chip memory bank
169
 */
170
void mpu6050_setMemoryBank(uint8_t bank, uint8_t prefetchEnabled, uint8_t userBank) {
171
    bank &= 0x1F;
172
    if (userBank) bank |= 0x20;
173
    if (prefetchEnabled) bank |= 0x40;
174
    mpu6050_writeByte(MPU6050_RA_BANK_SEL, bank);
175
}
176
 
177
/*
178
 * set memory start address
179
 */
180
void mpu6050_setMemoryStartAddress(uint8_t address) {
181
        mpu6050_writeByte(MPU6050_RA_MEM_START_ADDR, address);
182
}
183
 
184
/*
185
 * read a memory block
186
 */
187
void mpu6050_readMemoryBlock(uint8_t *data, uint16_t dataSize, uint8_t bank, uint8_t address) {
188
        mpu6050_setMemoryBank(bank, 0, 0);
189
        mpu6050_setMemoryStartAddress(address);
190
    uint8_t chunkSize;
191
    for (uint16_t i = 0; i < dataSize;) {
192
        // determine correct chunk size according to bank position and data size
193
        chunkSize = MPU6050_DMP_MEMORY_CHUNK_SIZE;
194
 
195
        // make sure we don't go past the data size
196
        if (i + chunkSize > dataSize) chunkSize = dataSize - i;
197
 
198
        // make sure this chunk doesn't go past the bank boundary (256 bytes)
199
        if (chunkSize > 256 - address) chunkSize = 256 - address;
200
 
201
        // read the chunk of data as specified
202
        mpu6050_readBytes(MPU6050_RA_MEM_R_W, chunkSize, data + i);
203
 
204
        // increase byte index by [chunkSize]
205
        i += chunkSize;
206
 
207
        // uint8_t automatically wraps to 0 at 256
208
        address += chunkSize;
209
 
210
        // if we aren't done, update bank (if necessary) and address
211
        if (i < dataSize) {
212
            if (address == 0) bank++;
213
            mpu6050_setMemoryBank(bank, 0, 0);
214
            mpu6050_setMemoryStartAddress(address);
215
        }
216
    }
217
}
218
 
219
/*
220
 * write a memory block
221
 */
222
uint8_t mpu6050_writeMemoryBlock(const uint8_t *data, uint16_t dataSize, uint8_t bank, uint8_t address, uint8_t verify, uint8_t useProgMem) {
223
        mpu6050_setMemoryBank(bank, 0, 0);
224
        mpu6050_setMemoryStartAddress(address);
225
    uint8_t chunkSize;
226
    uint8_t *verifyBuffer = 0;
227
    uint8_t *progBuffer = 0;
228
    uint16_t i;
229
    uint8_t j;
230
    if (verify) verifyBuffer = (uint8_t *)malloc(MPU6050_DMP_MEMORY_CHUNK_SIZE);
231
    if (useProgMem) progBuffer = (uint8_t *)malloc(MPU6050_DMP_MEMORY_CHUNK_SIZE);
232
    for (i = 0; i < dataSize;) {
233
        // determine correct chunk size according to bank position and data size
234
        chunkSize = MPU6050_DMP_MEMORY_CHUNK_SIZE;
235
 
236
        // make sure we don't go past the data size
237
        if (i + chunkSize > dataSize) chunkSize = dataSize - i;
238
 
239
        // make sure this chunk doesn't go past the bank boundary (256 bytes)
240
        if (chunkSize > 256 - address) chunkSize = 256 - address;
241
 
242
        if (useProgMem) {
243
            // write the chunk of data as specified
244
            for (j = 0; j < chunkSize; j++) progBuffer[j] = pgm_read_byte(data + i + j);
245
        } else {
246
            // write the chunk of data as specified
247
            progBuffer = (uint8_t *)data + i;
248
        }
249
 
250
        mpu6050_writeBytes(MPU6050_RA_MEM_R_W, chunkSize, progBuffer);
251
 
252
        // verify data if needed
253
        if (verify && verifyBuffer) {
254
                mpu6050_setMemoryBank(bank, 0, 0);
255
            mpu6050_setMemoryStartAddress(address);
256
            mpu6050_readBytes(MPU6050_RA_MEM_R_W, chunkSize, verifyBuffer);
257
            if (memcmp(progBuffer, verifyBuffer, chunkSize) != 0) {
258
                free(verifyBuffer);
259
                if (useProgMem) free(progBuffer);
260
                return 0; // uh oh.
261
            }
262
        }
263
 
264
        // increase byte index by [chunkSize]
265
        i += chunkSize;
266
 
267
        // uint8_t automatically wraps to 0 at 256
268
        address += chunkSize;
269
 
270
        // if we aren't done, update bank (if necessary) and address
271
        if (i < dataSize) {
272
            if (address == 0) bank++;
273
            mpu6050_setMemoryBank(bank, 0, 0);
274
            mpu6050_setMemoryStartAddress(address);
275
        }
276
    }
277
    if (verify) free(verifyBuffer);
278
    if (useProgMem) free(progBuffer);
279
    return 1;
280
}
281
 
282
/*
283
 * write a dmp configuration set
284
 */
285
uint8_t mpu6050_writeDMPConfigurationSet(const uint8_t *data, uint16_t dataSize, uint8_t useProgMem) {
286
    uint8_t *progBuffer = 0;
287
    uint8_t success, special;
288
    uint16_t i, j;
289
    if (useProgMem) {
290
        progBuffer = (uint8_t *)malloc(8); // assume 8-byte blocks, realloc later if necessary
291
    }
292
 
293
    // config set data is a long string of blocks with the following structure:
294
    // [bank] [offset] [length] [byte[0], byte[1], ..., byte[length]]
295
    uint8_t bank, offset, length;
296
    for (i = 0; i < dataSize;) {
297
        if (useProgMem) {
298
            bank = pgm_read_byte(data + i++);
299
            offset = pgm_read_byte(data + i++);
300
            length = pgm_read_byte(data + i++);
301
        } else {
302
            bank = data[i++];
303
            offset = data[i++];
304
            length = data[i++];
305
        }
306
 
307
        // write data or perform special action
308
        if (length > 0) {
309
            // regular block of data to write
310
            if (useProgMem) {
311
                if (sizeof(progBuffer) < length) progBuffer = (uint8_t *)realloc(progBuffer, length);
312
                for (j = 0; j < length; j++) progBuffer[j] = pgm_read_byte(data + i + j);
313
            } else {
314
                progBuffer = (uint8_t *)data + i;
315
            }
316
            success = mpu6050_writeMemoryBlock(progBuffer, length, bank, offset, 1, 0);
317
            i += length;
318
        } else {
319
            // special instruction
320
            // NOTE: this kind of behavior (what and when to do certain things)
321
            // is totally undocumented. This code is in here based on observed
322
            // behavior only, and exactly why (or even whether) it has to be here
323
            // is anybody's guess for now.
324
            if (useProgMem) {
325
                special = pgm_read_byte(data + i++);
326
            } else {
327
                special = data[i++];
328
            }
329
            if (special == 0x01) {
330
                // enable DMP-related interrupts
331
 
332
                //mpu6050_writeBit(MPU6050_RA_INT_ENABLE, MPU6050_INTERRUPT_ZMOT_BIT, 1); //setIntZeroMotionEnabled
333
                //mpu6050_writeBit(MPU6050_RA_INT_ENABLE, MPU6050_INTERRUPT_FIFO_OFLOW_BIT, 1); //setIntFIFOBufferOverflowEnabled
334
                //mpu6050_writeBit(MPU6050_RA_INT_ENABLE, MPU6050_INTERRUPT_DMP_INT_BIT, 1); //setIntDMPEnabled
335
                mpu6050_writeByte(MPU6050_RA_INT_ENABLE, 0x32);  // single operation
336
 
337
                success = 1;
338
            } else {
339
                // unknown special command
340
                success = 0;
341
            }
342
        }
343
 
344
        if (!success) {
345
            if (useProgMem) free(progBuffer);
346
            return 0; // uh oh
347
        }
348
    }
349
    if (useProgMem) free(progBuffer);
350
    return 1;
351
}
352
 
353
/*
354
 * get the fifo count
355
 */
356
uint16_t mpu6050_getFIFOCount(void) {
357
        mpu6050_readBytes(MPU6050_RA_FIFO_COUNTH, 2, (uint8_t *)buffer);
358
    return (((uint16_t)buffer[0]) << 8) | buffer[1];
359
}
360
 
361
/*
362
 * read fifo bytes
363
 */
364
void mpu6050_getFIFOBytes(uint8_t *data, uint8_t length) {
365
        mpu6050_readBytes(MPU6050_RA_FIFO_R_W, length, data);
366
}
367
 
368
/*
369
 * get the interrupt status
370
 */
371
uint8_t mpu6050_getIntStatus(void) {
372
        mpu6050_readByte(MPU6050_RA_INT_STATUS, (uint8_t *)buffer);
373
    return buffer[0];
374
}
375
 
376
/*
377
 * reset fifo
378
 */
379
void mpu6050_resetFIFO(void) {
380
        mpu6050_writeBit(MPU6050_RA_USER_CTRL, MPU6050_USERCTRL_FIFO_RESET_BIT, 1);
381
}
382
 
383
/*
384
 * get gyro offset X
385
 */
386
int8_t mpu6050_getXGyroOffset(void) {
387
        mpu6050_readBits(MPU6050_RA_XG_OFFS_TC, MPU6050_TC_OFFSET_BIT, MPU6050_TC_OFFSET_LENGTH, (uint8_t *)buffer);
388
    return buffer[0];
389
}
390
 
391
/*
392
 * set gyro offset X
393
 */
394
void mpu6050_setXGyroOffset(int8_t offset) {
395
        mpu6050_writeBits(MPU6050_RA_XG_OFFS_TC, MPU6050_TC_OFFSET_BIT, MPU6050_TC_OFFSET_LENGTH, offset);
396
}
397
 
398
/*
399
 * get gyro offset Y
400
 */
401
int8_t mpu6050_getYGyroOffset(void) {
402
        mpu6050_readBits(MPU6050_RA_YG_OFFS_TC, MPU6050_TC_OFFSET_BIT, MPU6050_TC_OFFSET_LENGTH, (uint8_t *)buffer);
403
    return buffer[0];
404
}
405
 
406
/*
407
 * set gyro offset Y
408
 */
409
void mpu6050_setYGyroOffset(int8_t offset) {
410
        mpu6050_writeBits(MPU6050_RA_YG_OFFS_TC, MPU6050_TC_OFFSET_BIT, MPU6050_TC_OFFSET_LENGTH, offset);
411
}
412
 
413
/*
414
 * get gyro offset Z
415
 */
416
int8_t mpu6050_getZGyroOffset(void) {
417
        mpu6050_readBits(MPU6050_RA_ZG_OFFS_TC, MPU6050_TC_OFFSET_BIT, MPU6050_TC_OFFSET_LENGTH, (uint8_t *)buffer);
418
    return buffer[0];
419
}
420
 
421
/*
422
 * set gyro offset Z
423
 */
424
void mpu6050_setZGyroOffset(int8_t offset) {
425
        mpu6050_writeBits(MPU6050_RA_ZG_OFFS_TC, MPU6050_TC_OFFSET_BIT, MPU6050_TC_OFFSET_LENGTH, offset);
426
}
427
#endif
428
 
429
/*
430
 * set sleep disabled
431
 */
432
void mpu6050_setSleepDisabled() {
433
        mpu6050_writeBit(MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, 0);
434
}
435
 
436
/*
437
 * set sleep enabled
438
 */
439
void mpu6050_setSleepEnabled(void) {
440
        mpu6050_writeBit(MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, 1);
441
}
442
 
443
 
444
/*
445
 * test connectino to chip
446
 */
447
uint8_t mpu6050_testConnection(void) {
448
        mpu6050_readBits(MPU6050_RA_WHO_AM_I, MPU6050_WHO_AM_I_BIT, MPU6050_WHO_AM_I_LENGTH, (uint8_t *)buffer);
449
        if(buffer[0] == 0x34)
450
                return 1;
451
        else
452
                return 0;
453
}
454
 
455
/*
456
 * initialize the accel and gyro
457
 */
458
void mpu6050_init(void) {
459
        //allow mpu6050 chip clocks to start up
460
        _delay_ms(100);
461
 
462
        //set sleep disabled
463
        mpu6050_setSleepDisabled();
464
        //wake up delay needed sleep disabled
465
        _delay_ms(10);
466
 
467
        //set clock source
468
        //  it is highly recommended that the device be configured to use one of the gyroscopes (or an external clock source)
469
        //  as the clock reference for improved stability
470
        mpu6050_writeBits(MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_CLKSEL_BIT, MPU6050_PWR1_CLKSEL_LENGTH, MPU6050_CLOCK_PLL_XGYRO);
471
        //set DLPF bandwidth to 42Hz
472
        mpu6050_writeBits(MPU6050_RA_CONFIG, MPU6050_CFG_DLPF_CFG_BIT, MPU6050_CFG_DLPF_CFG_LENGTH, MPU6050_DLPF_BW_42);
473
    //set sampe rate
474
        mpu6050_writeByte(MPU6050_RA_SMPLRT_DIV, 4); //1khz / (1 + 4) = 200Hz
475
        //set gyro range
476
        mpu6050_writeBits(MPU6050_RA_GYRO_CONFIG, MPU6050_GCONFIG_FS_SEL_BIT, MPU6050_GCONFIG_FS_SEL_LENGTH, MPU6050_GYRO_FS);
477
        //set accel range
478
        mpu6050_writeBits(MPU6050_RA_ACCEL_CONFIG, MPU6050_ACONFIG_AFS_SEL_BIT, MPU6050_ACONFIG_AFS_SEL_LENGTH, MPU6050_ACCEL_FS);
479
 
480
        #if MPU6050_GETATTITUDE == 1
481
        #error "Do not enable timer 0 it is in use elsewhere!"
482
        //MPU6050_TIMER0INIT
483
        #endif
484
}
485
 
486
//can not accept many request if we alreay have getattitude requests
487
/*
488
 * get raw data
489
 */
490
void mpu6050_getRawData(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz) {
491
        mpu6050_readBytes(MPU6050_RA_ACCEL_XOUT_H, 14, (uint8_t *)buffer);
492
 
493
    *ax = (((int16_t)buffer[0]) << 8) | buffer[1];
494
    *ay = (((int16_t)buffer[2]) << 8) | buffer[3];
495
    *az = (((int16_t)buffer[4]) << 8) | buffer[5];
496
    *gx = (((int16_t)buffer[8]) << 8) | buffer[9];
497
    *gy = (((int16_t)buffer[10]) << 8) | buffer[11];
498
    *gz = (((int16_t)buffer[12]) << 8) | buffer[13];
499
}
500
 
501
/*
502
 * get raw data converted to g and deg/sec values
503
 */
504
void mpu6050_getConvData(double* axg, double* ayg, double* azg, double* gxds, double* gyds, double* gzds) {
505
        int16_t ax = 0;
506
        int16_t ay = 0;
507
        int16_t az = 0;
508
        int16_t gx = 0;
509
        int16_t gy = 0;
510
        int16_t gz = 0;
511
        mpu6050_getRawData(&ax, &ay, &az, &gx, &gy, &gz);
512
 
513
        #if MPU6050_CALIBRATEDACCGYRO == 1
514
    *axg = (double)(ax-MPU6050_AXOFFSET)/MPU6050_AXGAIN;
515
    *ayg = (double)(ay-MPU6050_AYOFFSET)/MPU6050_AYGAIN;
516
    *azg = (double)(az-MPU6050_AZOFFSET)/MPU6050_AZGAIN;
517
    *gxds = (double)(gx-MPU6050_GXOFFSET)/MPU6050_GXGAIN;
518
        *gyds = (double)(gy-MPU6050_GYOFFSET)/MPU6050_GYGAIN;
519
        *gzds = (double)(gz-MPU6050_GZOFFSET)/MPU6050_GZGAIN;
520
        #else
521
    *axg = (double)(ax)/MPU6050_AGAIN;
522
    *ayg = (double)(ay)/MPU6050_AGAIN;
523
    *azg = (double)(az)/MPU6050_AGAIN;
524
    *gxds = (double)(gx)/MPU6050_GGAIN;
525
        *gyds = (double)(gy)/MPU6050_GGAIN;
526
        *gzds = (double)(gz)/MPU6050_GGAIN;
527
        #endif
528
}
529
 
530
#if MPU6050_GETATTITUDE == 1
531
 
532
volatile float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;
533
volatile float integralFBx = 0.0f,  integralFBy = 0.0f, integralFBz = 0.0f;
534
/*
535
 * Mahony update function (for 6DOF)
536
 */
537
void mpu6050_mahonyUpdate(float gx, float gy, float gz, float ax, float ay, float az) {
538
        float norm;
539
        float halfvx, halfvy, halfvz;
540
        float halfex, halfey, halfez;
541
        float qa, qb, qc;
542
 
543
        // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
544
        if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
545
 
546
                // Normalise accelerometer measurement
547
                norm = sqrt(ax * ax + ay * ay + az * az);
548
                ax /= norm;
549
                ay /= norm;
550
                az /= norm;
551
 
552
                // Estimated direction of gravity and vector perpendicular to magnetic flux
553
                halfvx = q1 * q3 - q0 * q2;
554
                halfvy = q0 * q1 + q2 * q3;
555
                halfvz = q0 * q0 - 0.5f + q3 * q3;
556
 
557
                // Error is sum of cross product between estimated and measured direction of gravity
558
                halfex = (ay * halfvz - az * halfvy);
559
                halfey = (az * halfvx - ax * halfvz);
560
                halfez = (ax * halfvy - ay * halfvx);
561
 
562
                // Compute and apply integral feedback if enabled
563
                if(mpu6050_mahonytwoKiDef > 0.0f) {
564
                        integralFBx += mpu6050_mahonytwoKiDef * halfex * (1.0f / mpu6050_mahonysampleFreq);     // integral error scaled by Ki
565
                        integralFBy += mpu6050_mahonytwoKiDef * halfey * (1.0f / mpu6050_mahonysampleFreq);
566
                        integralFBz += mpu6050_mahonytwoKiDef * halfez * (1.0f / mpu6050_mahonysampleFreq);
567
                        gx += integralFBx;      // apply integral feedback
568
                        gy += integralFBy;
569
                        gz += integralFBz;
570
                } else {
571
                        integralFBx = 0.0f;     // prevent integral windup
572
                        integralFBy = 0.0f;
573
                        integralFBz = 0.0f;
574
                }
575
 
576
                // Apply proportional feedback
577
                gx += mpu6050_mahonytwoKpDef * halfex;
578
                gy += mpu6050_mahonytwoKpDef * halfey;
579
                gz += mpu6050_mahonytwoKpDef * halfez;
580
        }
581
 
582
        // Integrate rate of change of quaternion
583
        gx *= (0.5f * (1.0f / mpu6050_mahonysampleFreq));               // pre-multiply common factors
584
        gy *= (0.5f * (1.0f / mpu6050_mahonysampleFreq));
585
        gz *= (0.5f * (1.0f / mpu6050_mahonysampleFreq));
586
        qa = q0;
587
        qb = q1;
588
        qc = q2;
589
        q0 += (-qb * gx - qc * gy - q3 * gz);
590
        q1 += (qa * gx + qc * gz - q3 * gy);
591
        q2 += (qa * gy - qb * gz + q3 * gx);
592
        q3 += (qa * gz + qb * gy - qc * gx);
593
 
594
        // Normalise quaternion
595
        norm = sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
596
        q0 /= norm;
597
        q1 /= norm;
598
        q2 /= norm;
599
        q3 /= norm;
600
}
601
 
602
/*
603
 * update quaternion
604
 */
605
void mpu6050_updateQuaternion(void) {
606
        int16_t ax = 0;
607
        int16_t ay = 0;
608
        int16_t az = 0;
609
        int16_t gx = 0;
610
        int16_t gy = 0;
611
        int16_t gz = 0;
612
        double axg = 0;
613
        double ayg = 0;
614
        double azg = 0;
615
        double gxrs = 0;
616
        double gyrs = 0;
617
        double gzrs = 0;
618
 
619
        //get raw data
620
        while(1) {
621
                mpu6050_readBit(MPU6050_RA_INT_STATUS, MPU6050_INTERRUPT_DATA_RDY_BIT, (uint8_t *)buffer);
622
                if(buffer[0])
623
                        break;
624
                _delay_us(10);
625
        }
626
 
627
        mpu6050_readBytes(MPU6050_RA_ACCEL_XOUT_H, 14, (uint8_t *)buffer);
628
    ax = (((int16_t)buffer[0]) << 8) | buffer[1];
629
    ay = (((int16_t)buffer[2]) << 8) | buffer[3];
630
    az = (((int16_t)buffer[4]) << 8) | buffer[5];
631
    gx = (((int16_t)buffer[8]) << 8) | buffer[9];
632
    gy = (((int16_t)buffer[10]) << 8) | buffer[11];
633
    gz = (((int16_t)buffer[12]) << 8) | buffer[13];
634
 
635
        #if MPU6050_CALIBRATEDACCGYRO == 1
636
        axg = (double)(ax-MPU6050_AXOFFSET)/MPU6050_AXGAIN;
637
        ayg = (double)(ay-MPU6050_AYOFFSET)/MPU6050_AYGAIN;
638
        azg = (double)(az-MPU6050_AZOFFSET)/MPU6050_AZGAIN;
639
        gxrs = (double)(gx-MPU6050_GXOFFSET)/MPU6050_GXGAIN*0.01745329; //degree to radians
640
        gyrs = (double)(gy-MPU6050_GYOFFSET)/MPU6050_GYGAIN*0.01745329; //degree to radians
641
        gzrs = (double)(gz-MPU6050_GZOFFSET)/MPU6050_GZGAIN*0.01745329; //degree to radians
642
        #else
643
        axg = (double)(ax)/MPU6050_AGAIN;
644
        ayg = (double)(ay)/MPU6050_AGAIN;
645
        azg = (double)(az)/MPU6050_AGAIN;
646
        gxrs = (double)(gx)/MPU6050_GGAIN*0.01745329; //degree to radians
647
        gyrs = (double)(gy)/MPU6050_GGAIN*0.01745329; //degree to radians
648
        gzrs = (double)(gz)/MPU6050_GGAIN*0.01745329; //degree to radians
649
        #endif
650
 
651
    //compute data
652
    mpu6050_mahonyUpdate(gxrs, gyrs, gzrs, axg, ayg, azg);
653
}
654
 
655
/*
656
 * update timer for attitude
657
 */
658
ISR(TIMER0_OVF_vect) {
659
        mpu6050_updateQuaternion();
660
}
661
 
662
/*
663
 * get quaternion
664
 */
665
void mpu6050_getQuaternion(double *qw, double *qx, double *qy, double *qz) {
666
        *qw = q0;
667
        *qx = q1;
668
        *qy = q2;
669
        *qz = q3;
670
}
671
 
672
/*
673
 * get euler angles
674
 * aerospace sequence, to obtain sensor attitude:
675
 * 1. rotate around sensor Z plane by yaw
676
 * 2. rotate around sensor Y plane by pitch
677
 * 3. rotate around sensor X plane by roll
678
 */
679
void mpu6050_getRollPitchYaw(double *roll, double *pitch, double *yaw) {
680
        *yaw = atan2(2*q1*q2 - 2*q0*q3, 2*q0*q0 + 2*q1*q1 - 1);
681
        *pitch = -asin(2*q1*q3 + 2*q0*q2);
682
        *roll = atan2(2*q2*q3 - 2*q0*q1, 2*q0*q0 + 2*q3*q3 - 1);
683
}
684
 
685
#endif
686