Any chance to prevent drift on a 3DOF gyro?

Hi,
I played around with a L3G4200D 3DOF gyro sensor using sparkfuns example code.
Actually I only need the x-axis, but only get a sort_of_stable output, when I don't move the sensor.

I had to eliminate zero-Point Errors, to get there.
But unfortunately, I get a huge drift when I move the sensor and put it back to starting Position.

Is there any chance to eliminate drift with only one 3DOF sensor, or do we always need a 3DOF accelerometer sensor too?

I haven't found much about the L3G4200D, could using the FIFO Registers help here?
Also couldn't find out yet which bandwidth would provide best accuracy.

the math behind the x_angle value is not final by now. I'm not sure how to cope with the interupt routine and millis()-readings.

/* L3G4200D 3-axis gyro example code
  by: Jim Lindblom
  SparkFun Electronics
  date: 4/18/11
  license: CC-SA 3.0 - Use this code however you'd like, all we ask
  for is attribution. And let us know if you've improved anything!
  
  Circuit:
  L3G4200D Breakout-------------Arduino Uno
  GND-----------------------------GND
  VCC-----------------------------3.3V
  SCL-----------------------------D13
  SDA-----------------------------D11
  SDO-----------------------------D12
  CS------------------------------D10
  INT2/DR-------------------------D6
  INT1----------------------------D7
  
  This example code is intended for use with ST. Microelectronics'
  L3G4200D triple-axis digital gyroscop. The L3G4200D is capable of
  both I2C and SPI communications, but we'll use SPI in this example.
  
  This code sets up the L3G4200D's 5 control registers, and then 
  streams the data from all three axes over the Serial Monitor at 9600bps.
  
*/

#include <SPI.h>
#include "L3G4200D.h"
#include <Wire.h> 
#include <LiquidCrystal_I2C.h> //sainsmart test library for 20x4 I2C LCD

// pin definitions
const int int2pin = 6;
const int int1pin = 7;
const int chipSelect = 10;

// gyro reading
int x;
int x_angle =0; //start with sensor top down on a flat surface
int x_offset = 15; // that's the average value when sensor isn't moving
int show_angle = 0;

LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 20x4 display

void setup()
{
  lcd.init(); 
  lcd.init();  // initialize the lcd twice
  lcd.backlight();
  lcd.setCursor(3,0);
  lcd.print("L3G4200D Test");
  
  // Start the SPI library:
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);
  SPI.setClockDivider(SPI_CLOCK_DIV8);
  
  pinMode(int1pin, INPUT);
  pinMode(int2pin, INPUT);
  pinMode(chipSelect, OUTPUT);
  digitalWrite(chipSelect, HIGH);
  delay(100);
  
  setupL3G4200D(2);  // Configure L3G4200 with selectabe full scale range
  // 0: 250 dps
  // 1: 500 dps
  // 2: 2000 dps
}

void loop()
{
  // Don't read gyro values until the gyro says it's ready
  while(!digitalRead(int2pin));  
  getGyroValues();  // This will update x with new values
  x+= x_offset; //eliminate zero offset and ignore small changes to minimize drift
  if (!( x < 7 && x > -7 )){  
    x_angle += x;
  } // end if
    
  show_angle += 1;  // try to read data as fast as possible but send data only every 50 loops
  if (show_angle == 50 ){ 
    lcd.setCursor(2,2);
    lcd.print("Raw X ");
    lcd.print(x, DEC);
    lcd.print("   "); // erase bigger values from screen
    lcd.setCursor(2,3);
    lcd.print("Pitch ");
    lcd.print(x_angle, DEC);
    lcd.print("   ");    
    show_angle = 0;
  } // end if  
} // end loop

int readRegister(byte address)
{
  int toRead;
  
  address |= 0x80;  // This tells the L3G4200D we're reading;
  
  digitalWrite(chipSelect, LOW);
  SPI.transfer(address);
  toRead = SPI.transfer(0x00);
  digitalWrite(chipSelect, HIGH);
  
  return toRead;
}

void writeRegister(byte address, byte data)
{
  address &= 0x7F;  // This to tell the L3G4200D we're writing
  
  digitalWrite(chipSelect, LOW);
  SPI.transfer(address);
  SPI.transfer(data);
  digitalWrite(chipSelect, HIGH);
}

int setupL3G4200D(byte fullScale)
{
  // Let's first check that we're communicating properly
  // The WHO_AM_I register should read 0xD3
  if(readRegister(WHO_AM_I)!=0xD3)
    return -1;
    
  // Enable x, y, z and turn off power down:
  writeRegister(CTRL_REG1, 0b00001111);
  
  // If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
  writeRegister(CTRL_REG2, 0b00000000);
  
  // Configure CTRL_REG3 to generate data ready interrupt on INT2
  // No interrupts used on INT1, if you'd like to configure INT1
  // or INT2 otherwise, consult the datasheet:
  writeRegister(CTRL_REG3, 0b00001000);
  
  // CTRL_REG4 controls the full-scale range, among other things:
  fullScale &= 0x03;
  writeRegister(CTRL_REG4, fullScale<<4);
  
  // CTRL_REG5 controls high-pass filtering of outputs, use it
  // if you'd like:
  writeRegister(CTRL_REG5, 0b00000000);
}

int getGyroValues()
{
  x = (readRegister(0x29)&0xFF)<<8;
  x |= (readRegister(0x28)&0xFF);
}

The value get from the gyro is "Rate Of Change" (degrees per second). I think you have to multiply that by the time period in order to get actual degrees. Is the gyroscope free-runing or does the reading of the register trigger a new reading?

If you don't need a full 2000 degrees-per-second range you might want to turn down the full-scale range to make it more sensitive.

You need the accelerometer to prevent drift. No way to get around that with a gyro alone.

johnwasser:
The value get from the gyro is "Rate Of Change" (degrees per second). I think you have to multiply that by the time period in order to get actual degrees. Is the gyroscope free-runing or does the reading of the register trigger a new reading?

If you don't need a full 2000 degrees-per-second range you might want to turn down the full-scale range to make it more sensitive.

I think, I have to divide the value by 'delta time' to get the angle.
The gyro triggers an interupt, but I'm not sure about the bandwidth. Maybe I skip a few readings? How could I find out?

I tried to set sensitivity to 250 dps, but that made the zero-point readings jump through the roof :wink:

Anyways, when I need a second sensor to eliminate drift, so be it.
MPU6050 is my next toy...

you can do better,

various filter algorithms,

but

in the end gyro will drift,

you can use a few different things to correct for drift,
gps, compass, star sight, wind direction,

depends what you want,

but a 9dof senser is not that much more than ac 3dof,

The final goal is to control a throttle signal to allow a certain pitch-angle and keep the vehicle below that level.
Some kind of digital wheelie bar. Pretty much like a balancing bot, but faster :smiley:
It will be a rc-car to test the behaviour, but finally there is an e-bike with plenty of power on the rear wheel, waiting to be tamed... ( Any tractor-pulling engineers out there? :wink: )

I think, the best way to control the sensordrift is to use an acc-sensor.

add an accelaromiter, in 3d , that gives u 6DOF.

9DOF are just a cheap, as they are used on model aircraft,

,

if your only doing a few, like one or two, just stick one of these on and see what you use.