Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calibrate Accelerometer #120

Open
Stips123 opened this issue Mar 1, 2017 · 45 comments
Open

Calibrate Accelerometer #120

Stips123 opened this issue Mar 1, 2017 · 45 comments

Comments

@Stips123
Copy link

Stips123 commented Mar 1, 2017

Dear Kris,

thank you so much for this beautiful library!
Anyhow, I have a small question. I only need acceleration data in my project, but I don't know how to calibrate the IMU.
my Code so far:

#include <Wire.h>
#include <MPU9250.h>

MPU9250 myIMU1;


void setup() {
	Serial.begin(115200);
	Wire.begin();

	myIMU1.initMPU9250();

	myIMU1.writeByte(myIMU1.sensorAdresse, SMPLRT_DIV, 0);

	myIMU1.getAres();
	myIMU1.getGres();
}


void loop() {
	myIMU1.readAccelData(myIMU1.accelCount);
	myIMU1.ax = (float)myIMU1.accelCount[0] * myIMU1.aRes -myIMU1.accelBias[0];
	myIMU1.ay = (float)myIMU1.accelCount[1] * myIMU1.aRes -myIMU1.accelBias[1];
	myIMU1.az = (float)myIMU1.accelCount[2] * myIMU1.aRes -myIMU1.accelBias[2];

	Serial.print(myIMU1.ax);
	Serial.print('\t');
	Serial.print(myIMU1.ay);
	Serial.print('\t');
	Serial.println(myIMU1.az);
}

The problem is that sqrt(ax^2 + ay^2 + az^2) is not 1 when I don't move the IMU. Can you please tell me, how to calibrate the Sensor? (The problem is still there, if I use the "-myIMU1.accelBias[0];" or not!).
Here are the values with respect to which axis is pointing into the direction of gravity:
grafik
Thank you!!

Additionally, it would be nice if you could tell me, how to change the sensors full-scale-range to ± 8g. I changed the code in the MPU9250.cpp file, line185:

c = c & ~0x18;  // Clear AFS bits [4:3]
  Ascale = 3;
  c = c | Ascale << 3; // Set full scale range for the accelerometer 
  writeByte(sensorAdresse, ACCEL_CONFIG, c); // Write new ACCEL_CONFIG register value

but I don't feel that this is how it is meant to be ;)

Steffen

@kriswiner
Copy link
Owner

Check here for an accel/gyro calibration function:

https://github.com/kriswiner/MPU-9250/blob/master/MPU9250_MS5637_AHRS_t3.ino

and adapt as needed.

@Stips123
Copy link
Author

Stips123 commented Mar 1, 2017

