The L3GD20 sensor is a low power chip that measures angular velocity. In other words, it is a component that senses motion and changes in orientation. It can communicate with other chips using either SPI (Serial Peripheral Interface) or I2C (Inter-Integrated Circuit) communication protocol. The L3GD20 has a full scale of ±250/±500/±2000 dps (degree per second) and is capable of measuring rates with a user-selectable bandwidth. Since this is a triple axis gyroscope, it measures rotation around three axes (x, y, z), thus, providing us with a value for each axis. Some applications for gyroscopes are for gaming, virtual reality, GPS navigation, and self-balancing robots, among other functions.  

In this tutorial, we are going to connect the Gyro sensor with six LEDs to show which direction angular rate is taking place.

Materials:

Project Assembly:
The L3GD20 Gyro sensor is soldered with 8 straight pins. The soldered sensor will look like this:


Figure 2: Gyro sensor

Connections:

  • VCC – 3.3V
  • GND – GND
  • SDO – GND
  • CS – VCC
  • SCL – A5
  • SDA – A4
  • Red LED – A7
  • Green LED – A5
  • Blue LED – A3
  • Yellow LEDs – A2, A4, A6
  • Use resistors to ground the LEDs' cathodes

The complete connection should look like this:

Software Coding:
Complete code.

#include <Wire.h>
 
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
#define CTRL_REG5 0x24
 
int L3GD20_Address = 106; //I2C address of the L3GD20
 
int x;
int y;
int z;
 
void setup(){
 
  Wire.begin();
  Serial.begin(9600);
 
  Serial.println("starting up L3GD20");
  setupL3GD20(2000); // Configure L3GD20  - 250, 500 or 2000 deg/sec
  pinMode(2, OUTPUT); // X +Ve value
  pinMode(3, OUTPUT); // X -Ve value
  pinMode(4, OUTPUT); // Y +Ve value
  pinMode(5, OUTPUT); // Y -Ve value
  pinMode(6, OUTPUT); // Z +Ve value
  pinMode(7, OUTPUT); // Z -Ve value
 
  delay(100); //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
 
  //*********LED Functions************//
 
//*********** X- position LEDs*********// 
  if (x >= 1000)
  {
   
    digitalWrite(2, HIGH);
    digitalWrite(3, LOW);
  }
   else if (x <= -1000)
   {
     digitalWrite(3, HIGH);
     digitalWrite(2, LOW);
   }
   else
   {
       digitalWrite(2, LOW);
       digitalWrite(3, LOW);
   }
//*********** Y- position LEDs*********// 
  if (y >= 1000)
  {
    digitalWrite(4, HIGH);
    digitalWrite(5,LOW);
  }
  else if (y <= -1000)
  {
    digitalWrite(5, HIGH);
    digitalWrite(4, LOW);
  }
   else
   {
       digitalWrite(4, LOW);
       digitalWrite(5, LOW);
   }
//*********** Z- position LEDs*********// 
  if (z >= 1000)
   {
     digitalWrite(6, HIGH);
     digitalWrite(7, LOW);
   }
   else if (z <= -1000)
   {
     digitalWrite(7, HIGH);
     digitalWrite(6, LOW);
   }
   else
   {
       digitalWrite(7, LOW);
       digitalWrite(6, LOW);
   }
//************ LED funcitons ENDs****************//
 
}
 
void getGyroValues(){
 
  byte xMSB = readRegister(L3GD20_Address, 0x29);
  byte xLSB = readRegister(L3GD20_Address, 0x28);
  x = ((xMSB << 8) | xLSB);
 
  byte yMSB = readRegister(L3GD20_Address, 0x2B);
  byte yLSB = readRegister(L3GD20_Address, 0x2A);
  y = ((yMSB << 8) | yLSB);
 
  byte zMSB = readRegister(L3GD20_Address, 0x2D);
  byte zLSB = readRegister(L3GD20_Address, 0x2C);
  z = ((zMSB << 8) | zLSB);
}
 
