Gyroscope (L3G4200D)

This sensor output and code example is difficult for me to understand. I have posted what I get from the sensor when it is stationary on my desk and I get some huge variation. I am using I2C communication for my gyroscope, bought from http://www.pololu.com/catalog/product/1272. The example code is off of their website and says it is for Arduino. I have tried contacting them with no luck on the issue. My current wiring setup is on a Duemilanove atmega 328. Could someone help me with this issue and converting the “raw” data or numbers into readable degrees? I cannot even tell if the gyroscope is reading relative or absolute change in the three axis’. Also, for an idiot like me, could someone sum up the differences between SPI versus I2C? I have seen an SPI example code for the Sparkfun version of the gyroscope but not sure how that would be wired up since I am missing an INT2 and not sure if my INT1 is same as the INT1 as the Sparkfuns or considered INT2… In any case, if it is “easier” to understand or translate raw data in SPI, could someone direct me in the right direction?

My wiring is as below:
SCL to Analog 5
SDA to Analog 4
Ground to Ground
VIN to 5v

Side note: I believe the reference for the arduino board pro mini for SDA and SCL is for analog 4 and analog 5. I have yet to confirm it. Right now I am using this on Arduino Duemilanove
http://arduino.cc/en/Main/ArduinoBoardProMini
A4 (SDA) and A5 (SCL)

Serial output (250 deg/sec):

starting up L3G4200D
X:105 Y:62 Z:46
X:111 Y:-26 Z:27
X:93 Y:-49 Z:7
X:47 Y:-65 Z:-225
X:-1 Y:-27 Z:4
X:59 Y:-94 Z:-63
X:66 Y:-151 Z:-21
X:10 Y:-120 Z:1
X:24 Y:-109 Z:-59
X:18 Y:-93 Z:-29
X:63 Y:-162 Z:-10
X:85 Y:-93 Z:-31
X:40 Y:-33 Z:-51
X:40 Y:-59 Z:-24
X:66 Y:-76 Z:0
X:82 Y:-6 Z:41
X:112 Y:-12 Z:64
X:71 Y:53 Z:61
X:84 Y:92 Z:44
X:74 Y:48 Z:67
X:123 Y:50 Z:102
X:117 Y:24 Z:45
X:72 Y:98 Z:44
X:104 Y:101 Z:5
X:146 Y:-5 Z:17
X:105 Y:-44 Z:45
X:111 Y:-9 Z:45
X:89 Y:5 Z:11
X:96 Y:-6 Z:8
X:107 Y:56 Z:12
X:160 Y:27 Z:42
X:123 Y:29 Z:26
X:67 Y:130 Z:19
X:92 Y:142 Z:34
X:142 Y:66 Z:78
X:149 Y:67 Z:123
X:159 Y:87 Z:50
X:115 Y:166 Z:70
X:124 Y:186 Z:70
X:135 Y:137 Z:68
X:169 Y:122 Z:98
X:135 Y:139 Z:69
X:111 Y:187 Z:92
X:77 Y:61 Z:64
X:114 Y:-25 Z:67
X:50 Y:-53 Z:9
X:31 Y:-42 Z:-48
X:40 Y:-53 Z:-221
X:41 Y:-143 Z:14
X:4 Y:-200 Z:17
X:-22 Y:-257 Z:-60
X:-56 Y:-216 Z:-108
X:-110 Y:-213 Z:-89
X:12 Y:-362 Z:-100
X:18 Y:-372 Z:-46
X:-75 Y:-276 Z:-115
X:-74 Y:-176 Z:-145
X:247 Y:-269 Z:-88
X:14 Y:-262 Z:-54
X:16 Y:-185 Z:-63
X:-29 Y:-116 Z:-68
X:69 Y:-92 Z:6
X:79 Y:-82 Z:56
X:92 Y:4 Z:51
X:68 Y:82 Z:54
X:67 Y:134 Z:-46
X:122 Y:-7 Z:50
X:72 Y:13 Z:34
X:93 Y:27 Z:24
X:37 Y:456 Z:64
X:22 Y:-465 Z:-337
X:622 Y:-739 Z:-361
X:473 Y:-526 Z:-278
X:129 Y:14 Z:-84
X:-88 Y:-92 Z:-155
X:378 Y:-206 Z:-311
X:489 Y:-247 Z:-162
X:340 Y:-49 Z:-143
X:204 Y:290 Z:-76
X:192 Y:308 Z:-76
X:61 Y:247 Z:298
X:-75 Y:615 Z:1652
X:8 Y:-121 Z:501
X:-41 Y:-817 Z:1342
X:-1846 Y:3000 Z:509
X:-334 Y:-550 Z:-400
X:-1081 Y:-532 Z:-1116
X:286 Y:-333 Z:-847
X:2813 Y:-2472 Z:253
X:1218 Y:-2532 Z:2289

