1
\$\begingroup\$

I am using a Parallax L3G4200D 3 axis Gyro. When a gyro is left on a flat surface with nothing interacting with it at all the outputs from it should all be “0″ correct? Mine is jumping around between numbers. For example “X_L = 0″ and “X_H = 17219″ with a “delay(500)” between refresh the X_H will jump around while X_L stays pretty much at 0 but will occasionally jump very high. Do you think this is a problem with the sensor or something code related? If I pick up the Gyro and shake it around all of the numbers start updating like its functioning correctly. Below is the output I am talking about this is when it is flat and nothing interacting with it:

Value of X is: 20
Value of Y is: 85
Value of Z is: 147168
Y_L equals: 0
Y_H equals: 9766
X_L equals: 2313
X_H equals: 0
Z_L equals: 34782
Z_H equals: 65535
The temperature is: 75


Value of X is: 22
Value of Y is: 49
Value of Z is: 147167
Y_L equals: 0
Y_H equals: 5654
X_L equals: 3855
X_H equals: 0
Z_L equals: 51143
Z_H equals: 65535
The temperature is: 75


Value of X is: 29
Value of Y is: 76
Value of Z is: 147168
Y_L equals: 0
Y_H equals: 8995
X_L equals: 65021
X_H equals: 65535
Z_L equals: 46260
Z_H equals: 65535
The temperature is: 77

Here is the code I am using to get the values I am using the I2C Library for the Pi from HERE

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>

#include <wiringPi.h>
#include <wiringPiI2C.h>

#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23


int fd;
int x = 0;
int y = 0;
int z = 0;
int main (){



    fd = wiringPiI2CSetup(0x69); // I2C address of gyro
    wiringPiI2CWriteReg8(fd, CTRL_REG1, 0x1F); //Turn on all axes, disable power down
    wiringPiI2CWriteReg8(fd, CTRL_REG3, 0x08); //Enable control ready signal
    wiringPiI2CWriteReg8(fd, CTRL_REG4, 0x80); // Set scale (500 deg/sec)
    delay(100);                    // Wait to synchronize

void getGyroValues (){
    int MSB, LSB;

    LSB = wiringPiI2CReadReg16(fd, 0x28);
    MSB = wiringPiI2CReadReg16(fd, 0x29);
    x = ((MSB << 8) | LSB);

    MSB = wiringPiI2CReadReg16(fd, 0x2B);
    LSB = wiringPiI2CReadReg16(fd, 0x2A);
    y = ((MSB << 8) | LSB);

    MSB = wiringPiI2CReadReg16(fd, 0x2D);
    LSB = wiringPiI2CReadReg16(fd, 0x2C);
    z = ((MSB << 8) | LSB);
}

    for (int i=0;i<10;i++){
    getGyroValues();
    // In following Divinding by 114 reduces noise
    printf("Value of X is: %d\n", x / 114);
    printf("Value of Y is: %d\n", y / 114);
    printf("Value of Z is: %d\n", z / 114);
    int t = wiringPiI2CReadReg8(fd, 0x26);
    t = (t*1.8)+32;//convert Celcius to Fareinheit
    int a = wiringPiI2CReadReg16(fd,0x2B);
    int b = wiringPiI2CReadReg16(fd,0x2A);
    printf("Y_L equals: %d\n", a);
    printf("Y_H equals: %d\n", b);
    int c = wiringPiI2CReadReg16(fd,0x28);
    int d = wiringPiI2CReadReg16(fd,0x29);
    printf("X_L equals: %d\n", c);
    printf("X_H equals: %d\n", d);
    int e = wiringPiI2CReadReg16(fd,0x2C);
    int f = wiringPiI2CReadReg16(fd,0x2D);
    printf("Z_L equals: %d\n", e);
    printf("Z_H equals: %d\n", f); 

    printf("The temperature is: %d\n\n\n", t); 
    delay(500);
}
};
\$\endgroup\$
9
  • \$\begingroup\$ It's probably worth adding a bit of code. While I haven't used that particular gyro it's not apparent to me how you're getting those final values from the L/H register values shown. You won't get exactly zero when it's stationary, there will be some noise and random walk although the above values appear too large. \$\endgroup\$
    – PeterJ
    Mar 3 '13 at 7:14
  • \$\begingroup\$ @PeterJ I updated the question with my code \$\endgroup\$ Mar 3 '13 at 7:22
  • \$\begingroup\$ OK that explains why I couldn't correlate the numbers, the registers are read a second time and have probably jumped around. I don't suppose you have it connected with long wires and/or a breadboard? I2C has a maximum capacitance of 400pF which can be pretty easy to exceed. \$\endgroup\$
    – PeterJ
    Mar 3 '13 at 7:50
  • 1
    \$\begingroup\$ You'll get drift. The output will drift over time. The output won't give you angular position but will give you angular velocity. \$\endgroup\$
    – efox29
    Mar 3 '13 at 7:51
  • \$\begingroup\$ Hard to know exactly, but given how easy it would be I'd certainly start by putting the gyro right next to the adapter. With an SPI gyro which is less forgiving than I2C I once had problems using about 10cm / 4" odd of ribbon cable and that wasn't using a breadboard that would add extra capacitance as well. \$\endgroup\$
    – PeterJ
    Mar 3 '13 at 8:11
