SOLVED!!: WORKING WITH GY-87.... EVERYTHING OK BUT HMC5883L NOT WORKING AT ALL

Hi everybody,

First of all, I hope I am in the right forum.... XD

I'm building a project using an arduino DUE along with the GY-87, which is a 10Dof IMU....3 accel + 3 gyros (MPU-6050), barometer (BMP-180) and ... 3-axis magnetometer....

the MPU-6050 is working beautifully. XD
the BMP-180 is working beautifully.... but with the BMP-085 library... so I'm guessing that the GY-87 comes with that sensor... :~

Finally, the magnetometer is the HMC5883L, address 0x1E, and it's not working at all. I've tried many... many libraries with no results. I also read a lot of forums and posts, including what many wrote in arduino forums. =(

Has anyone been able to make the HMC5883L sensor work yet? :roll_eyes:

Can anybody point me in the right direction? :roll_eyes:

Thank you very much in advance for your time!!!

Hello pistolero992000,
Have you used Nick Gammon's I2C scanner to confirm that DUE recognize the address of the magnetometer?
here the code just in case:

// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// 
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>


void setup()
{
  Wire.begin();

  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknow error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}

I have used a different I2C magnetometer ADXL345 but at the moment I don't have the code at hand.

Regards, Palliser

Thank you very much Palliser,

I've tried the scanner a few times and always receive the message:
"Scanning...
No I2C devices found"

this actually is very funny since the GY-87 uses SDA/SCL to communicate with the arduino and there is no other device detected.... and I'm certain that the accel/gyros are working properly (address 0x68)... so I don't know what may be happening to the scanner??

I'm using the GY-87 through I2Cdev... maybe that's the problem...

other thing may be the 32-bit processor compatibility... I don't know that much of electronics.... XD

Any other hint?

thanks a lot in advance!!

Hi,

maybe it is the wiring, since I'm not using every pin of the GY-87....

Can someone explain this electronic amateur the use of PINs named:
FSYNC
INTA
DRDY

I know that keeping INTA connected to GND I access the MPU6050 gyros and accelerometers...
Using I2C scanner, the only device detected is the MPU at address 0x68, which is OK, but I know there should be 3 devices detected... MPU, BMP and HMC.... so testing with the PINS I realized that pulling DRDY to GND momentarily during the scanning process, a new device is detected... at address 0x77 which I believe is the BMP sensor... but the HMC at 0x1E.... nothing...

I tried it with an Arduino MEGA 2560 and I had the same results...

could it be possible that the HMC may be damaged or broken???

:~ :~ :~ :~ :~ :~ :~

datasheet and/or schematic important! It will lead to the answer to your problem
A_INT.. interrupt from accelerometer ?
G_INT.. interrupt from gyro ?
M_DRDY.. magnetometer - data ready?
I'd leave theese the pins alone. (floating)

I found something interesting...at this address...

http://aeroquad.com/showthread.php?8449-Trouble-with-sensor-detection&p=71806#post71806

that should be the answer.... I'm digging in the h & cpp file....

:cold_sweat:

What GY-87 do you have? A quick google and I come up with this that looks similar to a 9DOF I was messing with this morning.
The code that worked for me is below. It came from Sparkfun but I don't have the link any more.

/*
An Arduino code example for interfacing with the HMC5883 3-Axis Digital Compass

by: Jordan McConnell
 SparkFun Electronics
 created on: 6/30/11
 license: OSHW 1.0, http://freedomdefined.org/OSHW

Analog input 4 I2C SDA
Analog input 5 I2C SCL
*/

#include <Wire.h> //I2C Arduino Library

#define address 0x1E //0011110b, I2C 7bit address of HMC5883

int aX,aY,aZ;

void setup(){
  //Initialize Serial and I2C communications
  Serial.begin(115200);
  Wire.begin();
  
  //Put the HMC5883 IC into the correct operating mode
  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.write(0x02); //select mode register
  Wire.write(0x00); //continuous measurement mode
  Wire.endTransmission();
}

void loop(){
  
  int x,y,z; //triple axis data

  //Tell the HMC5883 where to begin reading data
  Wire.beginTransmission(address);
  Wire.write(0x03); //select register 3, X MSB register
  Wire.endTransmission();
  
 
 //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 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
  }
  
  aX = (aX + x) / 2;
  aY = (aY + y) / 2;
  aZ = (aZ + z) / 2;
  
  //Print out values of each axis
  Serial.print("x: ");
  Serial.print(aX);
  Serial.print("  y: ");
  Serial.print(aY);
  Serial.print("  z: ");
  Serial.println(aZ);
  
  delay(250);
}

FINALLY!!!!

the issue was:

inside the GY-87 the HMC is in a different I2C bus? which has to be enabled, otherwise, the MPU wont be able to read anything from it....

I added this code to my 'void setup' being accelgyro the MPU object:

accelgyro.setI2CBypassEnabled(true);

After this, I don't get a very real value of the heading, but.... at least I get something: ACCESS TO THE HMC5883L!!!!!!

I'll continue posting with the solution to a correct heading indication.... some math to do....

cheers!!!

:slight_smile: :slight_smile: :slight_smile:

Hola
pistolero992000
He comprado una placa Gy-87 y estoy a la espera de recibirla
Podrias facilitarme alguna informacion de como has conseguido hacerla funcionar

Gracias
juanelete5@hotmail.com

¡¡¡Disculpa la demora!!!

#include "I2Cdev.h"
#include "MPU6050.h"
#include "Kalman.h" // Source: https://github.com/TKJElectronics/KalmanFilter

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif

#define GYRORATE_SEL 2000
#define ACCELRATE_SEL 16

MPU6050 accelgyro;
Kalman kalmanX; // Create the Kalman instances
Kalman kalmanY;

/* IMU Data */
int16_t ax, ay, az;
int16_t tempRaw;
int16_t gx, gy, gz;
float temp; // Temperature
float kalAngleX, kalAngleY; // Calculate the angle using a Kalman filter
uint32_t timer;
float fXg = 0;
float fYg = 0;
float fZg = 0;
float pitch, roll;
float Xg, Yg, Zg;
float gXg, gYg, gZg;
float gyroXrate, gyroYrate, gyroZrate;

void setup() {

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
#endif
  Serial.begin(115200);

  accelgyro.initialize();
  char text[256];
  sprintf(text, "%s", accelgyro.testConnection() ? "MPU6050 successful" : "MPU6050 failed");
  Serial.println(text);

  //************ COMPASS CODE ****************
  accelgyro.setI2CBypassEnabled(true);            // HMC5883L enable
  compass_x_offset = 122.17;
  compass_y_offset = 230.08;
  compass_z_offset = 389.85;
  compass_x_gainError = 1.12;
  compass_y_gainError = 1.13;
  compass_z_gainError = 1.03;

  //accelgyro.setXAccelOffset(-1025);
  //accelgyro.setYAccelOffset(1244);//1283
  //accelgyro.setZAccelOffset(1277);
  //accelgyro.setXGyroOffset(114);
  //accelgyro.setYGyroOffset(64);
  //accelgyro.setZGyroOffset(-1);
  sprintf(text, "Setting %d  DEG/s", GYRORATE_SEL);
  Serial.print(text);
  switch (GYRORATE_SEL) {
    case 250:
      accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_250);
      break;
    case 500:
      accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_500);
      break;
    case 1000:
      accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_1000);
      break;
    case 2000:
      accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
      break;
  }

  Serial.println("Done!");
  sprintf(text, "Setting %d  Gs", ACCELRATE_SEL);
  Serial.print(text);
  switch (ACCELRATE_SEL) {
    case 2:
      accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
      break;
    case 4:
      accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_4);
      break;
    case 8:
      accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_8);
      break;
    case 16:
      accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_16);
      break;
  }
  Serial.println("Done!");

// reading MPU for the first time
  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  //Low Pass Filter---> this actually smooths the readings
  Xg = ax * (ACCELRATE_SEL / pow(2, 15));
  Yg = ay * (ACCELRATE_SEL / pow(2, 15));
  Zg = -az * (ACCELRATE_SEL / pow(2, 15));

  gXg = gx * (ACCELRATE_SEL / pow(2, 15));
  gYg = gy * (ACCELRATE_SEL / pow(2, 15));
  gZg = gz * (ACCELRATE_SEL / pow(2, 15));

  fXg = Xg * alpha + (fXg * (1.0 - alpha));
  fYg = Yg * alpha + (fYg * (1.0 - alpha));
  fZg = Zg * alpha + (fZg * (1.0 - alpha));

  pitch = atan2(fYg, sqrt(fXg * fXg + fZg * fZg)) * RAD_TO_DEG;
  roll = atan2(fXg, fZg) * RAD_TO_DEG;
  timer = millis();
}

