luisrodenas Posted January 7, 2014 Report Share Posted January 7, 2014 (edited) I have made an Arduino sketch that simplifies the task of calibrating the MPU6050's offsets. Easy steps: - Wire your MPU6050 to your Arduino. - Put the MPU6050 as horizontal as possible and leave it there, don't touch it. - Check the sketch in order to configure your MPU's I2C address (0x68 or 0x69). - Upload the sketch to your Arduino. - Open Arduino serial monitor and send any character to the Arduino. - Wait. - Write down your offsets for that particular MPU6050 and use them with library's functions "...setoffset..." in your projects. There are also a few options in the code in case you want to fine tune it. There may be bugs, or maybe it does not converge for everyone, so let me know your experience. I use it with an Arduino DUE, configured to 400KHz I2C bus speed, but I think you can use any Arduino and standard bus speed (100KHz). If people find it useful maybe Jeff can add it to the library once it is bugfree. Happy new year. UPDATE 30th January: New version 1.1 available. It fixes a bug related to variables overflowing in Arduinos other than the DUE. MPU6050_calibration_v1.1.zip Edited January 31, 2014 by luisrodenas Ekbergdub, swordfish, Johnnydofs and 8 others 11 Quote Link to comment Share on other sites More sharing options...
violinuxer Posted January 10, 2014 Report Share Posted January 10, 2014 Great program you've got working here, should save me a lot of trouble! The one issue that I have is that the I2C address of the MPU6050 object is incorrectly set to 0x69 by default, this is NOT the default address of the IMU (i'm pretty sure it should be 0x68). It took me the longest time to figure out why my sensor wasn't connecting Thanks! violinuxer swordfish and elizabethds60 1 1 Quote Link to comment Share on other sites More sharing options...
luisrodenas Posted January 13, 2014 Author Report Share Posted January 13, 2014 Thanks for the feedback Violinuxer! Sure, I forgot to mention that step, topic edited. I am using several MPUs so I was bored of calibrating all of them by hand. Quote Link to comment Share on other sites More sharing options...
rflmota Posted January 29, 2014 Report Share Posted January 29, 2014 Hi luisrodenas, I tried your sketch but without success... I even set your parameters acel_deadzone and giro_deadzone to large values but i can't get the MPU-6050 to converge to a value for the offset, it just stays printing three dots forever... Can you help me with this?! Thanks in advance ! Quote Link to comment Share on other sites More sharing options...
luisrodenas Posted January 30, 2014 Author Report Share Posted January 30, 2014 Hi rflmota, What arduino are you using? How is your MPU placed when you are running the sketch? It must be completely still. Did you change anything on Jeff's library? Try this: Where the calibration() functions is defined, change the Serial.println("..."); to Serial.print(mean_ax); Serial.print("\t"); Serial.print(mean_ay); Serial.print("\t"); Serial.print(mean_az); Serial.print("\t"); Serial.print(mean_gx); Serial.print("\t"); Serial.print(mean_gy); Serial.print("\t"); Serial.println(mean_gz); Copy what is printed to your console to a file and attach it here. Quote Link to comment Share on other sites More sharing options...
rflmota Posted January 30, 2014 Report Share Posted January 30, 2014 Hi luisrodenas, thank you for your attention! I must say that I'm using an Arduino Leonardo and I'm running the sketch for calibration according to your instructions on the first post, in a plain horizontal table and completely as possible still. I'm using the Jeff's library as it is distributed with none modifications as your sketch, the only thing I changed was the I2C address to be 0x68 to work with my breakout board for MPU-6050. I ran your sketch with the default parameters: int buffersize=1000; //Amount of readings used to average, make it higher to get more precision but sketch will be slower (default:1000) int acel_deadzone=8; //Acelerometer error allowed, make it lower to get more precision, but sketch may not converge (default:8) int giro_deadzone=1; //Giro error allowed, make it lower to get more precision, but sketch may not converge (default:1) I ran it for about 10 minutes and the output I get through the serial port was recorded in the file attached. It seems to me that this condition, if (abs(16384-mean_az)<=acel_deadzone) ready++; else az_offset=az_offset+(16384-mean_az)/acel_deadzone; never occurs, so I believe that's why I can't get a sucessfull calibration from your sketch. Anyway I appreciate your help and your share of this sketch. Keep up with the good work! MPU6050_calibration_sketch_output.txt swordfish 1 Quote Link to comment Share on other sites More sharing options...
luisrodenas Posted January 31, 2014 Author Report Share Posted January 31, 2014 I have an Arduino Leonardo somewhere, I am going to try it. Anyway, calibration shouln't take more than 1 minute with default settings. Quote Link to comment Share on other sites More sharing options...
luisrodenas Posted January 31, 2014 Author Report Share Posted January 31, 2014 Fixed!! There was a bug in the sketch. Variables were overflowing in 8-bit Arduinos, like the UNO or Leonardo. Now it works fine in my Leonardo, but took a while to converge, 2-3 minutes. Thank you for your contribution and let me know if it works for you now. Quote Link to comment Share on other sites More sharing options...
edorphy Posted February 4, 2014 Report Share Posted February 4, 2014 I tried this out and it improved my mpu data fusion tremendously, however the RMS of the accelerations can now be greater than 1 at rest. Theory says something like the following: sqrt( sq(accelX/accel_sensitivity) + sq(accelY/accel_sensitivity) + sq(accelZ/accel_sensitivity) ) while at rest the only acceleration felt by the system would be 1 G (gravity itself), therefore the above equation should be "exactly" 1. It has been one of my tests while at rest. Not sure if it would be something you would like to incorporate into your calibration algorithm. It shouldn't affect things too vastly, but thought it was worthy of mention. Quote Link to comment Share on other sites More sharing options...
luisrodenas Posted February 5, 2014 Author Report Share Posted February 5, 2014 Well, I believe that BEFORE calibration, gravity vector length at rest will not be 1g exactly, due to sensor imperfections, where you are in Earth, etc. Ofcourse we could try to implement something to make it be as close as possible to 1g, I don't know if it will improve DMP's measure, but we can try. If the internal algorithm is using the three coordinates of gravity vector, I believe it is using its angle, and doesn't care about its length, as long as the vector is not distorted. But maybe I am wrong. I'll test it out when I have some free time. Thanks Quote Link to comment Share on other sites More sharing options...
cbandera Posted March 18, 2014 Report Share Posted March 18, 2014 Hi luisrodenas, it seems like I still have the "non converging" error. I've downloaded the code today, so I assume I have the newest version. Just what irritates me, is that my Outputs seem to be much higher, than rflmota's: 1074 2179 15557 -2636 -1035 -1034 ... -1232 -251 17762 2482 1012 1014 ... 1072 -255 15555 -2636 -1035 -1034 ... -1230 -254 15555 2483 1012 1013 ... 1074 -260 17768 -2637 -1037 -1035 Also, when I tried to play this simple sketch: Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); Serial.print("\n"); accelgyro.setXGyroOffset(0); accelgyro.setYGyroOffset(0); accelgyro.setZGyroOffset(0); Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); My output looks like this: 194 194 194 194 194 194 Which makes me think, that maybe my error lies within the setZGyroOffset-function already. Does anyone have any thoughts about this for me? Anyone recognises where my fault lies? Thx, cbandera Quote Link to comment Share on other sites More sharing options...
farhan Posted March 20, 2014 Report Share Posted March 20, 2014 Hi, I have tried with this sketch but unfortunately it was not successful. I am using Moteino ( Arduino clone) with mpu-6050. I run it for about 15 minutes or so and got the attached outputs. (2 different outputs, as tried two times) Could you please suggest something to solve the issue on urgent basis? Looking Forward anxiously. FARHAN Quote Link to comment Share on other sites More sharing options...
savida Posted April 8, 2014 Report Share Posted April 8, 2014 Hi I have a couple of questions about calibration. I am using a MPU6050 on a Raspberry Pi with perl. I understand the calibration part where one gets averages over a largish number of samples. What I don't understand is what is done to those averages before stuffing into registers. I assume that the registers in question are *G_OFFS_TC, or is it *G_OFFS_USR, and *A_OFFS ? Secondly, once one has those offsets, do you poke them on each power up or are the settings persistant? TIA Quote Link to comment Share on other sites More sharing options...
savida Posted April 8, 2014 Report Share Posted April 8, 2014 Well it seems they are persistant. However I seem to have bricked the thing. accel_x always gives 32767. I have tried a device reset to no avail. :-( Quote Link to comment Share on other sites More sharing options...
savida Posted April 9, 2014 Report Share Posted April 9, 2014 Phew! Not bricked. It seems if you set the accelerator offsets to zero then you get 32767 back. The above text converted to perl converges fine, but I had to make a modification. The problem with the above is that it will keep trying until the count is 6. All well and good but it will retry one it has already got right and increment the counter wrongly. ie four could have converged, the fith not and the sixth twice. What I did was set ready to zero then for each item if it had converged I set a different bit on in ready and quit when ready == 0xFC. Thaqnks for the code base. Quote Link to comment Share on other sites More sharing options...
luisrodenas Posted April 10, 2014 Author Report Share Posted April 10, 2014 It you have some time it would be nice if you merged your changes with base code. Quote Link to comment Share on other sites More sharing options...
savida Posted April 10, 2014 Report Share Posted April 10, 2014 Well my code is perl not C, but if I knew where the base code was and had write access I could contribute untested C based on the perl. Basically I changed the string of "ifs" that check for convergence. if ( abs mean_accel_x <= accel_dead_zone ) { ready++;; } else to if ( abs mean_accel_x <= accel_dead_zone ) { ready |= 0x80; } else And the exit from the loop to if (ready == 0xfc) break ; Each subsequent check uses the next bit, so the next tests set 0x40, 0x20, 0x10, 0x08 & 0x04 which or'ed together give 0xfc. The problen with the existing code is that "ready" can get incremented more than once by the same test on a subsequent loop iteration and therefore reach 6 before all six axis have converged. BTW anyone know where the /8 and /4 before stuffing into the registers is documented? Quote Link to comment Share on other sites More sharing options...
tom.svilans Posted April 25, 2014 Report Share Posted April 25, 2014 Hi, Thanks a lot for this sketch, seems like it's just what I needed for calibrating my MPU6050. It compiles fine, but then freezes in the calibration() loop. It runs through it a couple of times but then just stops in the middle of the meansensors() loop before it converges. I tested it by putting Serial.print(i); Serial.print('\t'); Serial.print(buffersize + 101); Serial.print('\n'); so that I can see where it hangs... Any ideas? I've read a little about i2c freezing sometimes? Is there a way to solve this? Perhaps an alternate library that I could use? Thanks! Quote Link to comment Share on other sites More sharing options...
dennisma Posted May 2, 2014 Report Share Posted May 2, 2014 Thanks this worked well first time. I made a slight modification to your code. In the loop() where it prints out the offsets I changed it to the following: Serial.println("Your offsets:\t"); Serial.print("mpu.setXGyroOffset("); Serial.print(gx_offset); Serial.println(");"); Serial.print("mpu.setYGyroOffset("); Serial.print(gy_offset); Serial.println(");"); Serial.print("mpu.setZGyroOffset("); Serial.print(gz_offset); Serial.println(");"); Serial.print("mpu.setXAccelOffset("); Serial.print(ax_offset); Serial.println(");"); Serial.print("mpu.setYAccelOffset("); Serial.print(ay_offset); Serial.println(");"); Serial.print("mpu.setZAccelOffset("); Serial.print(az_offset); Serial.println(");"); The output then becomes the following: Sensor readings with offsets: 4 2 16388 0 0 -2 Your offsets: mpu.setXGyroOffset(37); mpu.setYGyroOffset(-44); mpu.setZGyroOffset(26); mpu.setXAccelOffset(-1282); mpu.setYAccelOffset(-727); mpu.setZAccelOffset(1732); That way I can just copy/paste/format the code and I am done. Just a thought. TheEnginerd and luisrodenas 2 Quote Link to comment Share on other sites More sharing options...
nturley Posted May 15, 2014 Report Share Posted May 15, 2014 Hey this is really awesome stuff!I tried it out with a pinoccio board. (Check em out, they're new: https://pinocc.io/) Which uses an ATMega256RFR2 and I am unfortunately getting results that don't seem to be working. I changed the code as shown about to print mean values and get outputs that look like the following: 77 -1 -1 -1 -1 -1 210 -1 -1 -1 -1 -1 92 -1 -1 -1 -1 -1 102 -1 -1 -1 -1 -1 105 -1 -1 -1 -1 -1 91 -1 -1 -1 -1 -1 87 -1 -1 -1 -1 -1 109 -1 -1 -1 -1 -1 166 -1 -1 -1 -1 -1 112 -1 -1 -1 -1 -1 87 -1 -1 -1 -1 -1 104 -1 -1 -1 -1 -1 98 -1 -1 -1 -1 -1 227 -1 -1 -1 -1 -1 This seems... Odd? I'm not sure what expected behavior is. I'll try it out with an UNO, and see what I get, then maybe dig in to the code further.Thanks for all the work, this is really great. Quote Link to comment Share on other sites More sharing options...
ankur6ue Posted August 23, 2014 Report Share Posted August 23, 2014 Why are we dividing by 8 and 4 before setting the offsets? Where is that documented? Or is just a step to prevent wide changes in the offset and help the optimization converge? Johnnydofs, CharlesnurE and Melika Barzegaran 3 Quote Link to comment Share on other sites More sharing options...
jrlin Posted September 12, 2014 Report Share Posted September 12, 2014 Hello, Quote Link to comment Share on other sites More sharing options...
jrlin Posted September 12, 2014 Report Share Posted September 12, 2014 Just wondering if anyone knows why we are diviing by 8 and 4 in the cailbration function void calibration(){ ax_offset=-mean_ax/8; ay_offset=-mean_ay/8; az_offset=(16384-mean_az)/8; ??? Melika Barzegaran 1 Quote Link to comment Share on other sites More sharing options...
iceman222 Posted September 24, 2014 Report Share Posted September 24, 2014 Thanks for sharing! Quote Link to comment Share on other sites More sharing options...
Zakflow Posted October 1, 2014 Report Share Posted October 1, 2014 Thanks a lot luisrodenas, I had a 45° drift on z axis and had no idea how to find the offsets, now it's around 0.13° it's amazing your sketch works great thanks you very much !! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.