Monday, February 4, 2013

AVR Atmega MPU6050 gyroscope and accelerometer lib + processing

Updated to version 03

The MPU-6050 has an embedded 3-axis MEMS gyroscope, a 3-axis MEMS accelerometer, and a Digital Motion Processor (DMP) hardware accelerator engine with an auxiliary I2C port that interfaces to 3rd party digital sensors such as magnetometers.



In this libray, two attitude extimation mode are implemented, based on gyro + accelerometer
  • internal DMP processor
  • mahony filter


Gyro calibration is suggested to get more accurate parameters.
Setup parameters are stored in file mpu6050.h

A processing.org sketch is provided to display attitude estimation.


This library is developed on Eclipse, built with avr-gcc on Atmega168 @ 16MHz.

In addition to the processing sketch, Omid Abolghasemi provides this Matlab code to visualize quaternion data:
http://www.mathworks.com/matlabcentral/fileexchange/45302-serialport-quaternion-data-visualize


Changelog
  • 03: init fix to prevent random incorrect +/- 16g scaling register setup at startup (fix by Len Spyker )
  • 02: attitude estimation refactored to fit standards
  • 01: first release


Code


Notes
  • read risk disclaimer
  • excuse my bad english

334 comments:

  1. Hi, first of all I think you did a great job with this code, it is very simple to use and modify. few notes that might be helpful:
    1. I think theres is a typo in mpu6050.h:
    volatile float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 1.0f;
    the last variable should be: q3 = 0.0f;
    2. I think the conversion from quaternion to euler angles does not perform as one might wish. I changed it to wikipedia's formula:
    // from wikipedia http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
    *roll = atan2(2*q0*q1 + 2*q2*q3, 1-2*q1*q1 - 2*q2*q2);
    *pitch = asin(2*q0*q2 - 2*q3*q1);
    *yaw = atan2(2*q0*q3 + 2*q1*q2, 1 - 2*q2*q2 - 2*q3*q3);

    now the pitch and roll angle does not change when yawing the mpu.

    3. I changes the interrput to be TIMER0_COMPA_vect so that it can be set to
    various frequencies.

    cheers

    ReplyDelete
  2. hello, thank you for your comment, it gives me the chance to correct my code.

    the quaternion to euler correction i've used is correct, is for aerospace sequance, but unlucky i've inverted roll and yaw, and made the typo error.
    above the complete exaplanation (it is commented cause it will be part of the processing display code)
    i will post new code next days, when i will have time to check in deep the theory.


    ----
    //ref:
    // 1 - [J. B. Kuipers] Quaternions and Rotation Sequences: A Primer with Applications to Orbits, Aerospace and Virtual Reality
    // 2 - [Sebastian O.H. Madgwick] An e cient orientation filter for inertial and inertial/magnetic sensor arrays
    // 3 - [Jay A. Farrell] Aided Navigation GPS with High Rate Sensors

    //pre notes: for this purpose i do not use math notation, sorry :)

    //reference frames:
    // * 0e,Xe,Ye,Ze = inertial frame - Earth Centered Inertial (ECI)
    // * 0s,Xs,Ys,Zs = sensor frame - the sensor board frame
    // * 0d,Xd,Yd,Zd = display frame - the display system reference frame ("processing")
    //notation: is O=center X,Y,Z=axis

    //sensor frame return values according to the intertial frame
    //i.e. accel/gyro/magn return values according to physic properties of the intertial frame (earth)
    //an alghotim process those values to return a quaternion that defines the sensor attitude respet to intertial frame
    // Sq = [q0, q1, q2, q3]
    //sensor quaternion can be translated to aerospace sequence of yaw/pitch/roll angles
    // yaw = atan2(2*q1*q2 - 2*q0*q3, 2*(q0^2) + 2*(q1^2) - 1)
    // pitch = -asin(2*q1*q3 + 2*q0*q2)
    // roll = atan2(2*q2*q3 - 2*q0*q1, 2*(q0^2) + 2*(q3^2) - 1)
    //using the aerospace sequence the sensor attitude can be obtain applying those rotations (in order)
    //1. rotate sensor by yaw angle around sensor Z axis
    // yaw -> Zs
    //2. rotate sensor by pitch angle around sensor Y axis
    // pitch -> Ys
    //3. rotate sensor by roll angle around sensor X axis
    // roll -> Xs
    //defined as:
    // Rse = yaw -> Zs + pitch -> Ys + roll -> Xs

    //to print a 3d object on a display, we should know the display frame
    //in case of "processing" axis are transformed to fit a better 3d view
    // * Ze = Yd = inertial frame Z is Y "processing" axis (rotateY)
    // * Ye = Xd = inertial frame Y is X "processing" axis (rotateX)
    // * Xe = Zd = inertial frame X is Z "processing" axis (rotateZ)

    //to get the Euler angles to go from the rotated sensor frame to the inertial frame just negate the angles and reverse the order
    //so, the rotation sequence
    // Rse = yaw -> Zs + pitch -> Ys + roll -> Xs
    //can be converted to
    // Res = -roll -> Xe + -pitch -> Ye + -yaw -> Ze

    //resulting rotation is:
    // Rds = -roll -> Zd + -pitch -> Xd + -yaw -> Yd
    //"processing" code is:
    //1. rotateZ(-roll);
    //2. rotateX(-pitch);
    //3. rotateY(-yaw);

    ReplyDelete
  3. Hi Davide Gironi,
    Can you build for me hex file to atmega32 please !!! I'm just want test function MPU6050 but i'm dont have Atmega168

    ReplyDelete
    Replies
    1. atmega32 has different timer registers than 168, it should be a little modification of code, but you should do it by yourself. you could use eclipse + avr module + avrgcc to compile this project without issues.
      regards,
      davide

      Delete
  4. @@ but i'm using codevisionAVR, i dont know use GCC

    ReplyDelete
    Replies
    1. i've never use codevisionAVR, but if it is c for atmega, i suppose it should be similar to avrgcc. my code is written in c, not c++, so it should compile in codevisionAVR too.
      you also could get an atmega168 (or atmega328), those are the atmega you find in most of the cheap arduino board.

      Delete
  5. Thank DG.
    My place, to buy electronic components very difficult. MPU6050 and atmega32 is my professor give for me.

    ReplyDelete
    Replies
    1. i've buy some from ebay, and some from taobao. anyway, try avrgcc, there should be just a few change to make it works with atmega32. good work! davide

      Delete
    2. I'm create makefile for mega168 but GCC report error ?
      http://i243.photobucket.com/albums/ff247/kinglord1608/untitled-2_zps5c597eb7.png

      Delete
    3. you need to include (compile) all the library provided.
      a simple method is just use eclipse + avr, just create an avr project, and compile it.

      Delete
    4. Can you share files GCC you build success please !!!

      Delete
    5. Hi Davide Gironi!
      Can you tell me know that what software you used to do interface on the computer for your code.

      Delete
  6. hello DG, i from indonesian :)
    thanks for your information...
    I am very interested to learn programming MPU6050. I will make a rocket payload, it contains will be included MPU6050 for distance measurement. whether the animation of MPU6050 can be created in Visual Basic 6.0 or VB.NET?

    ReplyDelete
    Replies
    1. of course it can be. you could use OpenGL directly or use a framework to dram 3d object.

      Delete
    2. thanks Davide, i will try it :)
      thank you for your help, one day I will come back to ask for help if I run into trouble.

      Delete
  7. Hi. I really like your code and would really like to use it however whenever I compile the sketch avr_sample_mpu6050_01 i get a hefty list of errors. I'm not sure if it is because I am missing a library or something or does it not work on Arduino Uno? I don't know I am hoping that it's an easy fix, but maybe you'd know better.

    ReplyDelete
    Replies
    1. hello,
      i've delete the list of error, it is not needed.
      my code is not for Arduino, it is for avrgcc.
      To run on Arduino you should port it, it should be simple because arduino is avrgcc based, and my code also.
      Or you could compile it with avrgcc and load to the Atmega328 of your arduino.
      Or (most simple), i suggest you to give i2cdevlib a try. It works on arduino and contains the mpu6050 implementation from which i've based some of my code.

      Delete
  8. I am getting weird results when plotting the roll, pitch, and yaw over time. I calibrated my gyroscope. I have my sensor stationary and I am collecting data. I am seeing that the roll increases over time while the pitch decreases over time. The yaw, however, remains at about 0. Any ideas why?

    ReplyDelete
  9. Actually, scratch my last comment. Pitch decreases quite a bit then stabilizes. Roll increases a very small amount then stabilizes. Yaw drifts, which is what I expected. What's the reason for the pitch decreasing so much initially? Or is this not expected behavior?

    ReplyDelete
    Replies
    1. It could be the starting position of your device, because there is not magnetometer here, for the visual rapresentation to works week, device must be started always at the same "predefined" position. For further explanation about the visual rapresentation of the device, read comments in the processing file.

      Delete
  10. Hi Davide Gironi !!! I have a problem with MPU6050. MCU(Atmega16) in +5V and MPU6050 board in +3.3V. When two board communicate with each other problems have occurred and have communicate ??? I look forward to his answer. Thank you !!!

    ReplyDelete
    Replies
    1. check communication channel with a logic analyzer ;)

      Delete
  11. I use board MPU6050:

    http://dx.com/p/gy-521-6dof-mpu6050-module-3-axis-gyroscope-accelerometer-for-mwc-arduino-148190

    http://www.pnlabvn.com/pnlab/index.php?page=shop.product_details&flypage=shop.flypage&product_id=503&category_id=104&manufacturer_id=0&option=com_virtuemart&Itemid=29

    ReplyDelete
    Replies
    1. ok, it should work, check your connection (SDA SCL INT GND and VCC), if possible check SDA and SCL bus with a logic analyzer.

      Delete
    2. Thank Davide Gironi !!! I finished the project with MPU6050 ......

      Delete
  12. Hello David,

    look in your mpu6050.c code at
    int8_t mpu6050_readBytes(uint8_t regAddr, uint8_t length, uint8_t *data)
    ...
    //request register
    i2c_start(MPU6050_ADDR | I2C_WRITE);
    i2c_write(regAddr);
    _delay_us(10);
    ...
    }

    does not work with Peter Fleury soft i2c.

    I change to

    ...
    //request register
    i2c_start(MPU6050_ADDR | I2C_WRITE);
    i2c_write(regAddr);

    i2c_stop(); <-------------

    _delay_us(10);
    ...

    now it works.

    Thx for share your source.

    Gerry

    ReplyDelete
    Replies
    1. strange, cause i'm using it with fleury i2c too, and to me it works without this change. anyway.. if it work, it's good! ;)

      Delete
  13. Hello,
    How to fix error ''TCCR0B' undeclared (first use in this function)'?
    I got it in mpu6050.c on line 481...

    ReplyDelete
    Replies
    1. this library is developed on Atmega168, Atmega328 should be compatible, but you are probaly using other then those two, or you are not including the correct header files, because TCCR0B should be defined for Atmega168, but it can not be defined on other micro that does not have this register.

      Delete
    2. Thank you for reply, I've changed register according to datasheet (I use ATMega16) and it compiles without any errors. But when I try to use it - I get only noise. To be sure, that everything is OK with serial communication, I added few line to your code:

      #define UART_BAUD_RATE 9600
      .........
      #if MPU6050_GETATTITUDE == 1 || MPU6050_GETATTITUDE == 2
      uart_puts("IF_1_2_START"); uart_puts("\r\n");
      //quaternion
      ...........
      uart_puts("IF_1_2_END"); uart_puts("\r\n");
      #endi

      In terminal I see:
      IF_1_2_START
      и L>ШЛ!ѕљу;@3Bуѕ wї

      IF_1_2_END

      The data (or noise) comes different:
      й†?ж wЅ(^$»ґ’а;Ќ'ч=Џ(ї;я5[ј
      µm?ЎП‡Ѕ ‚5»Юtс; Ю >Р Х;Љйjј

      Q?щЉ”Ѕ¬

      Aе~?ДејЅ€ »Їl аJ <5е’ј


      Any ideas how to make it work correctly?

      Delete
    3. point 1, check that you compile code with the same frequency (F_CPU) your micro runs.
      to simplify things, start checking only uart communication. check with something like this

      #include
      #include
      #include

      #define UART_BAUD_RATE 2400
      #include "uart/uart.h"

      int main(void) {
      uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
      sei();

      while(1) {
      uart_putc('x');
      _delay_ms(500);
      }
      }

      Delete
    4. I've defined FCPU = 8000000 and baud rate = 9600.
      As you see from previous post I get to terminal strings ("IF_1_2_END") correctly. Only data from MPU6050 is 'encrypted'... :)

      Delete
    5. ok, as you can see my code output data as byte (uart_putc...) and then "parse" it back to number on processing.
      to output data as number you should use ltoa or dtostrf,
      just define MPU6050_GETATTITUDE to 0 and you should get ascii output on your uart terminal.

      Delete
    6. Great! Many thanks :)
      It almost started to work in a normal way, but for some reason after 10-15-20 seconds it starts to send the same data to terminal:
      -1 -1 -1 -1 -1 -1
      -0.00006 -0.00006 -0.00006 2.50000 -0.60976 1.70732
      If I restart Atmega - it will work normally again for short time, but then it sends the same mentioned above numbers.. :(

      Delete
    7. this errors never happens to me, i do not know how to help you. i can only suggest you to check your connections, check the chip with arduino / other code, and try to debug code with some simple uart_puts.

      Delete
    8. I just had this same error for what it's worth, but I know that I have intermittent connections too. I'll fix them and see if it goes away. It's funny to see that someone else has the exact same thing.

      I'm using an atmega1280 with the gy521 IMU that has the MPU6050.

      Delete
    9. Well, I figured out what the problem was with the random numbers that showed up after a few seconds of polling raw data. I had the EXACT same behavior as Denisas, and it wasn't due to bad connections as I suspected.

      I also thought that maybe it was because I didn't have INT0 connected, but then I realized that INT0 is only used for the DMP filter (oddly enough, my DMP filter mode works without it, though it lags a little bit).

      The real problem is that I compiled the code several times with #define MPU6050_GETATTITUDE 1 or 2, when I was playing around with the filters. Whenever I switched back to mode 0 to get raw data, it would only work for a short time. The issue seemed to be with the preprocessor definitions persisting and screwing things up. Once I ran a "make clean" and wiped out the old definitions, all was fine. I'm getting good raw data now.

      I swear I don't even know how many times a "make clean" has cleared up some weird problem of mine, but I still forget to try it!

      Delete
    10. good!
      i forget to tell you, if you change preprocessor def, a make clean is needed.

      Delete
  14. Hello.
    Thanks for great work. I research how can I use gyro and accelerometer together ? I can calculate row and pitch with only accelerometer but how can I use gyro I do not know. I write a small library for Mpu6050(find gravitiy and angular velocity). I want to know how can I use that together(gravity and angular velocity)? I want to do this with my library. Thank you. Good Work.

    ReplyDelete
    Replies
    1. to estimate attitude, you can use angular velocity and acceleration of a body with mpu6050 in two way: 1] using internal DMP, 2] using an implemented alghoritm, like the mahony i use in my code.

      Delete
  15. First of all thank you for this sharing your job is great. I have some problem with "processing". I send data through Bluetooth device to com port on pc and with "Realterm" I can see data transfer (hieroglyphs), but Processing program do not want to see this com port. Maybe you are faced with this problem?

    ReplyDelete
    Replies
    1. unfortunately i've never check bluetooth + processing.

      Delete
    2. Can you explain how to recompile double variables variable from char? Whether such a conversion does not affect the accuracy?
      long *ptr = 0;
      ptr = (long *)(&qx);
      uart_putc(*ptr);
      uart_putc(*ptr>>8);
      uart_putc(*ptr>>16);
      uart_putc(*ptr>>24);

      Delete
    3. it doesn't affect accurancy because this is not a conversion, this code "split" the double number in bytes. a double is 4 byte. then it get recompiled on processing side using this code (you can find it also in my processing sample)

      float f = Float.intBitsToFloat( (buf[3] & 0xff)<<24 | (buf[2] & 0xff)<<16 | (buf[1] & 0xff)<<8 | (buf[0] & 0xff) );

      Delete
    4. I understand now, thank you for your help. I have another question :). Why float value always increase in value? I try to get only one double value. May it be a mistake in avr code? My peace of code for reading values:
      int i = 0;
      byte[] buf= new byte[29];
      while(true)
      {
      int smb = comport.ReadByte();
      if ((Convert.ToChar(smb) == '\n'))
      {
      break;
      }
      buf[i] = Convert.ToByte(smb);
      i++;
      }
      if (buf.Count(a => a!=0) == 4)
      {
      i = 0;
      float value = Convert.ToSingle((buf[(i + 3)] & 0xff) << 24 | (buf[(i + 2)] & 0xff) << 16 | (buf[(i + 1)] & 0xff) << 8 | (buf[i] & 0xff));
      Log(LogMsgType.Incoming, value.ToString() + '\n');
      }
      else
      {
      Log(LogMsgType.Incoming, buf.Count(a => a != 0).ToString()+'\n');
      }

      Thank you for your help

      Delete
    5. I do not move sensor and got these results (period 500ms)

      -1.147967E+09
      -1.148398E+09
      -1.148801E+09
      -1.148876E+09
      -1.149041E+09
      -1.149097E+09
      -1.149557E+09
      -1.150044E+09
      -1.150769E+09
      -1.151405E+09
      -1.152164E+09

      Delete
    6. -1.xxx * 10^9 ? this value is too low.
      check you sensor using uart, then try use processing, check if the values are the same.

      Delete
    7. MPU6050_GETATTITUDE 0 (ax and axg)
      -336 -0.02466
      -368 -0.01929
      -364 -0.01831
      -320 -0.01953
      -364 -0.02441
      -328 -0.02246
      -468 -0.02271
      -296 -0.01953
      -352 -0.02026
      -440 -0.02051
      -384 -0.02539
      -372 -0.02441
      -392 -0.02197
      -328 -0.02222
      -316 -0.02490
      -364 -0.02759
      -216 -0.02222
      -396 -0.02441
      -360 -0.02100
      -356 -0.01733
      -452 -0.02490
      -308 -0.01855
      -316 -0.01953
      -296 -0.01807
      -256 -0.01782
      -416 -0.01880
      -400 -0.02539
      -272 -0.02002
      -248 -0.02075
      -336 -0.02319
      -368 -0.01489
      -316 -0.02197
      -288 -0.02002
      -364 -0.02051
      -420 -0.01489
      -300 -0.02637
      -324 -0.02441
      -336 -0.01782
      -504 -0.01807

      Is that normal? Do not move sensor.

      Delete
    8. ax accel value for x axis in raw format
      axg accel value for x axis expressed in gravitational force
      those values seems normal if x axis is perpendicular to ground, so no g force act on this axis

      Delete
    9. It means that my com port reading code is bad or code on controller do not work correct (double = (float*)x). When I try read data from com port with RealTerm software, I choose float4 data format and got very different values. Try to find solution, thank you again for your help.

      Delete
  16. Hello Davide!
    just want to know how you are performing floating point operation with atmega168 while it doesn't support this??

    ReplyDelete
    Replies
    1. just using libm, for the math i need it works.

      Delete
  17. hi,
    can you send me your compiled hex file for atmega328p please?

    ReplyDelete
    Replies
    1. please send me an email and i will reply it back as attachment.

      Delete
  18. what kind of program do you use on your computer to view orientation? Did you make the program yourself?

    ReplyDelete
    Replies
    1. Found it out; processing :)

      Delete
    2. good!
      you've been faster than my reply :)

      Delete
  19. hi davide,
    can you send me your hex file for atmega328. because I compile it by AVRStudio, serial data is very complicate. I vant to try your hex code please.

    ReplyDelete
    Replies
    1. as i write you above, send me an email and i will reply it back as attachment. :)

      Delete
  20. ok, thanks.
    atmci2002@yahoo.com

    ReplyDelete
    Replies
    1. Thank you David. I have got it and used. What is my fault I didn't understand?

      Delete
    2. i do not know :)
      just investigate the compiler ouput and check that all the files get compiled, also check that libm is included.

      Delete
    3. its ok. I added libm to libraries at AVRStudio. and everything is ok. thank your help and excuse me for my poor english.

      Delete
  21. Hello, Davide

    can you explain how you choose these values? Do you make any calibration tests? Thanks again!

    #define MPU6050_AXOFFSET 0
    #define MPU6050_AYOFFSET 0
    #define MPU6050_AZOFFSET 0
    #define MPU6050_AXGAIN 16384.0
    #define MPU6050_AYGAIN 16384.0
    #define MPU6050_AZGAIN 16384.0
    #define MPU6050_GXOFFSET -42
    #define MPU6050_GYOFFSET 9
    #define MPU6050_GZOFFSET -29
    #define MPU6050_GXGAIN 16.4
    #define MPU6050_GYGAIN 16.4
    #define MPU6050_GZGAIN 16.4

    ReplyDelete
    Replies
    1. using calibration methods for accellerometer and gyroscope.
      you could do your own, if you want i've developed an helper script here:
      http://davidegironi.blogspot.it/2013/01/accellerometer-calibration-helper-01.html
      http://davidegironi.blogspot.it/2013/01/gyroscope-calibration-helper-01-for-avr.html

      Delete
  22. Hy!

    First thank you for your publication!

    We try to use your code with atmega128 and DMP. During the porting we changed:
    #define MPU6050_DMP_INT0SETUP EICRA |= (1<
    #define MPU6050_DMP_INT0SETUP EICRB |= (1<

    #define MPU6050_DMP_INT0DISABLE EIMSK &= ~(1<
    ISR (INT7_vect) {

    Our code doesn't work. Does it necessary to change anything else? We changed the timer settings for atmega128 to use mahony filter. It works fine after a little offset corrigation, but I think it is too slow for us. Would be better the MPU options, what doesn't work.

    Can you help us?

    Zoltan Abonyi

    ReplyDelete
    Replies
    1. EICRA |= (1 < < ISC01) | (1 < < ISC00) - - >
      EICRB |= (1 < < ISC71) | (1 < < ISC70)

      EIMSK &= ~(1 < < INT0)
      EIMSK |= (1 < < INT0) - - >

      EIMSK &= ~(1 < < INT7)
      EIMSK |= (1 < < INT7)

      ISR (INT0_vect) { ---–>
      ISR (INT7_vect) {

      Sorry, but forum engine lost my codes.

      Delete
    2. check that your INT pin is connected.
      i'm sorry but i does not have any 128 to compile and check over it.

      Delete
    3. Finnaly We found the "mistake". We don't really understand the problem.

      We changed: success = mpu6050_writeMemoryBlock(progBuffer, length, bank, offset, 1, 0);
      to
      success = mpu6050_writeMemoryBlock(progBuffer, length, bank, offset, 0, 0);

      It is work now, but I'm a little bit confused. It disabled this line:
      if (verify) verifyBuffer = (uint8_t *)malloc(MPU6050_DMP_MEMORY_CHUNK_SIZE);

      Our ported one creshed in this line. Few time the atmega128 did it, but finnali stopped during this line. (debug method: sent character before and after this line, finnally we got only before this line).

      Do you have an idea for solving of the problem?

      Delete
    4. it seems a runtime memory error.
      i've check this code over Atmega168 and Atmega328, but those two are the same series, never checked this on other microcontroller, so i can not help you.
      check that you have got libm linked (-m).
      if possible, let me know your solution to let it works with Atmega128.

      Delete
  23. hello Davide, yor publication is good..
    can u explain how to convert degree per second to degree from this sensor?
    thank you

    ReplyDelete
    Replies
    1. if you mean raw data to deg/sec, look at the mpu6050_getConvData function
      if you mean accell + gyro data to aerospace sequence (roll pitch way), look at the mahony filter function or DMP function if you use this chip with internal DMP processing.

      Delete
    2. i mean how to get angle value (deg) ? because output from sensor is angular rate (deg/sec).

      Delete
    3. i suppose you mean roll / pitch / yaw angles, to estimate the position of the object in the space, i.e. attitude estimation.
      to get those angle you need both accellerometer and gyroscope values, you have two choice: 1 use the internal DMP, use an alghoritm, like the mahony one that i use here.
      for a better attitude estimation you should use also a magnetomer, take a look at the 10dof unit post here, for estimation using also a magnetometer.

      Delete
  24. Great job. How can I output heading (roll, pitch, yaw) in degrees ( 0-360)?

    ReplyDelete
    Replies
    1. Figured it out roll, pitch, yaw in degrees. However I am getting a lot of drift using the mahony filter.

      Using the internal DMP processor will not compile.

      Changed
      const prog_uchar mpu6050_dmpMemory[MPU6050_DMP_CODE_SIZE] PROGMEM = {

      to
      const uint8_t mpu6050_dmpMemory[MPU6050_DMP_CODE_SIZE] PROGMEM = {

      This eliminated the errors but it still won't compile.
      Maybe a flag issue?

      Any ideas?

      Delete
    2. MPU6050_GETATTITUDE = 0 will output to uart roll pitch yaw in degree (but you can not use the processing gui like the one above)

      for the drift problem, try to calibrate gyroscope (also accllerometer, but for the drift gyroscope is the thing involved).
      here you can find two method i use to calibrate accell and gyro:
      http://davidegironi.blogspot.it/2013/01/accellerometer-calibration-helper-01.html
      http://davidegironi.blogspot.it/2013/01/gyroscope-calibration-helper-01-for-avr.html

      for the compile problem, using Atmega168 and Atmega328P it gives me no problem with avrgcc.
      check that you have included libm (for the math.h) in the c linker (-m)

      Delete
    3. Thanks for the quick reply. I love your code. It was a math linker problem with compiling the internal DMP processor code. I used a different make file and it was okay. I still am getting too much yaw drift for my project. I think i will try using an MMA7455 accelerometer and HMC5883L magnetometer together. I see you have libraries for these. Will your two libraries work together? (Will there be i2c issues?)

      Thanks for your effort.

      Delete
    4. or the an ADXL345 accelerometer and HMC5883L magnetometer together.
      Same question:
      Will your two libraries work together? (Will there be i2c issues?)

      Delete
    5. you have to edit the code to make it works togheter, i suggest you a cheap ebay 10dof platform like the one i use.

      Delete
  25. Hi Davide Gironi
    Thanks a lot for sharing your work! I really appreciate it. I'm working with MPU6050 now, but i'm having some troubles. Would you mind helping me with it? My email is hoanghiep1412@gmail.com. May I have yours?

    ReplyDelete
  26. Hi Davide
    Great Job : i try to compile and there is error in this script :

    void mpu6050_writeByte(uint8_t regAddr, uint8_t data) {
    return mpu6050_writeBytes(regAddr, 1, &data);
    }
    Compiler didnt receive void with return ... thanks

    ReplyDelete
    Replies
    1. strange.
      this project is built using avrgcc, so if you are using other compiler, try this one.

      Delete
  27. Hi,
    first thanks for this lib, but my question isn't about the code, it's about the pin INT and AD0 where should I connect them. I use Atmega168 ? thanks for any help !

    ReplyDelete
    Replies
    1. INT pin from mpu6050 to PD2 (INT0) of your Atmega

      Delete
  28. Hey Davide,
    Great job on this informative article. Even though I read through it, I still have many questions as I am fairly new to programming on microcontrollers. I have emailed you in detail of my questions. If you have received it or haven't received it, can you let me know?
    Thank you!

    ReplyDelete
  29. Hello !
    I have a problem with my MPU 6050 !
    The temp sensor and de accelero work very good !
    The gyro result on register is always at 0 ! I don't make a calibration !
    I think i need do to something before reading the result !!

    Can you help me ?
    Thank you

    ReplyDelete
    Replies
    1. yes, you hsould get reading even if there is no calibration.
      the code proposed here should work without any change.
      try another device, try debugging with uart to check where it fails.

      Delete
  30. Hello Davide Gironi,
    Thank you for the work so far.
    I have a question about the calibration of the sensors. When I calibrate the sensors the quaternion (dmp) values are still the same. My question is, is it possible to calibrate the quaternion and how? or is it already calibrated.

    Thank you.

    ReplyDelete
    Replies
    1. if you would like to use DMP internal function for quoternion estimation,
      look at the mpu6050_dmpInitialize() funcion you should find the offet initialize function, edit here:

      mpu6050_setXGyroOffset(xgOffset);
      mpu6050_setYGyroOffset(ygOffset);
      mpu6050_setZGyroOffset(zgOffset);

      take a look to Jeff Rowberg i2cdevlib, here you should find other function you could implment to setup Accellerometer Offset, and fine grain Gyro gain

      Delete
  31. Dear Sir,
    I have a question about MPU6050 library. I want to delete gravitation component of the signal ( and gain gravity- free accel sensor measurements). Can I do this in Your library?
    Respectfully yours,
    Piotr

    ReplyDelete
    Replies
    1. you should get measure from the gyroscope of this chip, and then process it using an algorithm you can write.

      Delete
    2. Thank you for your response.
      I have next question.
      I have ATMEGA32 and I want to run library on this chip. I was modify these fragments in code:

      #define MPU6050_TIMER0INIT TCCR0B |=(1<<CS02)|(1<<CS00); \
      TIMSK0 |=(1<<TOIE0);
      to:
      #define MPU6050_TIMER0INIT TCCR0 |=(1<<CS02)|(1<<CS00); \
      TIMSK |=(1<<TOIE0);

      AND:

      #define MPU6050_DMP_INT0SETUP EICRA |= (1<<ISC01) | (1<<ISC00)
      //define enable and disable INT0 rise edge interrupt
      #define MPU6050_DMP_INT0DISABLE EIMSK &= ~(1<<INT0)
      #define MPU6050_DMP_INT0ENABLE EIMSK |= (1<<INT0)

      to:

      #define MPU6050_DMP_INT0SETUP MCUCR |= (1<<ISC01) | (1<<ISC00)
      //define enable and disable INT0 rise edge interrupt
      #define MPU6050_DMP_INT0DISABLE GICR &= ~(1<<INT0)
      #define MPU6050_DMP_INT0ENABLE GICR |= (1<<INT0)

      Unfortunately these modyfications are create mistekes - program doesn't work well. What I am doing wrong?

      Delete
    3. i've any atmega32 here to test, first build a clean project (without mpu6050 code), to test timers and interrupt input for your atmega, then you can integrate it to this code. run it at 16Mhz, check you atmega fuse. do some debug with uart.

      Delete
  32. can any one help me in coding mpu6050 for ATmega16

    ReplyDelete
    Replies
    1. hello, to make it works on ATmega16 just change some registers according to your micro. if you read comments above there may be some usefull informations

      Delete
  33. Hi

    This is very simple MATLAB code to visualize quaternion data:
    http://www.mathworks.com/matlabcentral/fileexchange/45302-serialport-quaternion-data-visualize

    you have to send quaternion values on serial port like this:
    //First set qw qx qy qz on mpu6050_getQuaternion
    //use this code:
    dtostrf(qw, 1, 4, itmp);uart_puts(itmp); uart_putc('\t');
    dtostrf(qx, 1, 4, itmp);uart_puts(itmp); uart_putc('\t');
    dtostrf(qy, 1, 4, itmp);uart_puts(itmp); uart_putc('\t');
    dtostrf(qz, 1, 4, itmp);uart_puts(itmp); uart_putc('\t');
    uart_putc(' ');//only for terminate line
    Thank you david

    ReplyDelete
    Replies
    1. thank to you,
      your like is above in description ;)

      Delete
  34. Greetings, Davide
    Trying to use your code for UAV orientation. I'm using AVRStudio and can not even compile it %)
    There are many errors such as undefined reference to some functions in uart.h and mpu6050.h. AVR C is new for me, and maybe these errors are simple to fix, but I see no way to do this.
    Also tried to open your files with AVR GCC, didn't succeded with this so far.

    ReplyDelete
    Replies
    1. Ensure that you are include references to libraries, and compiling also the .c files of libraries.
      Also add the malib to the linker (-m option).
      I found Eclipse AVR very simple, just import the project, and set the -m option to the linker, than avrgcc and Eclipse will do all the works on compile.

      Delete
  35. H,
    i have a question.
    i have calculated EULER ANGLE without using quaternion .
    How to apply EULER ANGLE into processing as:
    rotateZ(-roll);
    rotateX(-pitch);
    rotateY(-yaw);
    Could you guide me?
    That's great if u can show me short code about it.

    ReplyDelete
    Replies
    1. look at the "//roll pitch yaw" code in the main.c code.
      use this code to send euler values to processing, then simply apply rotations in processing, like actual code does. One important note, read the comment you can find in the processing code to understaind the correct order of rotation you have to do.

      Delete
    2. can you show example command code about send euler angle (serial list) from arduino to processing?
      thanks!

      Delete
    3. It's the code below the "//roll pitch yaw" comment in main.c, nothing more than that. Just copy and paste that code.
      Processing side, it's code you find in "serialEvent" method. Keep in mind that if you send only roll pitch and yaw to pressing, you have to change the bufread value check.

      Delete
  36. Hi Davide,
    I did put a LCD on my atmega16 in order to see what is going inside the avr.
    I just can't figure out how to write the pitch, roll and yaw values.
    I need them in degrees (integers) for my project.
    Could you help me out here please?

    ReplyDelete
    Replies
    1. In order to get roll, pitch and yaw, you could use the mpu6050_getRollPitchYaw function provided by this library.
      Check tha main.c sample code for reference.

      Delete
  37. Another thing:
    I used PC0/PC1 (SCL/SDA) and INT0 on the ATMega16. I have mounted 4k7 pull-ups on both SCL and SDA, but while inspecting the small module with the accelerometer on it I saw there are pull-up resistors there also. Should I desolder the ones on my proto board and let just the ones on the module?

    ReplyDelete
    Replies
    1. If you already have pull-ups on the module, you do not need it even on microcontroller side.

      Delete
  38. Sorry for my many comments...
    Is there a way to see that the gyro board is not present?
    This would help in avoiding to process data from a chip that isn't there...

    ReplyDelete
    Replies
    1. hello,
      At first i sugget you to print out your values to UART, and read using a terminal.
      Start with a simple hello word program.
      Then try to write out values you read from the accellerometer, using itoa conversion.
      Then, you can check your LCD output.
      If you are new to this subject you could also think about building your project with arduino, which is fairly simple that writing straight avg-gcc code.

      Delete
    2. Hi,

      I am not new, quite the opposite. The LCD works fine, I am outputting lots of info on it. I was just using your code without going into too much details. A change on the timer registers did the work fine, I mean the code compiled.
      Let me put my questions differently:
      1. I did not read the MPU datasheet and therefore I don't know what exactly mean the values you read for pitch roll and yaw. I knowthat what I need are values in degrees (0-359) and I was gently asking for a conversion formula;
      2. Your function MPU6050_init doesn't return any value. Thus I don't know if there is a responding MPU6050 in the circuit or not. It would be important to know because the project I am working at can work with or without the MPU6050 and it would be interesting to know inside the code if the device is actually connected, in order to process the events or not.

      Delete
    3. 1. pitch roll and yaw are expressed in radians, so you just have to convert it to degree. 1 Radian = 57.2957795 degrees, so angleDegree = angleRadians * 57.2957795
      2. try to call i2c_start directly, and read the output value (0 = device accessible, 1= failed to access device), it should work but i've not tried, i've always use this library with connected mpu6050.

      Delete
    4. 1. thanks a lot.
      2. I found out that the i2c library wasn't working without adding i2c_stop like in a previous comment. As soon as I added the line I was able to read data.

      Delete
    5. You are welome ;)
      Than you for your feedback.

      Delete
  39. It is Saturday and since it is a free day I am hobbying all day long.
    I have managed to get out of the MPU most of what I wished to.
    There are however some questions that reside:
    At start, it seems the MPU is somehow "positioning" itself. This takes quite a long time (10-20 seconds).
    While the roll and yaw values seem to position themselves relatively to a horizontal plane, the pitch value is constantly differing at every startup, randomly, and even changing slowly in time, without having the PCB moved.
    I understand the roll and yaw relate to gravity in order to "auto-zero" themselves. What I don't understand is the pitch: to what does it relate ?

    ReplyDelete
    Replies
    1. Never mind. It's in the datasheet. It should be linked to a magnetometer to have a yaw without offset.

      Delete
  40. One last thing, I think that's about it:
    The mpu6050_getRollPitchYaw function indeed computes the Euler angles from the [q0...q4] quaternion.
    These angles are relative to a fixed origin system relative to Earth.
    This means that if you roll, there will be also a DeltaY displacement too (a pitch) and viceversa.

    If you are inside the object equipped with the sensor, it is irrelevent to relate to Earth-fixed origin. Instead one should relate to the object itself, to see the roll and pitch degree (the yaw remains the same however).
    This system of coordinates defines the Tait-Bryan or Cardan angles. Since you, David, are italian, and my motorbike (where the device will be placed) is using a Cardan drive, I have used Cardan in the following as a compliment to Cardan and you. Hmmm...Cardan was an italian too...complicated stuff.

    So:

    I wrote a new function to your MPU6050.c file which gives the Cardan angles alpha, beta and gamma:

    void mpu6050_getCardanAngles(double *alpha, double *beta, double *gamma) {
    *alpha = atan2(2*q0*q1 + 2*q2*q3, 1-2*q1*q1 - 2*q2*q2);
    *beta = -asin(2*q0*q2 - 2*q3*q1);
    *gamma = atan2(2*q0*q3 + 2*q1*q2, 1 - 2*q2*q2 - 2*q3*q3);
    }

    ReplyDelete
    Replies
    1. I'm not shure about what you are asking, anyway, accellerometer and so the way we derive euler angles, works using the earth gravity force, so, euler angles that defines the position of the gyro+accell unit will be always related to position of the unit relatively the earth (ref. "...It is irrelevent to relate to Earth-fixed origin..."). Said this, you could fix an origin point where you want of course.
      You could convert quaternion to Cardan. Using Cardan (and euler even) pay attention to apply rotation in the correct order, read comments in the processing.org file to find an explanation about the reason why order of rotations is important.

      Delete
    2. I wasn't asking for anything, it was a feedback.

      Let me put it like this:

      When you look at the screen processing the MPU data in order to replicate on screen the position of the card you are holding in your hand, Euler angles are relevant since you (the observer) are in the Earth-fixed origin.

      However, when the observer in in the MPU coordinates and becomes a pilot (in a plane or motorbike containing the MPU card), everything changes. The pilot is interested in the roll or pitch angle relative to the plane/bike, not relative to earth. This when the Cardan angles become interesting to display and Euler angles aren't representative anymore.
      Example:

      You climb a 25 degrees hill with your bike and make a left turn. Excluding the yaw, from the pilot's point of view, it only makes a roll (leans to the left with the bike). From the Earth point of view, it is a combined yaw and pitch movement. Displaying Euler angles will disorient the pilot, while Cardan angles will be accurate.
      I looked a little more in detail on the comments and I saw there was another user (yuval) who observed the same thing. However, he just changed the formula whereas I added a new one.
      I am fortunate to be a former aircraft military engineer. More fortunate even to be a modern biker :) This morning I went through my old stuff from the Academy and I have found my old courses of special maths (geometric algebra) and aviation mechanics, dating 1991. After a summary review, my guess was confirmed. My suggestion to you would be to add that function in order to enhance your MPU library.

      Thanks again for the effort of writing it so accurately and moreover for sharing it with the community.

      Delete
    3. Ok, now i've understaind what you mean with "fixed origin".
      Thank you for sharing your feedback!

      Delete
  41. Hi Davide Gironi,
    i have a question:
    i have computed the roll, pitch, and yaw
    which command i can use to simulate the rotation with roll,pitch, yaw?
    rotateX(......... );
    rotateY( ............ );
    rotateZ (............ );
    Many thanks!

    ReplyDelete
    Replies
    1. If you look at my processing script you will find an explanation about the quaternions and rotation sequences.
      In my example, i've used the aerospace sequence, so:
      rotateZ -> for roll angle
      rotateX -> for pitch angle
      rotateY -> for yaw angle
      Hope this helps ;)

      Delete
    2. I don't understand when i use in processing:
      rotateZ -> for roll angle
      rotateX -> for pitch angle
      rotateY -> for yaw angle

      It 's not correctly.
      (I compute angle directly from acceleration & gyroscope & magnetometer) not quaternion.
      could you guide me repair it?
      Thanks!

      Delete
    3. The sequence of the rotation you apply to predict the object attitude depends on the way you have derivated it. On wikipedia Euler Angles page you should find all you need about spatial rotations.

      Delete
  42. Hello,

    I am using your library to read axg values. However, i only receive 254 and 255 over uart. Do you have any suggestions on how to fix this?

    Thank you very much!

    ReplyDelete
    Replies
    1. At first, test your uart bus, be shure that if you send any number you recive the right number at terminal side.
      Then, if the error is on the library, it could be a bounch of reasons. Double check wiring. Check your mpu6050 with other hardware and software, like arduino. Then debug the bus using a logic analizer, or if you do not have, use simple uart to debug. It could be the initialization code.

      Delete
    2. I figured it out. It was a define of F_CPU in delay.h which didn't fit the crystal i was using. I have no idea why that didn't throw an error, since i defined it correctly in main, though

      Delete
  43. hi,
    I am using atmega168a, but i can't get data in matlab.I don't know why the code is not working!
    any different is between atmega168A and atmega168 ?
    please help me

    ReplyDelete
    Replies
    1. Hello, data get printed to uart, and viewed in processing. This project does not use matlab.
      At first, compile and upload this project with MPU6050_GETATTITUDE set to 0 (zero), and check your output using a terminal.
      Double check your wiring. Check that your terminal uart connection works.

      Delete
  44. Hello again
    I have many question
    1. What is your interface to get data from mpu6050?(it means there are any software to setup on computer to get data from mpu6050 or can I use matlab to get data?)
    2. I tried to get data on matlab with this code:

    s= serial('COM4')
    fopen(s);
    Fscan(s) or fgetl(s)

    I can get data but like noise:

    š¯‰eyŠÒ˜_"
    ½žÝMÇ
    åõ¯¦Nä
    ß­§‰eyŠÒ˜_2
    ½žÝ]Ç
    •ûž¬Nä
    ßš¯‰eyŠÒ˜_"
    ½žÝ]Ç
    åõ¯¦Nä
    ß­§‰eyŠÒ˜_"
    ½žÝ]Ç
    •ûž¬Nä
    ß­§‰eyŠÒ˜_"

    Do you have any idea about it?


    3. I think occur this problem because frequency or Baudrate dose not match with your code. I cant find define baudrate or frequency on your code. Where defined baudrate in your code?

    ReplyDelete
    Replies
    1. I think you have to set your correct baud rate in matlab like this :
      s= serial('COM4')
      set(s,'BaudRate',9600)
      .
      .
      .
      but be sure how much is your BaudRate and set the correct Baud in matlab.
      u can use hyper-terminal or (Terminal part) in codevision or ... to communicate with and check your baud.

      Delete
    2. If you just want to read Values i recommend HTerm or Docklight. These are very easy to use.

      Delete
    3. when use
      s=serial ('com4')
      it means your baudrate is 9600, if you want change your buad must uses of this code:
      s=serial('com4','baudrate',4800)

      "Mr Soleimani please give me your email or phone number to talk about it, b komak ehtiaj daram dooste aziz :-)"
      alinezhad66@yahoo.com

      Delete
    4. "Test", I used Docklight but data is :
      و??,ة8‎Iے?? ٍح<|¬?? ‰6يlے??nٍvيlے?? ٍ6­,ے?? ٍv‎|ے??nگ6­,ے?? ²ح<|و??~`$ىي,ے?? ‰ح<|و ??‰v¼é‏??™¬اgجو??=فاgŒو???ٍاgŒو??=ظاxŒو??™ىئgŒو??™¬اgجو??™ى1ڑ½Yے??K¬اgجو??=ظئgŒو??™ىئgجو??ذگ½ يXے??ظگ؟SيJے??ظگ؟SيHے??ذگ؟SيHے??ظذ½ زùے??ظگ½ يHے??ظگ½ يHے??ùذ½ زùے??ذذ½ زù‏ظّ??چبy-و??Y0]+©x??Yب~X©Mے??Yب‏)R‰ے??Yب‏k©dے??Yب‏k©Mے??[0]+©]ے??Yب‏iR‰ے??Yب~}©x??Yب~X9Lے??Yب‏)©]ے??Yب‏> é]ے??\)بج}ـ??\?)lجTَ\iƒئé«ے??\)طج=ق??\)طج=ـ??\iƒئ

      wait wait......
      in Docklight there are 4 tab: 1. ASCII , 2.HEX, 3 Decimal, 4.Binary
      when select ASCII, data is like :
      ئé«ے??\)طج=ق??\)طج=ـ??\iƒئ
      but when select Decimal the data is number like:
      063 063 093 211 089 091 141 115 255 063 063 093 211 091 121 200 222 063 063 095 211 150 153 021 204 063 063 093 211 091 121 200 220 063 063 093 211 089 121 200 220 063 063 095 211 089 121 200 220 063 063 093 147 210 059 216 220 063 063 093 147 091 121 200 222 063 063 092 217 221 011 201 221 063 063 092 028 089 114 201 221 063 063 092 078 011 201 157 063 063 092 078 206 249 222 172 063 063 092 078 109 249 222 172 063 063 092 014 027 242 169 254 063 063 092 078 217 236 169 255 063 063 092

      these numbers are true?

      Delete
    5. Hello,
      Consider that if MPU6050_GETATTITUDE is set to 1 or 2, your output is byte formated, if otherwise MPU6050_GETATTITUDE is set to 0, atmega ouput number in the ascii format.

      Delete
    6. Do I need to use an external crystal?(an 16 MHz external crystal)

      Delete
    7. Yes, for better performance i run this project at 16Mhz, it could also run slower, but you have to change some timer setup, and if you use the mahony algoritmh for attitude estimation, 8Mhz is a little too low.
      Note that you have to setup fuses of your atmega to run it at 16Mhz.
      For further info on fuse, just search online and you will find it a lot of informations.

      Delete
  45. Salam,
    i am using atmega 16 internal 8Mhz oscillator with the respective fuse bit settings at baudrate 19200. The uart is currently printing gibberish:p Do i need to change fuse bit settings? Atmega works at max 8Mhz frequency so how do i cater for mahony??...any suggestions on going about this issue??
    Thank you in advance :)

    ReplyDelete
    Replies
    1. Mahony use more resources than DMP, so if you whant to use mahony, it is better to run it at 16Mhz, just attach an external 16Mhz crystal and set properly fuses.
      Also, to prevent gibberish output, you need higher baudrate.

      Delete
  46. When i run the code uartputstr works fine but uart_putc does not work. Any ideas for solution??

    ReplyDelete
    Replies
    1. Strange, build a new project using just uart library to check just the uart output.

      Delete
  47. Hello,

    When i try to read from the sensor, i only get back what i just sent there (adress + read). What am i doing wrong?

    ReplyDelete
    Replies
    1. It seems like i don't get an Ack from the sensor (tried both adresses). That is why TWDR doesn't change und that is why i get back what i just sent.

      I suggest to capture this error with
      if( i2c_write(regAddr) )
      {...}

      That being said. I'm still no closer to reading the sensor =/
      Any Ideas why i don't get an Ack?

      Delete
    2. Double check your wiring, also check your board with other hardware like arduino or adafruit. If it works, it may be the initialization or the i2c bus. Check it using a logic analizer.

      Delete
    3. I found that sometimes, depending on the wires length and proximity to other wires with heavy traffic, the 2k2 pullup resistors on the MPU6050 board are not enough. I have soldered another pair of 4k7 pullup resistors right next to the MCU i2c pins and the problem was solved.
      One more thing to check is the F_CPU definition in your project options. twimaster.c defines a default F_CPU of 4MHz if there is none defined for the project.

      Delete
  48. Great stuff, thanks!
    This project could use a simple setup guide.
    The things i had to do to make it work was:

    define _BV, as it was not defined anywhere
    #define _BV(bit) \
    (1 << (bit))

    define F_CPU
    #define F_CPU 16000000

    define what mcu im using, which is the 168PA. (i have the new xplained mini board)
    #define __AVR_ATmega168__

    One very important thing is that it ouputs trash to UART when MPU6050_GETATTITUDE is 1 or 2. Set it to 0 if you want numbers in UART output.

    If you are using prosessing for output, leave it at 1.


    ReplyDelete
  49. hi davide

    i use your processing source

    and i make appear window within cube and roll ,pitch ,yaw circle

    but one problem is happen

    roll,pitch,yaw is not change.

    just stay 0.....

    i don't know why this is happen to me

    i'm sorry but can you know me how can i solve this problem??

    ReplyDelete
    Replies
    1. ATmega is not sending data through uart to your pc, or the data is not sent in the correct format.

      Delete
  50. Hi David sir ,I've have downloaded your code and I've modified Ur code as per my controller .I've worked niether with mpu6050 nor with dmp before.I have read about quaterion on wiki .But I having problem using the code ,like how to get filtered data from 6050 ,right now i just want the filtered values to be displayed on my lcd.I know to use lcd, but I have no idea how to use the function in sequence to get those readings.Can u please provide me a documentation on the various funtions ,like where to use them or how to use them to get my things done.A little help would be appreciated.I am a mechanical engineer and a beginner in this stuff.

    ReplyDelete
    Replies
    1. Hello, here i propose two way to get filtered data, using the mahony filter, basically a complementary filter, and the DMP of the mpu6050, online you can find other filter implementation (kalman for example).
      To write things on lcd, i suppose you have to load a char array, so, use ltoa function or dtostrf to transform numbers to char, and then display the char array on your output. Refer to the main.c file as sample.
      If you are really a beginner, my suggestion is to use arduino and library on arduino, cause those library are a little user friendly :)
      Hope this helps.

      Delete
    2. hello sir ,thanks for your reply.After burning some midnight oil I have successfully run your code on my atmega 16 and also displayed the roll,pitch&yaw values in terms of degree on my lcd.Everythings working fine but the values are taking some time to get stabilized and also in between subsequent readings some strange angle values shows up like 170,250...,even when the angle is set at 30 degree.please shed some light on the problem.

      Delete
    3. At first, check that the raw values you get are consistent, it could be the way you convert values.
      Also double check your interrupt timer registers, run your ATmega at 16Mhz with an external crystal.

      Delete
  51. Allthough the example works, i have encountered a problem when i attempt to get both roll/pitch/yaw and gyro reading. My code currently gets the values and print them to serial. I am using this for a quadcopter flight controller.

    I am using Mahoney, so #define MPU6050_GETATTITUDE 1

    This code works.
    mpu6050_getRollPitchYaw(&roll, &pitch, &yaw);
    //mpu6050_getConvData(&axg, &ayg, &azg, &gxds, &gyds, &gzds);



    mpu6050_getRollPitchYaw(&roll, &pitch, &yaw);
    mpu6050_getConvData(&axg, &ayg, &azg, &gxds, &gyds, &gzds);

    This code does not. The roll/pitch/yaw values drift steadily (looks like some integrator continuosly adds to it), and the readings do not react to the sensor moving. The gyro readings are stable at some offset.

    Is it possible to extract both pitch/roll/yaw and gyro readings? Do the getrollpitchyaw and getconvdata somehow interfere with eachother?

    Full code is here: https://github.com/anderss90/quadcopter

    ReplyDelete
    Replies
    1. Hello,
      using your configuration, the library reads raw data (mpu6050_readBytes(MPU6050_RA_ACCEL_XOUT_H, 14...) every times the update quaternion timer interrupt is triggered TIMER0_OVF_vect.
      Then, then mpu6050_getConvData function reads raw data too (mpu6050_readBytes(MPU6050_RA_ACCEL_XOUT_H, 14...).
      You should try to implements a mpu6050_getConvData that does not call mpu6050_getRawData, use "global", volatile variable for axg, ayg, azg, gxds, gyds, gzds in mpu6050_updateQuaternion, and then simply return thos variable in a new mpu6050_getConvData2 function. This should works.

      Delete
    2. It works!

      Thanks alot for following up the comments!

      Delete
  52. Hi Davide,

    is it possible to get rid of using the timer0 interrupt in the code?
    I have a project on atmega32 and I need all three timers available for other purposes.

    ReplyDelete
    Replies
    1. If you just have to get gyro and accell data, you can even disable the attitude functions, and timers.
      If you need euler angles, and do not want to use any timer interrupt, you can use the internal DMP, which use INT0_vect interrupt. Eventually you can skip even the INT0_vect use, but the reading will be very unstable.

      Delete
    2. Thanks for your answer.

      I, however, found easier and more straightforward, to be sure there are no bugs in the code, to replace the atmega32 with an atmega644. The two processors have the same footprint with the exception of the OC2B pin. I just had to read the datasheets and rewrite the code related to the timers.
      The whole job was done in one day.

      Delete
  53. hi all
    I have taken the value after mpu6050_readBytes(MPU6050_RA_ACCEL_XOUT_H, 14, (uint8_t *)buffer);
    ax,ay,az,gx,gy,gz => ok
    but when i use mpu6050_mahonyUpdate(gxrs, gyrs, gzrs, axg, ayg, azg);
    all value q0, q1, q2,q3 always zezo? i don't know
    i use atmega128.
    please help me
    thank all !

    ReplyDelete
    Replies
    1. It could be that you set local ax,ay,az,gx,gy,gz values, instead of making new hlobal values. Also, you should add some sort of software concurrence to make it all works.

      Delete
    2. thank you!
      I have solved the problem, but i using mpu6050_getRollPitchYaw and value Yaw always drifts :( how to fix?

      Delete
    3. It should drift, but not a lot. Anyway, try to calibrate your gyro, and also accellerometer.
      You can find my calibration helper here at http://davidegironi.blogspot.it/2013/01/gyroscope-calibration-helper-01-for-avr.html and http://davidegironi.blogspot.it/2013/01/accellerometer-calibration-helper-01.html#.U5hA63J_vh4
      But you can basically use any other calibration method.

      Delete
  54. Hello! Thanks, good job!
    I'm using AT90CAN64 with MPU9150.
    But resulat, I think, not ideal:

    MPU6050_GETATTITUDE == 0.

    result axg, ayg, azg:

    0.14490,0.31653,0.72302
    0.14124,0.31592,0.74609
    0.15576,0.32532,0.72693
    0.13806,0.31299,0.72510
    0.14319,0.32239,0.72375
    0.14258,0.31689,0.73071
    0.14917,0.32813,0.72888
    0.15015,0.34021,0.74207
    0.15735,0.32361,0.73389
    0.15625,0.32104,0.73853
    0.14795,0.31812,0.72485
    0.13501,0.31592,0.73718
    0.14807,0.32007,0.71265

    Maybe I need to calibrate MPU or it can be some noize in result, because I think axg must be ~0,01, and ayg too.

    ReplyDelete
    Replies
    1. Hello, if the z plane of the mpu6050 is perpendicular to the horizon, z axis should be 1g. So, yes, you have to tyr to calibrate the accellerometer at least.

      Delete
  55. I impressed what you did. and it helped as well for my project. and now I wanna improve my project better so, I wanna simulating my module on the screen . Would you mind to get sketch source? (processing.org) . thanks
    momoco2002@naver.com

    ReplyDelete
    Replies
    1. Thank you. You can get the processing code from the above download link.

      Delete
    2. This comment has been removed by the author.

      Delete
    3. download link source is matlab.
      I want to get proccesing2 sketch soure. please
      Would you mind to get sketch source?,
      because, i like your design of processing sketch.
      i hope help me.

      Delete
    4. Look at the "Code" section, file "avr_lib_mpu6050_03.zip". You should find the processing folder, which contains the processing sketch.

      Delete
    5. oh.. very very thank you^^

      Delete
  56. This comment has been removed by the author.

    ReplyDelete
  57. This comment has been removed by the author.

    ReplyDelete
  58. Hi, i've go a little problem. When i put my board on flat surface and have 0 degress on all axe's and then i start to rotate around y-axis (pitch) there is a problem. When i hit 90 degres on the pitch angle, the roll and yaw axis accidentaly change to -120 degress. When i rotate around x (roll), the pitch and yaw doesn't change. The same when i rotate around z, the pitch and roll also doesn't change. The problem is only while roatating around y-axis (pitch). What is strange the cube is rotating properly, only the angles displayed under the cube are wrong. Do you havy any idea why?

    ReplyDelete
    Replies
    1. If you can't imagine what i'm talking about I can record a video, you will see what I mean.

      Delete
    2. I suppose you are using the wrong attiture formula, there is some sign wrong (- or +). In the processing script you should find comments about how does the quaternion to euler works, check it out.

      Delete
  59. Hi. Davide
    my tarket system is atmega128
    When I compile below source, Its doesnt work well.( "MPU6050_GETATTITUDE == 1 " sentance work same as well as yours)
    I cant find the problem so would you check my code, I have no idea what is wrong with my code.


    void TX0_CH(char ch){ while(!(UCSR0A&0x20)); UDR0=ch; }
    void TX0_STR(char *str){ while(*str)TX0_CH(*str++); }



    for(;;)
    {
    while(!flag); flag=0;

    sprintf(str,"%7.3f%7.3f%7.3f%7.3f%7.3f%7.3f%7.3f\r\n",qw,qx,qy,qz,roll,pitch,yaw);
    TX0_STR(str);
    _delay_ms(100);
    }


    at result out is

    -0.149 -0.340 0.594 0.714 1.486 0.724 -2.883

    -0.151 -0.342 0.593 0.713 1.486 0.729 -2.884

    -0.153 -0.344 0.592 0.713 1.485 0.735 -2.884

    -0.155 -0.345 0.591 0.713 1.485 0.740 -2.885

    -0.157 -0.347 0.590 0.712 1.484 0.746 -2.885

    -0.158 -0.348 0.589 0.712 1.484 0.751 -2.886


    -0.161 -0.350 0.588 0.711 1.484 0.757 -2.887

    -0.162 -0.351 0.587 0.711 1.483 0.762 -2.887

    -0.164 -0.353 0.586 0.710 1.483 0.768 -2.888

    -0.166 -0.355 0.585 0.710 1.482 0.774 -2.889

    ReplyDelete
    Replies
    1. Unfortunately, i can not check your code, you have to do it by yourself. Debug at first the raw value, check at first accell and gyro values. Then check if it is the conversion to quaternion or to euler angles that does not works.

      Delete
    2. thanks,
      um...

      would you mind to get atemga128 hex file?

      Delete
    3. I can give you the hex for the ATmega168. There are a few timer register to change for the ATmega128, and if i change thos, i've to check it. Compile it using avrgcc, you should not have problem.

      Delete
    4. hi...davide

      edited Register atmega128 timer which linked source as below.
      #if MPU6050_GETATTITUDE == 1
      TCCR0=7; TIMSK=1; //16000000/1024/256=61Hz=16.384ms <---------변경(system)
      #endif
      when data received (5700) its oupted as below ( Receive data type:ASCII)
      data bit 8
      stop bit 1
      parity none

      衾?옶
      K?0k=>?? ?핅NL옙" ?
      ??밡K?!둈>6;?? 픥MP퓉쑌?
      춫?롆J??K>(㉢>땟 ?갩퓋 !?
      憾??J?m S>U댌>쟛 ?XX옰 ?

      촋? ???Z>뱱?? ?M\왔 ?

      篆??I?혣a>彌?秊 ??`욍Y =

      檻>B?? ?>g좀>"v
      웹.d엘$E=

      췒?%KH?륥p
      >b戟>? 픖%h?K?

      ?
      ?梳G?컟w>d纜>?
      윳 l왐b?

      寺?F1G?즸~>왻?+?픡?엶8?

      ??苕F???핢? ?웸#s?輒=

      쳥?f F?] ? 듓>蔞 픛?풧 >

      稈>?E?"퀔>,꺡> ?픊썍옇?>

      y>읩D?괚?뭭?맲 ?I~??
      ->

      _"?Z.D?俚?
      쾎?됝 픴??mC>

      ??r귽?쮐?%M?2 윷퐘퓎?>

      rq?q??J?>I/?? ?}꽴" q>

      i뤢>?B?????? 핓7녉듳?


      development enviorment : avrstudio4.19
      compiler :AVR Toolchain(recent version)

      is there any linker option to set up?

      Delete
    5. Please, do not flood with code, use something like pastebin, or this thread will became too heavy to load.
      As i tell you, use avrgcc. Also, load libm in your linker (-m option).

      Delete
  60. Hey guys I have a really dumb questions! How do you construct a quaternion from the raw data without first calculating the euler angles?

    ReplyDelete
    Replies
    1. Hello,
      The simple answer is, at first transform raw to consistent data, such as acceleration, and gyroscopic acceleration, then using the Mahony alghorim you can found the quaternion. Then, if you want to understand how the Mahony works, the original report about the Madgwick alghortims, which is the one Mahony is based on, can be found here: http://www.x-io.co.uk/res/doc/madgwick_internal_report.pdf
      Also an interesting comparison on those filers can be read here: http://www.olliw.eu/2013/imu-data-fusing/, and there are many other paper online about this arguments.

      Delete
  61. Hello Davide,
    Now I have the project about the maze game. I want to control the ball on TFT screen by using MPU6050. (ATmega128) How to connect the MPU6050 and ATMEGA128? and I try to complile your code in AVR Studio but it always show the error so how to the code use it in AVR Studio?
    Thanks

    ReplyDelete
    Replies
    1. Hello, you have to include header and code files, then build a makefile and compile it. This code is for ATmega168 and 328, for 128 there could be something to change, but you have to try it.
      The code here is compiled using avrgcc. Check above comments about how to compile.

      Delete
    2. I try to compile but it show this error:
      ../src/mpu6050/mpu6050.c: In function `mpu6050_writeBytes':
      ../src/mpu6050/mpu6050.c:69: error: 'for' loop initial declaration used outside C99 mode
      ../src/mpu6050/mpu6050.c: In function `mpu6050_init':
      ../src/mpu6050/mpu6050.c:487: error: `TCCR0B' undeclared (first use in this function)
      ../src/mpu6050/mpu6050.c:487: error: (Each undeclared identifier is reported only once
      ../src/mpu6050/mpu6050.c:487: error: for each function it appears in.)
      ../src/mpu6050/mpu6050.c:487: error: `TIMSK0' undeclared (first use in this function)

      So how to fix this
      Thanks.

      Delete
    3. TCCR0B and TIMSK0 are ATmega168 and 328 Timer register, you have to set you ATmega version register timer. Again read comments above for timer register information.

      Delete
    4. Thanks but I test the MPU with your processing file but it is nothing happened! (it cannot read data , shows 0, 0, 0) so I want to know that I connected wrong wiring or not. For atmega128. VCC >> 3.3v, GND >> GND, SDA >> SDA, SCL >> SCL, AD0 >> GND, INT >> INT4 (I also use int0 in project so I change it to int4 and already change int0 to int4 in your .h file) and compile with avr studio. Or I must config anything else?

      Delete
    5. At first try to debug using simple serial terminal, then try processing connection.

      Delete
  62. Hi DG :)
    first i want to say greaat joob ! tank you
    i download the last lib 03.zip
    but when i tryed to complie it whit a atmega16a i got a lots of error !
    for example : error on

    #define MPU6050_TIMER0INIT TCCR0B |=(1<<CS02)|(1<<CS00); \
    TIMSK0 |=(1<<TOIE0);

    and i changed it to this :

    #define MPU6050_TIMER0INIT TCCR1B |=(1<<CS02)|(1<<CS00); \
    TCNT1 |=(1<<TOIE0);

    is it true ?
    and now i got a many errors too.
    for example :

    UART0_DATA undeclared
    UART0_STATUS undeclared
    ....

    ReplyDelete
    Replies
    1. Hello and thank you. If you look at other comments other have compiled it for ATmega16, you have to change some registerns, one is the timer register like the one you changed. Note that is not the TCNT1 register you have to change instead of the TIMSK0. Take a look at the datasheet, and build a simple program to understaind the use of TIMER.
      Also, the fact that UART0_DATA is undeclared make me things you are not setting the proper micro in your compiler. Look at the uart.c file from the P.Fleury library, UART0_DATA is the UDR register, that you should have load on compiler header for you micro.
      Split your project in small step: 1: build a Timer test project, 2: build a uart test project. Then you will understaind where are the points you have to change for using this library on ATmega16.

      Delete
  63. This comment has been removed by the author.

    ReplyDelete