void loop() {
  Get_Values();
  char text[256];
  sprintf(text,"Pitch: %03d Roll: %03d Kalman Pitch: %03d Kalman Roll: %03d", pitch, roll, kalAngleX, kalAngleY);
  Serial.println(text);
}

void Get_Values()
{
  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  //Low Pass Filter
  Xg =    ax * (ACCELRATE_SEL / pow(2, 15));
  Yg =    ay * (ACCELRATE_SEL / pow(2, 15));
  Zg =   -az * (ACCELRATE_SEL / pow(2, 15));
  
  gXg =   gx * (ACCELRATE_SEL / pow(2, 15));
  gYg =   gy * (ACCELRATE_SEL / pow(2, 15));
  gZg =   gz * (ACCELRATE_SEL / pow(2, 15));
  
  fXg = Xg * alpha + (fXg * (1.0 - alpha));
  fYg = Yg * alpha + (fYg * (1.0 - alpha));
  fZg = Zg * alpha + (fZg * (1.0 - alpha));
  
  pitch = atan2(fYg, sqrt(fXg * fXg + fZg * fZg)) * RAD_TO_DEG;
  roll  = 180.00 - atan2(fXg, fZg) * RAD_TO_DEG;

  gyroXrate =  (float)gx / (GYRORATE_SEL == 250 ? 131.0 : GYRORATE_SEL == 500 ? 65.5 : GYRORATE_SEL == 1000 ? 32.8 : 16.4);
  gyroYrate = -(float)gy / (GYRORATE_SEL == 250 ? 131.0 : GYRORATE_SEL == 500 ? 65.5 : GYRORATE_SEL == 1000 ? 32.8 : 16.4);
  gyroZrate =  (float)gz / (GYRORATE_SEL == 250 ? 131.0 : GYRORATE_SEL == 500 ? 65.5 : GYRORATE_SEL == 1000 ? 32.8 : 16.4);

  kalAngleX = kalmanX.getAngle(pitch, gyroXrate, (float)(micros() - timer) / 1000000); //  - float(180.00)  Calculate the angle using a Kalman filter
  kalAngleY = kalmanY.getAngle(roll , gyroYrate, (float)(micros() - timer) / 1000000); //- float(180.00)
  timer = millis();
  temp = ((float)tempRaw + 12412.0) / 340.0;
}

Hello, I am using your code from last message, and it works, but shows greatly changing values)

Also before compiling it said, throw some errors:

sketch_feb28a.ino: In function 'void setup()':
sketch_feb28a.ino:47:3: error: 'compass_x_offset' was not declared in this scope
sketch_feb28a.ino:48:3: error: 'compass_y_offset' was not declared in this scope
sketch_feb28a.ino:49:3: error: 'compass_z_offset' was not declared in this scope
sketch_feb28a.ino:50:3: error: 'compass_x_gainError' was not declared in this scope
sketch_feb28a.ino:51:3: error: 'compass_y_gainError' was not declared in this scope
sketch_feb28a.ino:52:3: error: 'compass_z_gainError' was not declared in this scope
sketch_feb28a.ino:108:14: error: 'alpha' was not declared in this scope
sketch_feb28a.ino: In function 'void Get_Values()':
sketch_feb28a.ino:136:14: error: 'alpha' was not declared in this scope

So what is alpha?

Should say, that I am using Arduino Mega 2560, connected with gy-87 only with VCC, GND, SDA and SCL.

Some output:

Pitch: -826 Roll: 16827 Kalman Pitch: 27672 Kalman Roll: 17293
Pitch: 2465 Roll: 16826 Kalman Pitch: -27785 Kalman Roll: 17293
Pitch: 26008 Roll: 16828 Kalman Pitch: -22658 Kalman Roll: 17293
Pitch: 5691 Roll: 16824 Kalman Pitch: -27747 Kalman Roll: 17293
Pitch: 26584 Roll: 16825 Kalman Pitch: -3012 Kalman Roll: 17293
Pitch: -28995 Roll: 16828 Kalman Pitch: 29012 Kalman Roll: 17293
Pitch: 8188 Roll: 16827 Kalman Pitch: -23309 Kalman Roll: 17293
Pitch: 26103 Roll: 16829 Kalman Pitch: 28586 Kalman Roll: 17293
Pitch: 27104 Roll: 16826 Kalman Pitch: -12945 Kalman Roll: 17293
Pitch: -7257 Roll: 16826 Kalman Pitch: 31141 Kalman Roll: 17293
Pitch: 22127 Roll: 16825 Kalman Pitch: 29382 Kalman Roll: 17293
Pitch: -22504 Roll: 16825 Kalman Pitch: -25469 Kalman Roll: 17293

