Converting raw gyro (L3GD20H) values into angles

gyrosensor

As per my understanding, in order to convert the raw gyro values into angles, I need to first multiply the raw values of each axis with the sensitivity level.

Example:

//Convert Gyro raw to degrees per second
   
   rate_gyr_x = (float) gyrRaw[0] * G_GAIN;

   rate_gyr_y = (float) gyrRaw[1]  * G_GAIN;

   rate_gyr_z = (float) gyrRaw[2]  * G_GAIN
source : http://ozzmaker.com/2014/12/11/berryimu/

In order to calculate the angle, I need to multiply the rate with the loop period.

Example:

  gyroXangle+=rate_gyr_x*DT;

  gyroYangle+=rate_gyr_y*DT;

  gyroZangle+=rate_gyr_z*DT;

Source.

But I don't understand why the angle values are added with previous values.

In my problem, I trying to write a program to balance an inverted pendulum. I have a timer which will interrupt the main program once in every 30ms. Once in every 30 ms, I will run a function to read the gyro values and compare the read value with reference. Based on the difference, the speed and direction of motor will be adjusted.

In order to get the reference angle and the newly read angle, I have multiplied the raw gyro values with the sensitivity level and multiplied that result with 0.03s (as my loop period is 30 ms) to get the sngle value. But in the reference link I have provided above the author has added the angles (integrated over time.) Just multiplying the rate (degrees/sec) with loop period will give the angle, but then why do we have to sum it up over time?

How can you use this summed up angle for comparison against the reference angle?

Am I missing something?

Best Answer

But I don't understand why the angle values are added with previous values.

They are added to previous values because they aren't angles, instead being angular velocities. The "gyro" is in proper terms called an angular rate sensor: it is incapable of measuring absolute angles, instead measuring the angular velocity of the sensor (how fast it turns). The raw values are in sensor-specific units and they must be converted to degrees or radians per second by multiplying with a gain value (G_GAIN, which determines how many degrees/radians a raw "count" corresponds to) and the sampling interval (DT) in order to make the data useful. In your code, this is accomplished with:

inrate_gyr_x = (float) gyrRaw[0] * G_GAIN;
gyroXangle+=rate_gyr_x*DT;

Just as it is possible to estimate distance traveled in a car given the speed and time traveled, it is possible to estimate the current angle of the sensor by measuring the angular velocity over time and summing the results. This operation is called integration in mathematics and is exactly what that code does with:

inrate_gyr_x = (float) gyrRaw[0] * G_GAIN;
gyroXangle+= rate_gyr_x*DT;

The code is as it is now incomplete since it does not account for gyro drift. The sensor is not perfect, and will probably return a nonzero angular velocity even when completely stationary. This must be countered by adding a compensation term to the measured angular velocity before integration, or the estimated angle will drift away from the correct value even without motion.

Furthermore, the sensor gain is probably not exactly the same along the different axis due to the manufacturing process etc. If the gain is wrong, a 360° rotation can register as, for example, 349° or 368°. In order to correct for this, you should have separate gains for each of the axis, so you can tune them independently.

All this would be taken into account with the following code:

rate_gyr_x = (float) gyrRaw[0] * G_GAIN_X;  
rate_gyr_y = (float) gyrRaw[1] * G_GAIN_Y;  
rate_gyr_z = (float) gyrRaw[2] * G_GAIN_Z;  
gyroXangle += rate_gyr_x * DT - est_drift_x;  
gyroYangle += rate_gyr_y * DT - est_drift_y;  
gyroZangle += rate_gyr_z * DT - est_drift_z;