Serial output (2000 deg/sec)P

starting up L3G4200D
X:35 Y:-16 Z:15
X:12 Y:-103 Z:-34
X:-40 Y:-79 Z:-21
X:-13 Y:-58 Z:-31
X:13 Y:-54 Z:3
X:35 Y:-59 Z:20
X:-1 Y:-49 Z:1
X:-16 Y:-31 Z:-23
X:-3 Y:-17 Z:-17
X:30 Y:-25 Z:9
X:18 Y:-15 Z:19
X:-3 Y:-11 Z:10
X:-5 Y:-252 Z:-6
X:3 Y:2 Z:4
X:19 Y:3 Z:18
X:20 Y:2 Z:13
X:13 Y:1 Z:1
X:8 Y:9 Z:-3
X:13 Y:2 Z:8
X:20 Y:7 Z:16
X:23 Y:11 Z:14
X:21 Y:12 Z:17
X:23 Y:14 Z:13
X:9 Y:20 Z:5
X:-1 Y:16 Z:-1
X:19 Y:5 Z:12
X:22 Y:0 Z:16
X:19 Y:1 Z:14
X:3 Y:-7 Z:4
X:9 Y:-1 Z:-9
X:10 Y:-6 Z:9
X:22 Y:-5 Z:14
X:15 Y:-7 Z:13
X:13 Y:-9 Z:-4
X:1 Y:-10 Z:-7
X:0 Y:-7 Z:6
X:16 Y:-12 Z:12
X:19 Y:-8 Z:11
X:13 Y:-4 Z:7
X:3 Y:-3 Z:-3
X:7 Y:-2 Z:255
X:12 Y:-2 Z:13
X:2 Y:-3 Z:20
X:16 Y:-4 Z:42
X:29 Y:-2 Z:-1
X:-4 Y:-8 Z:-17
X:-8 Y:-4 Z:-8
X:11 Y:-2 Z:18
X:18 Y:-7 Z:17
X:23 Y:-12 Z:13
X:7 Y:-8 Z:-2
X:2 Y:-16 Z:-6
X:10 Y:-10 Z:0
X:11 Y:-10 Z:3
X:6 Y:-16 Z:11
X:20 Y:-14 Z:10
X:9 Y:-5 Z:7
X:55 Y:56 Z:14
X:-29 Y:45 Z:-108
X:52 Y:21 Z:15
X:55 Y:4 Z:58
X:-20 Y:47 Z:16
X:-23 Y:36 Z:-95
X:-33 Y:31 Z:18
X:-18 Y:8 Z:159
X:-63 Y:72 Z:168
X:-13 Y:-124 Z:305
X:71 Y:120 Z:-388
X:59 Y:206 Z:25
X:-121 Y:517 Z:-10
X:-29 Y:443 Z:78
X:30 Y:-924 Z:344
X:-191 Y:-402 Z:-327
X:-177 Y:-364 Z:-186
X:91 Y:-363 Z:193
X:-22 Y:-165 Z:-64
X:-4 Y:-176 Z:-113
X:-59 Y:-106 Z:-129
X:34 Y:-278 Z:27
X:-210 Y:87 Z:-205
X:167 Y:-45 Z:192
X:19 Y:15 Z:21
X:25 Y:-72 Z:75
X:-193 Y:162 Z:-198
X:38 Y:290 Z:45
X:71 Y:167 Z:76
X:85 Y:143 Z:156
X:-60 Y:99 Z:2
X:-13 Y:-29 Z:38
X:-23 Y:40 Z:21
X:-234 Y:100 Z:-406
X:-136 Y:19 Z:-191
X:135 Y:134 Z:56
X:180 Y:-11 Z:57
X:122 Y:-85 Z:100
X:33 Y:-176 Z:7
X:138 Y:-321 Z:295
X:-164 Y:608 Z:-218
X:123 Y:261 Z:79
X:587 Y:635 Z:-451
X:566 Y:613 Z:769
X:248 Y:282 Z:282

The code I was using with the sensor

//Arduino 1.0+ only

#include <Wire.h>

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

int L3G4200D_Address = 105; //I2C address of the L3G4200D

int x;
int y;
int z;

void setup(){

  Wire.begin();
  Serial.begin(9600);

  Serial.println("starting up L3G4200D");
  setupL3G4200D(2000); // Configure L3G4200  - 250, 500 or 2000 deg/sec

  delay(1500); //wait for the sensor to be ready 
}

void loop(){
   getGyroValues();  // This will update x, y, and z with new values

  Serial.print("X:");
  Serial.print(x);

  Serial.print(" Y:");
  Serial.print(y);

  Serial.print(" Z:");
  Serial.println(z);

  delay(100); //Just here to slow down the serial to make it more readable
}