Please help me to setting the code) Maybe I should connect other pins?

Hello Pistolero992000:

I have a Gy-87 sensor, I have tried your code, but I have exactilly the same problem than NeaWeaR when I try to compile the code:

GY-87_10DOF.ino: In function 'void setup()':
GY-87_10DOF.ino:47: error: 'compass_x_offset' was not declared in this scope
GY-87_10DOF.ino:48: error: 'compass_y_offset' was not declared in this scope
GY-87_10DOF.ino:49: error: 'compass_z_offset' was not declared in this scope
GY-87_10DOF.ino:50: error: 'compass_x_gainError' was not declared in this scope
GY-87_10DOF.ino:51: error: 'compass_y_gainError' was not declared in this scope
GY-87_10DOF.ino:52: error: 'compass_z_gainError' was not declared in this scope
GY-87_10DOF.ino:108: error: 'alpha' was not declared in this scope
GY-87_10DOF.ino: In function 'void Get_Values()':
GY-87_10DOF.ino:136: error: 'alpha' was not declared in this scope

Do we need some addtional header or cpp file to compile
Regards!

Hi,
i have the solution without an external library. You have to set the bypass bits in the Register of the MPU6050 and turn off the sleep mode.

Registers for Bypass Mode:
0x37 to 0x02
0x6A to 0x00

Register for disable Sleep Mode
0x6B to 0x00

Here the Arduino Code

//Bypass Mode
Wire.beginTransmission(0x68);
Wire.write(0x37);
Wire.write(0x02);
Wire.endTransmission();

Wire.beginTransmission(0x68);
Wire.write(0x6A);
Wire.write(0x00);
Wire.endTransmission();

//Disable Sleep Mode
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();

you have to put it at the end of the setup() part of the i2c scanner sketch.

1 Like

How do i connect 2 GY-87 sensors on the same arduino via I2C bus?

hi! some body can help me with the functions of GY-87? What is exactly the role of that sensor? Can i have some code to program it? Plz

Sorry to bring up an old thread, If there is no reply I will Make a new thread.

I have purchased a gy87 clone (HW-290) and I am in the process of testing the module.

My setup is using Arduino IDE 1.87, NANO using atmega328P "old boot loader"

The pin outs and code are exactly the same as http://www.techmonkeybusiness.com/the-gy87-combined-sensor-test-sketch.html

Noting the obvious "can not find sensors" messages in serial monitor; I did an I2c sniff and got the following addresses on my arduino NANO

Scanning...
I2C device found at address 0x0D !
I2C device found at address 0x68 !
I2C device found at address 0x77 !
done

The following address is different to the one originality specified in this thread.

I2C device found at address 0x0D !

So my next task was to find the data sheet https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf

Page 26 7.11 states that there is a "Master" and "PassThrough" mode.

Page 28 7.13 states there is an "interface bypass multiplexer to get to the external compass sensor

Can some one please explain to me how on Page 38 section 10 ; how to set the conditions required to set the slave mode AND sniff for the addresses my module actually uses.

Thank you for reading

Hi Slant_Eng,

If you're getting the 0x0D I2C address then your GY-87 breakout board is using a QMC5883L, rather than a HMC5883L or HMC5983. (The HMC5983 is the same as the HMC5883L, but with temperature compensation).

Sadly, Honeywell discontinued the HMC5983/HMC5883L in 2016, but licensed the technology to QST Corporation, who now manufacture the replacement QMC5883L. However, while the QMC5883L is pin for pin compatible, its registers are not the same as the Honeywell device. It's essentially a different chip.

To make matters worse, QST Corporation have produced two versions of the QMC5883L:

  1. A completely undocumented 'A' version with "DA 5883" on the QFN package that responds to the I2C address 0x1E. It's identical to the HMC5983/HMC5883L, except (and I kid you not) that the status register doesn't work.

  2. A documented 'B' version with "DB 5833" on the QFN package that responds to I2C address 0x0D. This works as per the QMC5883L datasheet.

It looks like you've got the 'B' version of the QMC5883L on your GY-87 breakout board.

1 Like