1
\$\begingroup\$

I am using a Parallax L3G4200D 3 axis Gyro.

Don't you mean a STMicroelectronics gyroscope? Right.

When a gyro is left on a flat surface with nothing interacting with it at all the outputs from it should all be “0″ correct? Mine is jumping around between numbers.

No, they are supposed to output values, which vary from part to part and its distribution is approximate to a Gaussian curve (less frequent-most frequent- less frequent histogram shape). You need to take an average of these values (offset) and then always subtract from the value you read each time in order to use it (so the most frequent value is closer to zero).

vale = value - offset;

For example “X_L = 0″ and “X_H = 17219″ with a “delay(500)” between refresh the X_H will jump around while X_L stays pretty much at 0 but will occasionally jump very high.

Is it possible that you are inverting the order of the bytes? The low byte represents the most sensitive readings.

Do you think this is a problem with the sensor or something code related? If I pick up the Gyro and shake it around all of the numbers start updating like its functioning correctly.

Not exactly, I would assume, since the values you read at idle state are just intrinsic noise.

Wire.beginTransmission(0x69);
Wire.write(0xA8);
Wire.endTransmission();
Wire.requestFrom(0x69, 6);
while (Wire.available() < 6); //you need to wait for the date to be ready
low   = Wire.read();
high  = Wire.read();
X  = ((high << 8) | low);     //you need to read the 3 registers 1 by 1   

low   = Wire.read();
high  = Wire.read();
Y  = ((high << 8) | low);

low   = Wire.read(); 
high  = Wire.read();
Z  = ((high << 8) | low);


X -= <offset here>;           //you need to take average (offset) and subtract
y -= <offset here>;
Z -= <offset here>;

Only then you can actually start using the values. They are still in 2 complements (MSB is sign bit) and they are not yet in degrees per second (dps). Each value you have to multiply by a constant (sensitivity). This constant varies with the measurement range. If it is 500 dps, then the constant is 0.0175.

Xdps = X*0.0175;

You might be interested in calculating the angle, then you have to integrate the angular speed. If the loop time for reading is 1ms, then multiply Xdps by 0.001.

Xdps = X*0.0175*0.001; 

Due to lack of timing precision, the gyro will drift with time. It will never go back to zero angle if you bring it physically to the zero position, but it will keep an offset. You need to fuse accelerometer to kill this offset.

But you still (probably) need to filter the values:

Xflt = Xflt*0.9 + Xdps*0.1;

This will make sure that only considerable variation in magnitude of Xdps will actually affect the final value Xflt (i.e. it suppresses noise values).

\$\endgroup\$
1
  • \$\begingroup\$ Welcome to EE.SE! Thanks for the comprehensive answer on this old question. \$\endgroup\$ Aug 28 '16 at 16:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.