Recently I got an IMU (Inertial Measurement Unit) from Sparkfun, called SparkFun 6 Degrees of Freedom IMU Digital Combo Board.
This IMU has embedded a gyroscope (ITG-3200) and a accelerometer (ADXL345) in a breakout board being useful for application that requires knowledge about orientation, position, and velocity.
The gyroscope is responsible to measure angular velocity on body axes:
- X Axis – Roll
- Y Axis – Pitch
- Z Axis – Yaw
Some examples:
The accelerometer is responsible to measure acceleration on the body axes (x, y and z) that is useful to determine how fast a body is speeding up or slowing down.
Another point is the use of I2C (Inter-Integrated Circuit) bus that is an intra-board serial bus that uses only two “wires” for comunication: one responsible for synchronizing the devices on bus (CLOCK – SCL) and another one responsible for data transmission (DATA – SDA).
This article aims to present a arduino implementation that simply shows output data from sensors. The references on source code are highly recommended for study before deploy this code in real application.
// SparkFun 6 Degrees of Freedom IMU Digital Combo Board // ITG-3200 (GYRO) & ADXL345 (ACCEL) - Arduino Example Algorithm // // Author: Gustavo Bertoli // // References: // https://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf // http://bildr.org/2011/03/adxl345-arduino/ // https://learn.sparkfun.com/tutorials/itg-3200-hookup-guide // https://www.sparkfun.com/datasheets/Sensors/Gyro/PS-ITG-3200-00-01.4.pdf // https://www.sparkfun.com/products/10121 #include <Wire.h> // I2C Devices Address #define GYRO 0x68 // ITG-3200 I2C Address - 0x68 #define ACCEL 0x53 // ADXL345 I2C Address - 0x53 // ITG-3200 (GYRO) REGISTERS #define GYRO_X_H 0x1D #define GYRO_X_L 0x1E #define GYRO_Y_H 0x1F #define GYRO_Y_L 0x20 #define GYRO_Z_H 0x21 #define GYRO_Z_L 0x22 #define DLPF_FS 0x16 #define SMPLRT_DIV 0x15 // ADXL345 (ACCEL) REGISTERS #define ACCEL_X_L 0x32 #define ACCEL_X_H 0x33 #define ACCEL_Y_L 0x34 #define ACCEL_Y_H 0x35 #define ACCEL_Z_L 0x36 #define ACCEL_Z_H 0x37 #define POWER_CTL 0x2D #define DATA_FORMAT 0x31 //ITG-3200 //DLPF, Full Scale Register Bits //FS_SEL must be set to 3 for proper operation //Set DLPF_CFG to 3 for 1kHz Fint and 42 Hz Low Pass Filter char DLPF_CFG_0 = 1<<0; char DLPF_CFG_1 = 1<<1; char DLPF_CFG_2 = 1<<2; char DLPF_FS_SEL_0 = 1<<3; char DLPF_FS_SEL_1 = 1<<4; byte adxl345[6]; void setup() { //Set serial communication at 9600 baudrate Serial.begin(9600); //Initialize the I2C communication. Wire.begin(); //Set the gyroscope scale for the outputs to +/-2000 degrees per second writeI2C(GYRO, DLPF_FS, (DLPF_FS_SEL_0|DLPF_FS_SEL_1|DLPF_CFG_0)); //Set the sample rate to 100 hz writeI2C(GYRO, SMPLRT_DIV, 9); //to enable measurement mode in ADXL345 (measure bit) writeI2C(ACCEL, POWER_CTL, 0b00001000); //The DATA_FORMAT register controls the presentation of data to Register 0x32 through Register 0x37 //writeI2C(ACCEL, DATA_FORMAT, 0b0000); } void loop() { int data = 0; int x, y ,z; //acceleration - ADXL345 Serial.println(""); Serial.println("=============================="); Serial.println("=ACCELEROMETER DATA (ADXL345)="); Serial.println("=============================="); readI2C(ACCEL,ACCEL_X_L,6); //ADXL345 multiple-byte read to prevent a change in data between reads of sequential registers // each axis reading comes in 10 bit resolution, ie 2 bytes. Least Significat Byte first!! // thus we are converting both bytes in to one int x = (((int)adxl345[1]) << 8) | adxl345[0]; y = (((int)adxl345[3]) << 8) | adxl345[2]; z = (((int)adxl345[5]) << 8) | adxl345[4]; Serial.print("X-axis: "); Serial.print(x); Serial.print(" Y-axis: "); Serial.print(y); Serial.print(" Z-axis: "); Serial.print(z); Serial.println(""); Serial.println("=============================="); Serial.println("= GYROSCOPE DATA (ITG-3200) ="); Serial.println("=============================="); //Angular velocity on x axis data = readRoll(); Serial.print("Roll: "); Serial.print(data); //Angular velocity on y axis data = readPitch(); Serial.print(" Pitch: "); Serial.print(data); //Angular velocity on z axis data = readYaw(); Serial.print(" Yaw: "); Serial.print(data); delay(10000); } int readRoll (void){ int data = 0; data = readI2C(GYRO, GYRO_X_H,1)<<8; data |= readI2C(GYRO, GYRO_X_L,1); return data; } int readPitch (void){ int data = 0; data = readI2C(GYRO, GYRO_Y_H,1)<<8; data |= readI2C(GYRO, GYRO_Y_L,1); return data; } int readYaw (void){ int data = 0; data = readI2C(GYRO, GYRO_Z_H,1)<<8; data |= readI2C(GYRO, GYRO_Z_L,1); return data; } // function to read from a device on I2C bus byte readI2C(byte devAddress, byte devRegister, int numBytes){ byte data = 0; int aux = 0; Wire.beginTransmission(devAddress); //Set device address on I2C bus Wire.write(devRegister); //Set register to read from device Wire.endTransmission(); //Stop Wire.beginTransmission(devAddress); //Set device address on I2C bus Wire.requestFrom(devAddress, numBytes); //read data if (numBytes == 1) { if (Wire.available()){ data = Wire.read(); } } else { //ADXL345 multiple-byte read to prevent a change in data between reads of sequential registers while (Wire.available()){ adxl345[aux] = Wire.read(); aux++; } } Wire.endTransmission(); return data; } // function to write in a device on I2C bus void writeI2C(byte devAddress, byte devRegister, byte devData){ Wire.beginTransmission(devAddress); //Start tx - set device address on I2C bus Wire.write(devRegister); //Set register from I2C device Wire.write(devData); //Set value to register Wire.endTransmission(); //Stop tx }
Result:
