I am intending to use a GY87 board on my Homebuilt VR system. This is a 10 degree of freedom device which incorporates an MPU6050 accelerometer and gyro chip, an HMC5883L digital compass, and a BMP180 barometer. These are all common chips and there is plenty of code around for each of them.

I have used the HMC5883L digital compass and the BMP180 barometer in some of my ROV related projects. You can find them here:

In the first instance I wanted to test that sensors reported something useful and combine this into a single sketch. I quickly discovered that the HMC5883L was not reporting and would not even appear in any i2c port scans that I carried out. It appears that the MPU6050 somehow blocks the HMC5883L. Thanks to the work of pistolero992000 on the Arduino forum who worked through the issue and described the solution. This page brings together a number of sketches for each of the sensors on the GY87 board into one sketch, adds the fix for the HMC5883L, and writes the data output to the Serial. I cannot lay claim to any of the original coding because it really has been an exercise in copying and pasting it all together from the work of others.

I have taken the liberty of bundling the libraries used into a zip file for convenience and have a working snapshot of the libraries. I would recommend you go to the home project pages for these libraries to get the latest versions. The extra libraries used are:

MPU6050, i2cdevlib, and HMC5883L libraries from Jeff Rowberg.

and the BMP180 library from love Electronics Ltd: BMP180 Library

You can download the zip packaged containing these libraries from here: GY87_Library_Collection.zip

I developed this with Arduino IDE 1.6.8. Some of the older versions cannot handle these libraries.

The Circuit

Here are the connections.

  • SCL to Arduino Pin A5
  • SDA to Arduino Pin A4
  • GND, 5V and 3.3V connections

GY87 Testing Connections to Arduino Nano

The Code

Here is the Arduino Code. The output is a tab separated list on the serial monitor. Because there is so much data the list gets a little ugly and so you will probably want to widen your Serial monitor window as much as you can to accommodate: it all. The data from the accelerometer and gyros is in a raw form and would require further processing to get angles as an output. In Jeff Rowberg’s example for the MPU6050 he gives the option of a binary output. This is faster, but not human readable. Depending on lag in the system when the VR system is running, it may be necessary to use the binary output directly for the sake of speed. We’ll see about that when I get there.

You can download this sketch from here: GY87_Readerv0.ino

/*
GY87_Readerv0.ino
This sketch is based on various sketches and libraries by Jeff Rowberg
<jeff@rowberg.net> and discussion thread by pistolero992000 on the Arduino forum
https://forum.arduino.cc/index.php?topic=223345.0.  The BMP180 pressure
Senor library is from Love Electronics Ltd (loveelectronics.com)
http://embedded-lab.com/blog/bmp180/bmp180_11/

It gets all sensors on a GY87 IMU board reporting (something) to the
Serial.  The challenge is the Digital Compass which is nromally blocked by
the Accelerometer.  This is remedied by using an I2C bypass command.  Thanks to
pistolero992000 for this solution.

Sensors on board the GY87 are:
MPU6050 Accelerometer.  Address is 0x68
HMC5883L Digital Compass.  Address is 0x1E
BMP180 Barometer and Temperature Sensor.  Address is 0x77

Connections are through the i2c bus.

SCL to Arduino Pin A5
SDA to Arduino Pin A4
GND, 5V and 3.3V connections also present.

All sensors report sensible values.  The tab seperated data covers a lot of screen space
so you will need to stretch your Serial monitor window to accommodate: it.

*/

#include "I2Cdev.h"
#include "MPU6050.h"
#include "Wire.h"
#include <BMP180.h>  //Library for the BMP180 barometer.

//MPU6050 Accelerometer 
MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;

//HMC5883L Digital Compass
const int hmc5883Address = 0x1E; //0011110b, I2C 7bit address for compass
const byte hmc5883ModeRegister = 0x02;
const byte hmcContinuousMode = 0x00;
const byte hmcDataOutputXMSBAddress = 0x03;

