Measuring angle using gyroscope

I am trying to measure the angle using a gyroscope for a quadcopter. I have both a ITG3200 and a ITG3205 and these are not working! I have tried soo many different things but my readings when I integrate are not correct. Can someone explain to me what I am doing wrong? I have a feeling its to do with multiplying my deg/s reading by dt but I really am not sure. When my sensor is flat the values fluctuate around 0 so that works, but as soon as I tilt 90 degrees the pitch/roll goes to 170 or so, and then a completely wrong number when i reset it horizontally. This is for getting my x angle reading for example:

float getXGyro() {
  byte* data = readFromDevice(GYRO, 0x1D, 2);
  float gyroRate = (((data[0] << 8) | data[1]) / 14.375) - gyroXOffset; // divide by 14.375 gives degrees per second
  gyroXAngle += gyroRate * dt;
  return gyroXAngle; 
}

and in my mail loop i have dt computed by:

now = millis();
dt = (now-lastTime)/1000;
dt = now;

and this is with dt being at the bottom when code finishes. Can someone post there own working version or lend me a hand? I’ll attach my project if that helps anyone!
Please and thank you!!

EDIT: changed test.ino to proper file

gyro.ino (1.06 KB)

accel.ino (976 Bytes)

magneto.ino (586 Bytes)

test.ino (2.3 KB)

I don't see the 'dt' calculation in either test.ino or gyro.ino. The calculations you show above are unlikely to work.

now = millis();
dt = (now-lastTime)/1000;  // This will produce dt=0 if 'now' and 'lastTime' are both unsigned long as they should be.
dt = now;  // Shouldn't this be "lastTime = now;"?

johnwasser:
I don't see the 'dt' calculation in either test.ino or gyro.ino. The calculations you show above are unlikely to work.

Hmm it should be there... But regardless it calculates like I described, except for dt should read lastTime but I typed that in here, the code says lastTime. Its like this:

now = millis();
dt = (now  - lastTime ) /1000

//all the code goes here
delay(10);
lastTime = now;

ben_cunningham:

dt = (now  - lastTime ) /1000

That line is missing the closing semicolon so it won't compile.

Dividing a small integer (now - lastTime) by 1000 is likely to result in the value 0. You should, therefore, not do the division here.

If your loop( ) is running quickly, dt will usually be zero, the way you are calculating it.

You need to make dt a floating point number so that it can be a fraction of a second.

Or alternative, calculate the roll rate in degrees per millisecond, and dt in milliseconds.

float getXGyro() {
  byte* data = readFromDevice(GYRO, 0x1D, 2);
  float gyroRate = (((data[0] << 8) | data[1]) / 14.375) - gyroXOffset; // divide by 14.375 gives degrees per second
  gyroXAngle += gyroRate * dt;
  return gyroXAngle; 
}

For this bit of code to be doing anything useful, gyroXAngle must be a global value in your program.

There is not a lot of point to having it as a global variable AND as a return value from the function. You are just wasting some of the cpu time.

johnwasser:

ben_cunningham:

dt = (now  - lastTime ) /1000

That line is missing the closing semicolon so it won't compile.

Dividing a small integer (now - lastTime) by 1000 is likely to result in the value 0. You should, therefore, not do the division here.

Yes I know it won't compile, that's not my problem. Where should I divide it by then? If it's milliseconds its really not that small of an integer, like 10 or something

michinyon:
If your loop( ) is running quickly, dt will usually be zero, the way you are calculating it.

You need to make dt a floating point number so that it can be a fraction of a second.

Or alternative, calculate the roll rate in degrees per millisecond, and dt in milliseconds.

Ok thanks for the advice, I'll take a look at that!

michinyon:

float getXGyro() {

byte* data = readFromDevice(GYRO, 0x1D, 2);
  float gyroRate = (((data[0] << 8) | data[1]) / 14.375) - gyroXOffset; // divide by 14.375 gives degrees per second
  gyroXAngle += gyroRate * dt;
  return gyroXAngle;
}




For this bit of code to be doing anything useful, gyroXAngle must be a global value in your program.

There is not a lot of point to having it as a global variable AND as a return value from the function. You are just wasting some of the cpu time.

But if it’s not a global variable then how will I keep my integration in memory? Unless I pass something as a parameter?

Well it needs to be a global variable, so you can keep the progressive result of your integration.

But then if it is, you don’t need to return it from the function. The other part of the program, that wants to use it, can just refer to the global variable also. So you don’t actually need a return value there, you could just have the return type of the function as void, not have a return statement, and save some time.

I assume that you are also aware that, because of noise and drift, this process of adding up the rotation rate to find out the total angle you have turned, will become highly inaccurate in a matter of seconds, without some other calculation to correct it.

Oh right thank you, I'll take out the return statements. I know that the sensors have built in filters as well I'm using an accelerometer in conjunction and using a complementary filter to acquire pitch and roll. Is "a matter of seconds" an hyperbole?

No, if you just use the gyro rate only, you will be miles off in seconds.

You use the accelerometer reading to correct that gyro drift, at least in the roll and pitch directions, you didn't mention before that you also had an accelerometer.