My first 6 DOF IMU Sensors Fusion Implementation: ADXL345, ITG3200, Arduino and Processing
When you have created two breakout boards for the ADXL345 accelerometer and the ITG3200 gyroscope and you have those two nice sensors what you can do? Simple: create an implementation of an Attitude sensor fusion which runs with those chips!
So, I started documenting myself and reading lot of stuff on IMUs (inertial measurement units - composed by an accelerometer and a gyroscope) and MARG sensor (an IMU which also has a magnetometer to sense heading).
One really good article you should read to get started with IMUs is A Guide To using IMU (Accelerometer and Gyroscope Devices) in Embedded Applications available on http://www.starlino.com/ . Also from the same website there is a nice implementation of the theory from the IMU guide: you can find it on Arduino code for simplified Kalman filter. Using a 5DOF IMU.
So, I took the algorithm above and converted it to be used with the ADXL345 and the ITG3200. I came out with two implementations both with parts in Arduino and Processing code (see the attachments to this page below).
IMPORTANT: If you use the IMU Digital Combo Board from Sparkfun you will need to change the address of the Gyroscope from 0x69 in my code to 0x68.
The first implementation simply reads the raw accelerometer and gyroscope values on the Arduino while the Processing code (running on the PC) will compute the sensor fusion algorithm, produce the orientation vector and siplay a nicely oriented cube.
In other implementation all the sensor fusion logic is implemented in Arduino code so it will run embedded in the microcontroller. Looks like Arduino can coupe with that without any problems! So, once the orientation is computed is all sent to the PC where the Processing application will display incoming data and the oriented cube.
You can see a demonstration in the following video:
All the code is available in the attachments below. You can see the circuit in the picture below. Note that these are custom made breakout boards, your pin configurations will vary depending on the schematics of your breakout board. If you have questions just leave a comment below.
The processing programs need to be executed on the Processing IDE, available for download from http://processing.org/
Remember to adjust the serial port configuration in the Processing code to match your connection to the Arduino in your system. Here I use /dev/ttyUSB9, if you are under windows you'll probably have to use something like COM3 or something like that. See in the Arduino IDE under Tools->Serial Port to get the exact value you have to use.
| Attachment | Size |
|---|---|
| Arduino Code IMU 6DOF - ADXL345 ITG3200 on chip filter | 15.03 KB |
| Arduino Code IMU 6DOF ADXL345 ITG3200 | 13.64 KB |
| Processing Code | 37.56 KB |
| Processing code for on chip version | 38.77 KB |