void getGyroValues(){

  byte xMSB = readRegister(L3G4200D_Address, 0x29);
  byte xLSB = readRegister(L3G4200D_Address, 0x28);
  x = ((xMSB << 8) | xLSB);

  byte yMSB = readRegister(L3G4200D_Address, 0x2B);
  byte yLSB = readRegister(L3G4200D_Address, 0x2A);
  y = ((yMSB << 8) | yLSB);

  byte zMSB = readRegister(L3G4200D_Address, 0x2D);
  byte zLSB = readRegister(L3G4200D_Address, 0x2C);
  z = ((zMSB << 8) | zLSB);
}

int setupL3G4200D(int scale){
  //From  Jim Lindblom of Sparkfun's code

  // Enable x, y, z and turn off power down:
  writeRegister(L3G4200D_Address, CTRL_REG1, 0b00001111);

  // If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
  writeRegister(L3G4200D_Address, 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(L3G4200D_Address, CTRL_REG3, 0b00001000);

  // CTRL_REG4 controls the full-scale range, among other things:

  if(scale == 250){
    writeRegister(L3G4200D_Address, CTRL_REG4, 0b00000000);
  }else if(scale == 500){
    writeRegister(L3G4200D_Address, CTRL_REG4, 0b00010000);
  }else{
    writeRegister(L3G4200D_Address, CTRL_REG4, 0b00110000);
  }

  // CTRL_REG5 controls high-pass filtering of outputs, use it
  // if you'd like:
  writeRegister(L3G4200D_Address, CTRL_REG5, 0b00000000);
}

void writeRegister(int deviceAddress, byte address, byte val) {
    Wire.beginTransmission(deviceAddress); // start transmission to device 
    Wire.write(address);       // send register address
    Wire.write(val);         // send value to write
    Wire.endTransmission();     // end transmission
}

int readRegister(int deviceAddress, byte address){

    int v;
    Wire.beginTransmission(deviceAddress);
    Wire.write(address); // register to read
    Wire.endTransmission();

    Wire.requestFrom(deviceAddress, 1); // read a byte

    while(!Wire.available()) {
        // waiting
    }

    v = Wire.read();
    return v;
}

The L3G4200D seems like a nice gyro sensor.
The pololu page provides lots of information and a schematic of the board.
So you have a good sensor and lots of information.

SPI versus I2C: I prefer I2C, since every manufacturer must use the I2C protocol, so many devices can be used on the same bus. But it is slower. For applications that need to be really fast, I would use SPI.

The pololu board has a I2C level shifter: http://arduino.cc/playground/Main/I2CBi-directionalLevelShifter
It also has already pull-up resistors, so you don’t need to add them.
The CS is pulled up, so the device is in I2C mode.
The SDO is also pulled up, that is the lowest bit of the I2C address (use a i2c_scanner to scan for the address).

To check the I2C, try this i2c_scanner sketch: http://arduino.cc/playground/Main/I2cScanner (just uploaded it this morning)

I would have written the code you use in a different way, but I think it’s okay.

Now about the values.
They look good to me.
You have an offset, which is normal.
In the code you could measure the gyro values in setup() for the offset.
The values are 16-bits, and the sensor is sensitive. So they might seem all over the place, but that’s because it is sensitive. The gyro sensor has internal filters to get more stable readings.

To get more stable reading, get rid of the offset and try the filters of the sensor.

Krodal, so the raw data values are offset. Are they also in degrees? (I guess there is only one way to find out). What do you mean by filters? The 250, 500 or 2000?

From what it sounds like the gyroscope needs to be in other words zeroed. I have worked with tangible/static zeroing such as zeroing a weight scale, calipers, tensile stress sensors, etc. but this kind of offset not sure how to filter it.

My guess is that I should leave it running for 30 seconds to a minute in a stationary, static position. Copy those values, find the range and average of those values and then add a line of code in the program that has an if/else statement. i.e. If x > -124 && x<238, x=0. That would be a program filter which I would then have to make it like a cluster for each major angular velocity. But then if I measure the offset values in the void setup, I wouldn’t need to find the range and average and paste it in a spreadsheet… so then, setting up an array or vector?

Is this useful ? http://arduino.cc/forum/index.php?topic=78578.0

I don't understand your if statement. Sorry.

This thread has a number of interesting links: http://arduino.cc/forum/index.php?topic=95022.0

I just read in the datasheet, that external components are needed for low-pas filtering. Perhaps using the average of a number of samples is easier.

T86157: Are they also in degrees? (I guess there is only one way to find out). What do you mean by filters? The 250, 500 or 2000?

Per the datasheet on page 10, the output is in mdps/digit. That is to say, for each selected scale, there is a conversion from output value to mdps (millidegrees per second) For 250, it's 8.75.

Multiply your output value by that, and you get millidegrees per second of angular rate. Divide that by 1000 if you want degrees per second.