//The BMP180 Digital Barometer
BMP180 barometer;
// Store the current sea level pressure at your location in Pascals.
float seaLevelPressure = 101325;

int LEDPin = 13;
bool blinkState = false;

int x,y,z; //triple axis data from HMC5883L.

void setup() {
    Wire.begin();
    Serial.begin(9600);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
    accelgyro.setI2CBypassEnabled(true);  //This sets the bypass so the HMC5883L gets a look in.

      
    //Initialise the Digital Compass
    Wire.beginTransmission(hmc5883Address);  //Begin communication with compass
    Wire.write(hmc5883ModeRegister);  //select the mode register
    Wire.write(hmcContinuousMode); //continuous measurement mode
    Wire.endTransmission();
    
    //Initialise the BMP180 Barometer (and Temperature Sensor)
    barometer = BMP180();
    // We check to see if we can connect to the BMP180 sensor.
    if(barometer.EnsureConnected())
    {
      Serial.println("Connected to BMP180.");
       // When we have connected, we reset the device to ensure a clean start.
      barometer.SoftReset();
      // Now we initialize the sensor and pull the calibration data.
      barometer.Initialize();
    }
    else
    { 
      Serial.println("No BMP180 sensor found.");
    }
    
    // configure Arduino LED for
    pinMode(LEDPin, OUTPUT);
    delay(10000);
}

void loop() {
    
    // read raw accel/gyro measurements from device
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    // these methods (and a few others) are also available
    //accelgyro.getAcceleration(&ax, &ay, &az);
    //accelgyro.getRotation(&gx, &gy, &gz);

    // display tab-separated accel/gyro x/y/z values
    Serial.print("a/g:\t");
    Serial.print(ax); Serial.print("\t");
    Serial.print(ay); Serial.print("\t");
    Serial.print(az); Serial.print("\t");
    Serial.print(gx); Serial.print("\t");
    Serial.print(gy); Serial.print("\t");
    Serial.print(gz); Serial.print("\t");

    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LEDPin, blinkState);
    
    //Accessing the HMC5883L Digital Compass  
    //Tell the HMC5883L where to begin reading the data
    Wire.beginTransmission(hmc5883Address);
    Wire.write(hmcDataOutputXMSBAddress);  //Select register 3, X MSB register
    Wire.endTransmission();
  
    //Read data from each axis of the Digital Compass
    Wire.requestFrom(hmc5883Address,6);
    if(6<=Wire.available())
    {
      x = Wire.read()<<8; //X msb
      x |= Wire.read();   //X lsb
      z = Wire.read()<<8; //Z msb
      z |= Wire.read();   //Z lsb
      y = Wire.read()<<8; //Y msb
      y |= Wire.read();   //Y lsb    
    }
  
    int angle = atan2(-y,x)/M_PI*180;
    if (angle < 0)
    {
      angle = angle + 360;
    }
  
    //Reporting the Compass data to the Serial port
    //Serial.print("Compass XYZ:\t");
    //Serial.print(x,y,z);Serial.print("\t");
    Serial.print("Dir(deg):\t");
    Serial.print(angle); Serial.print("\t");
    
    if(barometer.IsConnected)
    {
      long currentPressure = barometer.GetPressure();
      
      // Print out the Pressure.
      Serial.print("BMP180 P:\t");
      Serial.print(currentPressure);Serial.print("Pa");Serial.print("\t");
            
      // Retrieve the current altitude (in meters). Current Sea Level Pressure is required for this.
      float altitude = barometer.GetAltitude(seaLevelPressure);
    
      // Print out the Altitude.
      Serial.print("Alt:\t");
      Serial.print(altitude);Serial.print(" m");Serial.print("\t");
    
      // Retrieve the current temperature in degrees celcius.
      float currentTemperature = barometer.GetTemperature();
    
      // Print out the Temperature
      Serial.print("Temp:\t");
      Serial.print(currentTemperature);Serial.println("C");
    }   
}