...
mmm... not many ideas about this.. sorry. Let me know if you find a solution.
using this code with other IMUs
Hi,
we're using the processing ide code ,with the off chip filter to try and validate our data...
I'll paste the code here... in the processing ide we changed the usb port to 'COM11' and we even tried Serial.list()[0] since we only have one port
(the port is actually a virtual serial port).
we tried changing the baudrate from 9600 to 57600 as well but it didnt work for us..
could please take a look at the arduino code and see if maybe we're sending data the wrong way or something...
because though we can use the serial port monitor on arduino to view our data (and it comes out fine...) we cant seem to get any data on processing ide...
#define GYRO 0x68 // gyro I2C address#define REG_GYRO_X 0x1D // IMU-3000 Register address for GYRO_XOUT_H
#define ACCEL 0x53 // Accel I2c Address
#define ADXL345_POWER_CTL 0x2D
char buffer[12]; // Array to store ADC values
int gyro_x;
int gyro_y;
int gyro_z;
int accel_x;
int accel_y;
int accel_z;
int i;
int c;
char str[512];
#include
void setup(){
Serial.begin(9600);
c=0;
Wire.begin();
// Set Gyro settings
// Sample Rate 1kHz, Filter Bandwidth 42Hz, Gyro Range 2000 d/s
writeTo(GYRO, 0x16, 0x0F);
//set accel register data address
writeTo(GYRO, 0x18, 0x32);
// set accel i2c slave address
writeTo(GYRO, 0x14, ACCEL);
// Set passthrough mode to Accel so we can turn it on
writeTo(GYRO, 0x3D, 0x08);
// set accel power control to 'measure'
writeTo(ACCEL, ADXL345_POWER_CTL, 8);
//set accel right justified range to 16g
writeTo(ACCEL,B00110001,B00000011);
//cancel pass through to accel, gyro will now read accel for us
writeTo(GYRO, 0x3D, 0x28);
}
// Write a value to address register on device
void writeTo(int device, byte address, byte val) {
Wire.beginTransmission(device); // start transmission to device
Wire.send(address); // send register address
Wire.send(val); // send value to write
Wire.endTransmission(); // end transmission
}
void loop()
{// Read the Gyro X, Y and Z and Accel X, Y and Z all through the gyro
// First set the register start address for X on Gyro
Wire.beginTransmission(GYRO);
Wire.send(REG_GYRO_X); //Register Address GYRO_XOUT_H
Wire.endTransmission();
// New read the 12 data bytes
Wire.beginTransmission(GYRO);
Wire.requestFrom(GYRO,12); // Read 12 bytes
i = 0;
while(Wire.available())
{ buffer[i] = Wire.receive();
i++;
}
Wire.endTransmission();
//Combine bytes into integers
// Gyro format is MSB first
gyro_x = buffer[0] << 8 | buffer[1];
gyro_y = buffer[2] << 8 | buffer[3];
gyro_z = buffer[4] << 8 | buffer[5];
// Accel is LSB first. Also because of orientation of chips
// accel y output is in same orientation as gyro x
// and accel x is gyro -y
accel_y = buffer[7] << 8 | buffer[6];
accel_x = buffer[9] << 8 | buffer[8];
accel_z = buffer[11] << 8 | buffer[10];
sprintf(str, "%d,%d,%d,%d,%d,%d,%d", accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z);
Serial.print(str);
Serial.print(10, BYTE);
c++;
// delay(400); // wait for a second
}
p.s the basic code we got from hobbytronics
Hi there, thanks for stopping
Hi there, thanks for stopping by..
The Arduino code you added here uses 9600 speed.. so you have to use that too on the processing program.
I would suggest using the code in the attachment above called "Arduino Code IMU 6DOF ADXL345 ITG3200" which should work with the associated Processing code. Remember to change the address of the sensors in the I2C code to match the setup in your imu.
Btw, which IMU are you using?
thanks for your quick
thanks for your quick reply
we're using the IMU 3000 with adxl 345 ... we got it to work finally... simply had to remove the 256 and 14.35 from the processing side...
your codes been a great help for us in visually validating our imu data...
Thanks again.
code for imu3000 with adxl345
i am also using the same fusion board so can u mail me the code plzz
Hey again Fabio! So, ive got
Hey again Fabio!
So, ive got to code to work thanks to you, but now i need to correct it. The directions are completely wrong for me. Do you know what i need to change in my code please? For example, for the cube to be flat in the program i need to place my device upside down! Can you check my code please as see what's wrong?
http://pastebin.com/v8ixYL7e
Highly appreciate it!
Becky
Without knowing specifically
Without knowing specifically the devices you are using is hard to tell what's wrong in your code. The only thing I would suggest you to check is the fact the the gyro and accelerometer axis on your board aren't aligned, this means that you will have to align them in software.
Sparkfun guys are used in not aligning sensors axis on their boards: I always thought about this as non sense as it adds unneeded complexity without a clear advantage to the user.
Hey again fabio! Sorry i
Hey again fabio!
Sorry i forgot to add the board im using before! Its this one: http://www.sparkfun.com/products/10010
And you're right! The axes arent aligned but through trial and error im getting the board to move in the right directions now :D
But i have a question, my yaw doesnt work at all! Was there something missing in the code i provided, or do i need to change something? (http://pastebin.com/v8ixYL7e)
Thanks for any help!
This code is for gravity
This code is for gravity sensing only.. this means that you won't have informations on the yaw angle, just picth and roll. There are however algorithms which uses accelerometer + gyroscope for yaw, pitch, roll sensing but they suffers from drifting on the yaw angle. See for example the algorithm described in this paper (you will also get some code there).
In order to fix the yaw drifting you need another reference vector, the Earth north sensed by a magnetometer. So, only your board won't be enough. You need to add a magnetometer breakout board or evaluate 9 degrees of measurement (DOM) boards like my FreeIMU.
If i would have known much
If i would have known much earlier about this yaw drifting i would have gotten the 9DOF IMU instead as it seems much better but unfortunately i dont have enough time to change things around :(
Hrmm, regarding the algorithm, i went through the document but, is there an easier way to get a yaw output instead of through matrices and all the complex calculations? As it seems so difficult :/ Maybe you know another document regarding this subject please?
Im sorry if im such a pest, i just rly need some help :(
Everyone, including me will
Everyone, including me will need help from somebody else, sooner or later.. I think that if I help you now, "karma" will provide me with help when I'll need that. Moreover, I feel good helping people.. so you are not a pest at all.
Give a look at the code posted here. You'll find the FreeIMU library which will contain all the sensor fusion algorithm for doing a 9 DOM sensor fusion, which would need a magnatometer.
However, I think that you can just comment out the magnetometer part in the AHRSupdate function in FreeIMU.cpp to only use acc+gyro.
Hehe thanks fabio! Yea, i
Hehe thanks fabio! Yea, i just end up feeling kinda bad when asking for help!
And thanks for that 9DOF website! Im gonna try implement it in my code and get back to you soon :) Thanks again for helping!
My gyro, is not giving me appropriate data
Hi
this is my code for Accelerometer and Gyroscope:
http://pastebin.com/Q4uuMgJH
could you check the part about GYRO and see if there is something wrong or not?
when I am at 90 degree, it gives me very big values like 400 degree.
the clock for timer is 1MHz.
Please, when posting on
Please, when posting on pastebin, choose Never as expiration. Resubmitted to http://pastebin.com/pvHKjvea
A gyroscope measures angular velocity, not an absolute angle. I'm not sure what you mean.
I did integrate the data from
I did integrate the data from gyro. But the data I get it does not look right?
I turn on the timer and then I multiply the timer value to gyro reading and adding that to previous value we had for angle.
wireless IMU
Hi everybody!
Great job, Fabio. I'm having a lot of fun playing with your code and it works very fine for me. Many thanks for that :)
Now I'm trying to use a wireless connection through XBee radios, and checking the serial lines everything is ok, but starting up with the Processing code I get an "out of range" error message on line
"inString = inString.substring(2, 10);"
Do you have any idea what might be happening?
Many thanks in advance.
how to find out gyro conversion values
Hi,
we have a digital gyro and we need to figure out how to covert the data.
I've found the following equation:
Rt = SC × (Rm - R0)
Where,
Rt (dps): true angular rate
Rm (LSBs): gyroscope measurement
R0 (LSBs): zero-rate level
SC (dps/LSB): sensitivity
but how do we get zero rate level from the gryo datasheet??
thanks
You won't get that from the
You won't get that from the gyro datasheet as it is gyro specific. You can simply average a number of readings (eg: 64) while keeping the gyro steady and use that as R0.
thanks =D
thanks =D
could you measure the period of your measuring loop?
Hi
I am reading my gyro and integrate my input and it takes me 0.036~0.039 second. I am using 1MHZ clock. Does this mean that my code is not efficient? could you measure the loop that you measure your gyro in all three axis and integrate? and could you state your clock if you did that?
thanks
I don't have specific timing
I don't have specific timing for only the gyro.. but I can say that reading an ADXL345, ITG3200 and HMC5843 and doing sensor fusion of them takes us 5 ms using a regular Arduino which runs at 16Mhz.
Thanks and another question
Thanks for your answer.
I am facing new problems, firstly I got your codes, and extract them but they are in tar format and I do not have any idea how to open them.
The second problem is with ADXL345, I read the datasheet but I am not sure about it. How should I make my ADXL345 to give me the data for one reading from all 3 axis at the same time. Now I just write 8 in 0x2D POWER_CTL register and it works but I am no so sure am I reading all data from all 6 axis for the same time or not. The other issue is that I am using 3.3 V and in datasheet they did not mention anything about mg/LSB at 3.3 Volt and they did not say anything about %/°C for 3.3 Volts. I think you used 3.3 volt so how did you solve the problem with mg/LSB and %/°C.
Any other thing that you think I have to take care of in order to get better result from ADXL345? I appreciate if you share your experience.
Thanks, like always you helped me out.
1 - Just get a serious
1 - Just get a serious archiving tool like 7-zip if you are under Windows and use that to open the code archives.
2 - You can't read all the three axis data from a single reading, but only with one big subsequent reading. The code posted in the article does exactly that.
Regarding the 3.3v issue, you may want to use a simple calibration procedure.. Place the accelerometer with one axis pointing up. Write down the reading. Place the accelerometer with the same axis pointing down. Write down the reading. Now you have the +1g and -1g interval values from the readings you wrote down. Divide the interval in two to compute the axis offset then use reading when pointing up or down + offset as LSB/g.
Hope this helps,
Fabio
I used 7-Zip, win RAR, and
I used 7-Zip, win RAR, and Win Zip but after I extarxt the file it comes with .tar format I do not have any idea why.
Could you send them to my email or any other sulotion that you have in your mind. I know it sounds stupid but I really tried to open them and I could not.
Thanks a lot for all your helps. I will try LSB/g today.
Once you have the .tar file
Once you have the .tar file you can open that again with 7-zip .. .tar files are also archives.
Hi I am sorry, I do not try
Hi
I am sorry, I do not try to distract you, but seriously I can not open the file. I can open licence but the other file is in PDE which I cannot open it. Is that because I am using windows XP?
I am sorry, to waste your time for this kind of question... :(
That file is either an
That file is either an Arduino file or a Processing file which you should open with the respective IDE.
sorry to waste your time but
sorry to waste your time but I am not using Arduino, I am using Atmega 16. I thought I can change your code to C and use them for my micro. But anyway I thing that is not going to work.
I tried my accelerometer and I have new question, how should I find mg/C?
should I care about it? did you care about it in your codes?
thanks for fast replies.
Just use any text editor to
Just use any text editor to open the files, I would suggest ConTEXT if you are running Windows.
mg/C? What do you mean?
The ratio between temperature
The ratio between temperature and LSB. I mean that, does temperature affect my sensors output? If yes how can I deal with it?
I read in datasheet that the mg/C is equal to +-1 at 25C and 2.5 V, It did not make sense for me, that how this value is affecting the readings. I thought you read temperature from ITG3200 in order to get an exact value from sensor. Am I right?
I saw your codes; I can just say fantastic…. I think it will answer many of my questions without asking you.
Thanks
I didn't do any temperature
I didn't do any temperature compensation in the codes posted in this article. There is work in progress on implementing that on the ITG3200 arduino library. See http://code.google.com/p/itg-3200driver/issues/detail?id=9
Thanks a lot, for all your
Thanks a lot, for all your help. Can I share my code later when I am done with it and you improve it for me?
sure..
I can give it a review.
Thanksin this part I just
Thanks
in this part I just read data from sensor.
http://pastebin.com/6mQyLbeD
admin edit: do not post code here directly. Use something like
http://pastebin.com/
sorry, next time I will post
sorry, next time I will post it there.
really tanks...
BTW it works. but is there
BTW it works. but is there anyway to make it faster?
and one question I did not see 2 complement in your code/or you had a way that I did not understand, could you explain about it. please.
I don't think you need to do
I don't think you need to do anything about handling 2's complement.. your microcontroller is probably already using that representation so once you assemble LSB and MSB you should be just fine. That's true for ATMEGA 328p on the Arduino.
at first glance it looks
at first glance it looks good.. do you have any specific question?
Hey Fabio, Quick question, i
Hey Fabio,
Quick question, i connected my hardware like this ( http://voidbot.net/razor-6dof.html (look at the third image from that page)). Would your code still work for my device when refering to the hardware or do i need to change something in the code to connect them properly?
Thanks a lot!
Hi Becky, thanks for stopping
Hi Becky, thanks for stopping by..
Unfortunately not.. you are using different sensors then mine so you have to adapt this code for them. Specifically, I'm using digital sensors while you have analog sensors. You may be interested in seeing this code:
http://www.starlino.com/imu_guide.html
http://www.starlino.com/imu_kalman_arduino.html
I based my code on the code there and, as Starlino also was using analog sensors, I think you may use that as a reference.
Hey Fabio, This is probably
Hey Fabio,
This is probably a really stupid question but please bare with me as i dont have much experience with coding! Can you confirm im writing the pins properly please? As i think they're wrong :S
In my code i wrote the following:
#define cGyroGXPin 0 //1x
#define cGyroGYPin 1 //1x
#define cGyroGZPin 2 //1x
#define cGyroGXPinAmp 3V3 //4x
#define cGyroGYPinAmp AREF //4x
#define cGyroGZPinAmp GND //4x
#define cGyroAXPin 3
#define cGyroAYPin 4
#define cGyroAZPin 5
And i connected my pins like this (third picture) http://voidbot.net/razor-6dof.html
Am i doing something wrong?
I think they are correct. You
I think they are correct. You should share the whole code to help you more.
Another quick question, In
Another quick question,
In your code where did you get the 14.375 from?
// convert raw readings to degrees/sec
void rawGyroToDegsec(int * raw, float * gyro_ds)
{
gyro_ds[0] = ((float) raw[0]) / 14.375;
gyro_ds[1] = ((float) raw[1]) / 14.375;
gyro_ds[2] = ((float) raw[2]) / 14.375;
}
I know which calculation it is in the starlino exercises, but i cant understand how you got the 14.375 out of the equation they provided :S Thanks
The equation i was referring
The equation i was referring to is this one:
RateAxz = (AdcGyroXZ * Vref / 1023 - VzeroRate) / Sensitivity
Is your 14.375 your sensitivity? As on my datasheet for my gyro my sensitivity is 3.33mV/deg/s which seems so little next to yours. Or did you multiply the sensitivity with other parts of the equation? Thansk for any help fabio!
Im so silly! I forgot yours
Im so silly! I forgot yours is digital!! Forget my question! Haha, i just realised i need to use that equation into my code..! :)
Thanks fabio! I'll start
Thanks fabio! I'll start posting the code bit by bit when its a bit more structured (very soon hopefully!). Im implementing your code together with another code i found on your website too :) Talk soon!
Hey, I have a quick question.
Hey,
I have a quick question. Once I get the values from the gyroscope and accelerometer, I'm trying to combine them using a complimentary filter algorithm.
On most websites, they have a formula or function (in code) that takes in a value for the gyro and a value for the accelerometer.
My question is: We have 3 values for the gyro and accelerometer. Does this mean that the formula/function will have to be used 3 times like this:
function(gyroX, accelX)
function(gyroY, accelY)
function(gyroZ, accelZ)
Thanks!
Well, post here the link to
Well, post here the link to the code you are trying to use and I'll have a look at how you should use it.. answering your question without knowing the particular example you are talking about it's not possible.
I would like to write my own
I would like to write my own implementation of the complementary filter that combines the agyro/accel and filters out the unwanted stuff.
So I'm mostly looking at algorithms to translate. The problem is that many of them go too much into the theoretical part.
This is the one that I found to be the easiest:
http://web.mit.edu/scolton/www/filter.pdf
Wiring combo board sparkfun
Hi, I'm using the Combo Board from Sparkfun, not currently working.
I'm not sure how to connect the Arduino board Duemilanove.
D2>INT1?
A4>SDA?
A5>SCL
?>INT0
thanks in advance
Post new comment