Thanks for the fast reply! I really appreciate it.
Do you mean, that I have to adapt the code for the MPU9250.h library, or do you advice to use the library in your link (cause it's more up-to-date)?
btw you definitely get the beer if we'll ever meet =)

@kriswiner
Copy link
Owner

I don't use Sparkfun's library even though they based it one one of my sketches. They chose a really old sketch for some reason that had some errors and omissions. The sketch I linked to is more up to date, has accel/gyro as well as mag calibration and I recommend you use it.

Well, virtual beer is OK too!

@Stips123
Copy link
Author

Stips123 commented Mar 2, 2017

thanks for the link!
is the calibration permanently stored in the MPU, or do I have to calibrate every single time I (re-)start the Arduino? Or is it necessary to place the IMU on flat ground at all?
I'm asking because I can't place the IMU on solid ground everytime in my application (it's rigidly attached to sth).
Cheers! =)
grafik

@kriswiner
Copy link
Owner

Thanks for the beer. You can calculate the offset bias calibrations and store them in your sketch to avoid calibrating each time.

For gyro and accel the device should be motionless and flat. Fir mag calibration, you have to move the device around to sample all of the 3D response surface. If you print out the calibration values on the serial monitor, you can just subtract these from your data stream on subsequent startup without having to calibrate anymore unless the environmental conditions (location and temperature, mostly) change.

@Stips123
Copy link
Author

Stips123 commented Mar 3, 2017

hey,
thanks for your answer. Something strange is happening here: The x- and y-axes are working fine. Sometimes the z-axis is working correctly which means it is +1 g or -1 g, if the +z or -z-axis is parallel to gravity, respectively. But sometimes, the output is 0 g and -2 g at rest, and I don't know why (as you see in the graphs above). Have you ever observed such a behaviour?
Thanks!

@kriswiner
Copy link
Owner

Yes, there is a bug in the calibration code. The calibration has to be done with the sensor facing up in order to get the correct calibration.

@Stips123
Copy link
Author

Stips123 commented Mar 4, 2017

lol, that's good to know.

@NickMortimer
Copy link

Hi I'm looking through your excellent calibration information. I'm trying out the sketch from above. I have installed the <i2c_t3.h> library but I'm getting this compile errors. Mainly round wire not being defined. I see that the wire.h is commented out but un-commenting still gives errors. Am I missing something?

@iamchrisb
Copy link

@NickMortimer can you post the exact error message after uncommenting the header file?

@kriswiner
Copy link
Owner

kriswiner commented Jul 21, 2017 via email

@NickMortimer
Copy link

Ah sorry for the delay I have been what we say here in Australia out in the bush! I'm using Pro mini but I'm ordering Teensy right now!

@NickMortimer
Copy link

So I have un-commented the wire and taken out i2c_t3.h and get the following, seems to be a problem with I2C_MASTER not being defined. could be me?

C:\Users\mor582\Documents\Arduino\myIMU\myIMU.ino: In function 'void setup()':

myIMU:312: error: 'I2C_MASTER' was not declared in this scope

Wire.begin(I2C_MASTER, 0x00, I2C_PINS_16_17, I2C_PULLUP_EXT, I2C_RATE_400);

          ^

myIMU:312: error: 'I2C_PINS_16_17' was not declared in this scope

Wire.begin(I2C_MASTER, 0x00, I2C_PINS_16_17, I2C_PULLUP_EXT, I2C_RATE_400);

                            ^

myIMU:312: error: 'I2C_PULLUP_EXT' was not declared in this scope

Wire.begin(I2C_MASTER, 0x00, I2C_PINS_16_17, I2C_PULLUP_EXT, I2C_RATE_400);

                                            ^

myIMU:312: error: 'I2C_RATE_400' was not declared in this scope

Wire.begin(I2C_MASTER, 0x00, I2C_PINS_16_17, I2C_PULLUP_EXT, I2C_RATE_400);

                                                            ^

C:\Users\mor582\Documents\Arduino\myIMU\myIMU.ino: In function 'void loop()':

myIMU:521: error: 'MadgwickQuaternionUpdate' was not declared in this scope

 MadgwickQuaternionUpdate(-ax, ay, az, gx*PI/180.0f, -gy*PI/180.0f, -gz*PI/180.0f,  my,  -mx, mz);

                                                                                                ^

C:\Users\mor582\Documents\Arduino\myIMU\myIMU.ino: In function 'void MS5637PromRead(uint16_t*)':

myIMU:1219: error: 'I2C_NOSTOP' was not declared in this scope

       Wire.endTransmission(I2C_NOSTOP);        // Send the Tx buffer, but send a restart to keep connection alive

                            ^

C:\Users\mor582\Documents\Arduino\myIMU\myIMU.ino: In function 'uint32_t MS5637Read(uint8_t, uint8_t)':

myIMU:1233: error: 'I2C_NOSTOP' was not declared in this scope

     Wire.endTransmission(I2C_NOSTOP);        // Send the Tx buffer, but send a restart to keep connection alive

                          ^

C:\Users\mor582\Documents\Arduino\myIMU\myIMU.ino: In function 'uint8_t readByte(uint8_t, uint8_t)':

myIMU:1340: error: 'I2C_NOSTOP' was not declared in this scope

Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive

                    ^

C:\Users\mor582\Documents\Arduino\myIMU\myIMU.ino: In function 'void readBytes(uint8_t, uint8_t, uint8_t, uint8_t*)':

myIMU:1352: error: 'I2C_NOSTOP' was not declared in this scope

Wire.endTransmission(I2C_NOSTOP); // Send the Tx buffer, but send a restart to keep connection alive

                    ^

exit status 1
'I2C_MASTER' was not declared in this scope

@kriswiner
Copy link
Owner

kriswiner commented Jul 25, 2017 via email

@Bobur23
Copy link

Bobur23 commented Aug 16, 2017

Hello Kris! I have been wondering how to calibrate MPU9250 on Unity. I am using Serial, Madgwick source codes

@kriswiner
Copy link
Owner

kriswiner commented Aug 16, 2017 via email

@NickMortimer
Copy link

Hi Kris, Sorry to bother you again I'm having real problems getting my calibration to work. I have a 9 DOF using on the inside of a large and very magnetic statue of the Moon. The 9 DOF is on the lighting system inside the moon.

I have attached some output. I would really value your opinion!

It's a standard ax,ay,az,gx,gy,gz,hx,hy,hz format

Thanks
moon2.zip

Nick

@NickMortimer
Copy link

Ok I think my problem is that the statue is fixed and my light assembly moves that is the worst possible combination

"It is also important to recognize that effective compensation of hard- and soft-iron distortions is dependent upon the distorting material(s) rotating/moving with the sensor. An example would be mounting the sensor in an aircraft; any materials that are part of the aircraft that exhibit a distorting effect would move as the aircraft and mounted sensor move, and it would generally be possible to compensate for the associated hard- and soft-iron effects. In contrast, it is much more difficult—if not impossible—to compensate for distorting effects exhibited by material external to the aircraft/sensor platform. Thus, it is important to understand not only how compensation may be applied, but also to recognize those conditions under which effective compensation techniques are not possible."

So that leaves me with a bit of a problem!

Nick

@kriswiner
Copy link
Owner

kriswiner commented Oct 2, 2017 via email

@NickMortimer
Copy link

19621396_10212892259760688_2032012674_n

Thanks once again your input. Here's a picture of the structure, I don't need to be too accurate but as you can see there is a lot of steel on the supports, the light system is inside the globe!

@kriswiner
Copy link
Owner

kriswiner commented Oct 2, 2017 via email

@NickMortimer
Copy link

Yep I was not involved with the design, I wanted shaft encoders on the axis but it was built before I was on board! Yep The cal data I posted is the sensor mounted on the light system. Checking with a standard compass you can get needle reversals at points close to the bottom of the structure!

@NickMortimer
Copy link

figure_5-1
So this is the problem. This was a vertical circle!

@kriswiner
Copy link
Owner

kriswiner commented Oct 4, 2017 via email

@NickMortimer
Copy link

NickMortimer commented Oct 5, 2017

No at this time I can fix the calibration if I'm only interested in one plain as soon as I change the orientation of the sensor and sweep it a gain I get a completely different result mainly because the thing causing the deviation is in a fixed location and thus it's distance to the sensor is varying. I'm going to tell them to get some shaft encoders! Thanks once again for your replies and information!

@PatelKishanJ
Copy link

Hello kris,

  I have used your code with mpu9250 and testing data.

I had some doubt that how can verify data.So,i have verify with android application.

I have comparing data with SENSOR KINETICS (app),and its very different readings.

So,what should be issue?

@kriswiner
Copy link
Owner

kriswiner commented Jan 9, 2018 via email

@PatelKishanJ
Copy link

PatelKishanJ commented Jan 10, 2018

I dont know which one is wrong but one of the two is wrong.
I have used your code as it is,no any additional configuration has done.

So,how can i verify raw data as well as all result of code.(yaw,pitch,roll 9 axis data with particular units)?

And below lines of code shows that sample rate is 1 kHz.

// Configure MPU9250 gyro and accelerometer for bias calculation
i2c_write_data_byte_kt(MPU9250_ADDRESS, CONFIG, 0x01); // Set low-pass filter to 188 Hz
i2c_write_data_byte_kt(MPU9250_ADDRESS, SMPLRT_DIV, 0x00); // Set sample rate to 1 kHz
i2c_write_data_byte_kt(MPU9250_ADDRESS, GYRO_CONFIG, 0x00); // Set gyro full-scale to 250 degrees per second, maximum sensitivity
i2c_write_data_byte_kt(MPU9250_ADDRESS, ACCEL_CONFIG, 0x00); // Set accelerometer full-scale to 2 g, maximum sensitivity

And i have also one another doubt about quaternions.

quaternion is represented by qw + i qx + j qy + k qz.

In your code we can get q[0], q[1], q[2], q[3].
So,can you match this array with w,x,y and z.

Thanks in advanced.

@kriswiner
Copy link
Owner

kriswiner commented Jan 10, 2018 via email

@PatelKishanJ
Copy link

Sorry if i had not respond your question.But i told you.

As you asked me about which one is wrong?
I told that one of two platform can wrong.

I want to verify IMU data.So,from android application we can measure 9-axis data.
And data which we getting from IMU and APPLICATION.Both are different.

So,how can i verify it?.

@nanoTitan
Copy link

Hi Kris,

I went through your accel/gyro calibration with the device at rest, and the magnetometer calibration while performing figure eights. If I rotate the device parallel to the ground, the yaw seems to work well. However, I'm seeing that a change in the roll of the device also causes a large change in the yaw.

Any ideas of what might be causing this or where I can look to fix it?

Thanks so much for putting this library together! I've modified it from your Stm32 Mbed code to use Stm's HAL library for the Stm32f401. If you would like, I can provide that code for you.

@kriswiner
Copy link
Owner

kriswiner commented Feb 27, 2018 via email

@nanoTitan
Copy link

Yes, I can verify my magnetometer data with a 2-D plot like you have in your magnetometer calibration article. I'm not sure of how I would verify accel/gyro data though after running the calibration on those. Any tips on that would be great. I do see that the accel/gyro trims are within roughly 1-2% of factory settings.

Yes, I believe the data is provided in the N.E.D. orientation. I'm using your example code from here:
https://os.mbed.com/users/onehorse/code/MPU9250AHRS/file/4e59a37182df/main.cpp/

@kriswiner
Copy link
Owner

kriswiner commented Feb 27, 2018 via email

@nanoTitan
Copy link

Ok, I've remapped those ax, ay, az, etc to the order that the filter expects. It looks like it is working much better now. Thanks for that!

For the accel calibration, I'm getting 0.02, 0.01, 1.00 which looks about right. The gyro is giving me values around 0.2, 0.3, 0.01. Are those close enough to zero consider accurate? I'm trying to get this within the 2 degrees of accuracy.

@kriswiner
Copy link
Owner

kriswiner commented Feb 28, 2018 via email

@nanoTitan
Copy link

I'm using a stm32f401 running at 84Mhz. It looks like the Teensy runs at 180Mhz, and I'm guessing I need something close to that to get greater precision.

@kriswiner
Copy link
Owner

kriswiner commented Feb 28, 2018 via email

@aabdulkadar
Copy link

I have problem with my mpu 9250 .I use this code( https://github.com/kriswiner/MPU-9250/blob/master/MPU9250_MS5637_AHRS_t3.ino) to calibrate .But the values are not changing and I used to get these in serial monitor

Gyro temperature is 30.8 degrees C
Digital temperature value = 20.00 C
Digital temperature value = 68.00 F
Digital pressure value = 0.00 mbar
Altitude = 145366.45 feet
Yaw, Pitch, Roll: 13.80, 0.00, 0.00
Grav_x, Grav_y, Grav_z: 0.00, 0.00, 1000.00 mg
Lin_ax, Lin_ay, Lin_az: 0.00, 0.00, -1000.00 mg
rate = 6978.08 Hz
ax = 0.00 ay = 0.00 az = 0.00 mg
gx = 0.00 gy = 0.00 gz = 0.00 deg/s
mx = 0 my = 0 mz = 0 mG
q0 = 1.00 qx = 0.00 qy = 0.00 qz = 0.00

Please help me.I am new

@aabdulkadar
Copy link

always zero irrespective of the movements !!

@kriswiner
Copy link
Owner

kriswiner commented Jun 20, 2018 via email

@aabdulkadar
Copy link

Thank you for the fast response.

I am reading like what I written below

/ If intPin goes high, all data registers have new data
if(newData == true) { // On interrupt, read data
newData = false; // reset newData flag
readMPU9250Data(MPU9250Data); // INT cleared on any read
readAccelData(accelCount); // Read the x/y/z adc values

// Now we'll calculate the accleration value into actual g's
ax = (float)MPU9250Data[0]*aRes - accelBias[0];  // get actual g value, this depends on scale being set
ay = (float)MPU9250Data[1]*aRes - accelBias[1];   
az = (float)MPU9250Data[2]*aRes - accelBias[2];  

readGyroData(gyroCount); // Read the x/y/z adc values

// Calculate the gyro value into actual degrees per second
gx = (float)MPU9250Data[4]*gRes;  // get actual gyro value, this depends on scale being set
gy = (float)MPU9250Data[5]*gRes;  
gz = (float)MPU9250Data[6]*gRes;   

readMagData(magCount);  // Read the x/y/z adc values

// Calculate the magnetometer values in milliGauss
// Include factory calibration per data sheet and user environmental corrections
if(newMagData == true) {
  newMagData = false; // reset newMagData flag
  mx = (float)magCount[0]*mRes*magCalibration[0] - magBias[0];  // get actual magnetometer value, this depends on scale being set
  my = (float)magCount[1]*mRes*magCalibration[1] - magBias[1];  
  mz = (float)magCount[2]*mRes*magCalibration[2] - magBias[2];  
  mx *= magScale[0];
  my *= magScale[1];
  mz *= magScale[2]; 
} 

}

@kriswiner
Copy link
Owner

kriswiner commented Jun 21, 2018 via email

@aabdulkadar
Copy link

yes..I checked with 2 and 12 also ..No change

@aabdulkadar
Copy link

I changed intpin to 3 and it works

Digital temperature value = 20.00 C
Digital temperature value = 68.00 F
Digital pressure value = 0.00 mbar
Altitude = 145366.45 feet
Yaw, Pitch, Roll: 280.96, -24.25, -144.30
Grav_x, Grav_y, Grav_z: 532.09, -410.65, -740.44 mg
Lin_ax, Lin_ay, Lin_az: -480.34, 1387.70, -1310.83 mg
rate = 96.03 Hz

but even it is at rest,acceleration values are not zero..?
Thank you for your patience

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants