luisrodenas

Arduino Sketch to automatically calculate MPU6050 offsets

56 posts in this topic

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 by luisrodenas

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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 ! ;)

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

 

 

post-1497-0-75145400-1395337508_thumb.jpg

post-1497-0-65835100-1395337510_thumb.jpg

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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. :-(

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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!

Share this post


Link to post
Share on other sites

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.
luisrodenas and TheEnginerd like this

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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;

 

???

Share this post


Link to post
Share on other sites

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 !!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now