int setupL3GD20(int scale){
  //From  Jim Lindblom of Sparkfun's code
 
  // Enable x, y, z and turn off power down:
  writeRegister(L3GD20_Address, CTRL_REG1, 0b00001111);
 
  // If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
  writeRegister(L3GD20_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(L3GD20_Address, CTRL_REG3, 0b00001000);
 
  // CTRL_REG4 controls the full-scale range, among other things:
 
  if(scale == 250){
    writeRegister(L3GD20_Address, CTRL_REG4, 0b00000000);
  }else if(scale == 500){
    writeRegister(L3GD20_Address, CTRL_REG4, 0b00010000);
  }else{
    writeRegister(L3GD20_Address, CTRL_REG4, 0b00110000);
  }
 
  // CTRL_REG5 controls high-pass filtering of outputs, use it
  // if you'd like:
  writeRegister(L3GD20_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;
}

Code explanation:

#include<Wire.h>
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
#define CTRL_REG5 0x24
int L3GD20_Address = 106
int x;
int y;
int z;

In this part of the code the Wire library is included. This library allows the Arduino Uno to communicate with I2C / TWI (Two Wire Interface) devices. Also, the control registers for the L3GD20 Gyro sensor are defined. Each register is used to configure the chip during initialization. For instance, register 0x20 is used to enable the x, y, and z axes. Register 0x21 is used to set a high pass filter. Register 0x22 is used to control the internal interrupts of the chip. Register 0x23 is used to control the full scale range. Register 0x24 is used to control the high pass filtering of the outputs. Then the slave address for our device is declared. If we refer to the L3GD20 datasheet, we can see that the address associated with the L3GD20 is 110101xb. The SAO pin in our gyroscope allows us to choose the last bit of the address by setting it high or low. Thus, we have two possible addresses: 1101010 or 1101011. In this tutorial we decided to ground SAO, so our slave address is 1101010, or 106 in decimal. Lastly x, y, and z are declared as integer variables to hold the values measured by the gyroscope on each axis. 

void setup(){
  Wire.begin();
  Serial.begin(9600);
  Serial.println("starting up L3GD20");
  setupL3GD20(2000); // Configure L3GD20  - 250, 500 or 2000 deg/sec
  pinMode(2, OUTPUT); // X +Ve value
  pinMode(3, OUTPUT); // X -Ve value
  pinMode(4, OUTPUT); // Y +Ve value
  pinMode(5, OUTPUT); // Y -Ve value
  pinMode(6, OUTPUT); // Z +Ve value
  pinMode(7, OUTPUT); // Z -Ve value 
  delay(100); //wait for the sensor to be ready
}

In the setup section, we initiate the Wire library and set the baud rate for serial communication. Then we call the function “setupL3GD20” with the scale of degrees per seconds that we want as its argument. Finally, we set the LEDs as outputs and create a delay of 100ms. 

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 
  //*********LED Functions************//
//*********** X- position LEDs*********// 
  if (x >= 1000)
  {
    digitalWrite(2, HIGH);
    digitalWrite(3, LOW);
  }
   else if (x <= -1000)
   {
     digitalWrite(3, HIGH);
     digitalWrite(2, LOW);
   }
   else
   {
       digitalWrite(2, LOW);
       digitalWrite(3, LOW);
   }
//*********** Y- position LEDs*********// 
  if (y >= 1000)
  {
    digitalWrite(4, HIGH);
    digitalWrite(5,LOW);
  }
  else if (y <= -1000)
  {
    digitalWrite(5, HIGH);
    digitalWrite(4, LOW);
  }
   else
   {
       digitalWrite(4, LOW);
       digitalWrite(5, LOW);
   }
//*********** Z- position LEDs*********// 
  if (z >= 1000)
   {
     digitalWrite(6, HIGH);
     digitalWrite(7, LOW);
   }
   else if (z <= -1000)
   {
     digitalWrite(7, HIGH);
     digitalWrite(6, LOW);
   }
   else
   {
       digitalWrite(7, LOW);
       digitalWrite(6, LOW);
   }
//************ LED funcitons ENDs****************//
}

In the loop, we call the function “getGyroValues” to get the x, y, and z values measured by the gyroscope. Then we print them in the serial monitor and create a delay of 100ms. to slow down the transmission of data and make the values readable. Finally, we check if x, y, and z are less than or greater than 1000. Each case will turn on or off a corresponding LED to visually see what condition has been met.  

void getGyroValues(){
 
  byte xMSB = readRegister(L3GD20_Address, 0x29);
  byte xLSB = readRegister(L3GD20_Address, 0x28);
  x = ((xMSB << 8) | xLSB);
 
  byte yMSB = readRegister(L3GD20_Address, 0x2B);
  byte yLSB = readRegister(L3GD20_Address, 0x2A);
  y = ((yMSB << 8) | yLSB);
 
  byte zMSB = readRegister(L3GD20_Address, 0x2D);
  byte zLSB = readRegister(L3GD20_Address, 0x2C);
  z = ((zMSB << 8) | zLSB);
}

In the “getGyroValues” function, we read the raw data measured by the L3GD20 gyroscope and store it in the variables of x, y, and z respectively. 

int setupL3GD20(int scale){
  //From  Jim Lindblom of Sparkfun's code
  // Enable x, y, z and turn off power down:
  writeRegister(L3GD20_Address, CTRL_REG1, 0b00001111);
  // If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
  writeRegister(L3GD20_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(L3GD20_Address, CTRL_REG3, 0b00001000);
  // CTRL_REG4 controls the full-scale range, among other things:
  if(scale == 250){
    writeRegister(L3GD20_Address, CTRL_REG4, 0b00000000);
  }else if(scale == 500){
    writeRegister(L3GD20_Address, CTRL_REG4, 0b00010000);
  }else{
    writeRegister(L3GD20_Address, CTRL_REG4, 0b00110000);
  }
  // CTRL_REG5 controls high-pass filtering of outputs, use it
  // if you'd like:
  writeRegister(L3GD20_Address, CTRL_REG5, 0b00000000);
}

The “setupL3GD20” function is used to configure our gyroscope by writing values to the registers defined earlier in the code. Refer to the datasheet (page 31) to see what each value is used for. For Control Register 4, we check what scale was chosen as the argument of the function to assign it a corresponding value.

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

The “writeRegister” function is used to send values to the registers using some of the Wire library’s functions. The function takes three arguments: the address of our device, the address of the register to which we want to send the value, and the value that we want to send. 

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 “readRegister” function is used to read values from the registers. In this case we use it to read the values from the registers that hold the raw data for x, y, and z. Once again, we use some of the Wire library’s functions to accomplish this. 

Output:

Once the code is uploaded, the output can be viewed in the serial monitor. When the sensor is kept flat, without any rotation, we get the following values:  

When the sensor is rotated along the z-axis in one direction, the values of z will be negative and higher, and the red LED will turn on. When the sensor is rotated along the z-axis in the opposite direction, the values of z will be positive and higher, and the yellow LED will turn on. 

When the sensor is rotated along the y-axis in one direction, the values of y will be negative and higher, and the green LED will turn on. When the sensor is rotated along the y-axis in the opposite direction, the values of y will be positive and higher, and the yellow LED will turn on. 

When the sensor is rotated along the x-axis in on direction, the values of x will be negative and higher, and the green LED will turn on. When the sensor is rotated along the x-axis in the opposite direction, the values of x will be positive and higher, and the yellow LED will turn on.

Now that you know how to use a gyroscope sensor and how it works, you can create your own project like a self-stabilizing platform or even a self-balancing robot.

If you have any questions about this tutorial, do not hesitate to post a comment, shoot us an email, or post it in our forum.