How to make the GY-87 work probably ?

Hello,
First I wish anyone could help me here, this is my first post on arduino.

I bought a GY-87 10-DOF-IMU Chip that I'm willing to use for my quad-copter project later after I first know how to make it work.

After searching and trying between many codes, I could make the BMP work or at least it's getting a believable reads.

The MPU also is working fine except that the code doesn't showing the Z axis which I need and can't really understand how to get it, it's using KALMAN filter btw.

finally the real problem, the HMC, GY-87 comes with a HMC5883L, which was stuck at 50.3 degrees, after modifications and combining an I2C code, it could work but when I rotate it the value changes only from 200 to 350 or so, it's not working fine ...

How to make the compass (HMC5883L) work functionally
How to get the Z axis of the MPU6050

wish anyone could answer me cuz I'm really disappointed with that sensor :confused:

The main code :-

#include "Kalman.h" 
#include <Wire.h>
#include <HMC5883L.h>
#include <Adafruit_BMP085.h>

Adafruit_BMP085 bmp;
HMC5883L compass;

int error = 0;
int ac1 ,ac2 ,ac3;
int b1,b2,mb,mc,md,b5;

const unsigned char OSS = 0;  
unsigned int ac4 ,ac5 ,ac6;

Kalman kalmanX; Kalman kalmanY;

double accX, accY, accZ,gyroX, gyroY, gyroZ;
double gyroXangle, gyroYangle, compAngleX, compAngleY, kalAngleX, kalAngleY;

int16_t tempRaw;

uint32_t timer;
uint8_t i2cData[14];


void setup() {
  Serial.begin(115200);
  Wire.begin();
  
  TWBR = ((F_CPU / 400000L) - 16) / 2; 
  
  i2cData[0] = 7; 
  i2cData[1] = 0x00; 
  i2cData[2] = 0x00; 
  i2cData[3] = 0x00; 
  
  while (i2cWrite(0x19, i2cData, 4, false)); 
  while (i2cWrite(0x6B, 0x01, true)); 
  while (i2cRead(0x75, i2cData, 1));
  if (i2cData[0] != 0x68) { 
  Serial.print(F("Error reading sensor"));
  while (1);
  Serial.println("Starting the I2C interface.");
  Serial.println("Constructing new HMC5883L");
  compass = HMC5883L(); 
  Serial.println("Setting scale to +/- 1.3 Ga");
  error = compass.SetScale(1.3); 
  if(error != 0) 
  Serial.println(compass.GetErrorText(error));
  Serial.println("Setting measurement mode to continous.");
  error = compass.SetMeasurementMode(Measurement_Continuous); 
  if(error != 0) 
  Serial.println(compass.GetErrorText(error));
  }
  
  delay(100);
  
  if (!bmp.begin()) {
	Serial.println("Could not find a valid BMP085 sensor, check wiring!");
	while (1) {}
  }
  
  delay(100); 
  while (i2cRead(0x3B, i2cData, 6));
  accX = (i2cData[0] << 8) | i2cData[1];
  accY = (i2cData[2] << 8) | i2cData[3];
  accZ = (i2cData[4] << 8) | i2cData[5];
#ifdef RESTRICT_PITCH 
  double roll  = atan2(accY, accZ) * RAD_TO_DEG;
  double pitch = atan(-accX / sqrt(accY * accY + accZ * accZ)) * RAD_TO_DEG;
#else 
  double roll  = atan(accY / sqrt(accX * accX + accZ * accZ)) * RAD_TO_DEG;
  double pitch = atan2(-accX, accZ) * RAD_TO_DEG;
#endif
  kalmanX.setAngle(roll); // Set starting angle
  kalmanY.setAngle(pitch);
  gyroXangle = roll;
  gyroYangle = pitch;
  compAngleX = roll;
  compAngleY = pitch;
  timer = micros();
}

void loop() {
  
      //****************** BMP085 *****************\\
 
  float temperature = bmp.readTemperature();
  float pressure = bmp.readPressure();
  float atm = bmp.readSealevelPressure();
  float altitude = bmp.readAltitude();
  
  Serial.print("Standard Atmosphere: ");
  Serial.println(pressure / 101325, 4); //display 4 decimal places
  
  Serial.print("Pressure at sealevel (calculated) = ");
  Serial.print(atm, 4);
  Serial.println(" Pa");
    
  Serial.print("Temperature: ");
  Serial.print(temperature, 2); //display 2 decimal places
  Serial.println("deg C");
  
  Serial.print("Altitude: ");
  Serial.print(altitude, 2); //display 2 decimal places
  Serial.println(" M");
  
  Serial.println();//line break
  
  delay(500); //wait a second and get values again.
 
 //******************** MBU6050 ************************\\
 
  while (i2cRead(0x3B, i2cData, 14));
  accX = ((i2cData[0] << 8) | i2cData[1]);
  accY = ((i2cData[2] << 8) | i2cData[3]);
  accZ = ((i2cData[4] << 8) | i2cData[5]);
  tempRaw = (i2cData[6] << 8) | i2cData[7];
  gyroX = (i2cData[8] << 8) | i2cData[9];
  gyroY = (i2cData[10] << 8) | i2cData[11];
  gyroZ = (i2cData[12] << 8) | i2cData[13];
  double dt = (double)(micros() - timer) / 1000000; // Calculate delta time
  timer = micros();
#ifdef RESTRICT_PITCH // Eq. 25 and 26
  double roll  = atan2(accY, accZ) * RAD_TO_DEG;
  double pitch = atan(-accX / sqrt(accY * accY + accZ * accZ)) * RAD_TO_DEG;
#else // Eq. 28 and 29
  double roll  = atan(accY / sqrt(accX * accX + accZ * accZ)) * RAD_TO_DEG;
  double pitch = atan2(-accX, accZ) * RAD_TO_DEG;
#endif
  double gyroXrate = gyroX / 131.0; // Convert to deg/s
  double gyroYrate = gyroY / 131.0; // Convert to deg/s
#ifdef RESTRICT_PITCH
 if ((roll < -90 && kalAngleX > 90) || (roll > 90 && kalAngleX < -90)) {
    kalmanX.setAngle(roll);
    compAngleX = roll;
    kalAngleX = roll;
    gyroXangle = roll;
  } else
    kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter
  if (abs(kalAngleX) > 90)
    gyroYrate = -gyroYrate; // Invert rate, so it fits the restriced accelerometer reading
    kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt);
#else
  if ((pitch < -90 && kalAngleY > 90) || (pitch > 90 && kalAngleY < -90)) {
    kalmanY.setAngle(pitch);
    compAngleY = pitch;
    kalAngleY = pitch;
    gyroYangle = pitch;
  } else
    kalAngleY = kalmanY.getAngle(pitch, gyroYrate, dt); // Calculate the angle using a Kalman filter
  if (abs(kalAngleY) > 90)
    gyroXrate = -gyroXrate; // Invert rate, so it fits the restriced accelerometer reading
  kalAngleX = kalmanX.getAngle(roll, gyroXrate, dt); // Calculate the angle using a Kalman filter
#endif
  gyroXangle += gyroXrate * dt; // Calculate gyro angle without any filter
  gyroYangle += gyroYrate * dt;
  compAngleX = 0.93 * (compAngleX + gyroXrate * dt) + 0.07 * roll; // Calculate the angle using a Complimentary filter
  compAngleY = 0.93 * (compAngleY + gyroYrate * dt) + 0.07 * pitch;
#if (gyroXangle < -180 || gyroXangle > 180)
  gyroXangle = kalAngleX;
#endif
#if (gyroYangle < -180 || gyroYangle > 180)
  gyroYangle = kalAngleY;
#endif
  Serial.print("Roll (X)");Serial.print(kalAngleX); Serial.print("\t");
  Serial.print("Pitch (Y)"); Serial.print(kalAngleY); Serial.print("\t");

  delay(2);
  
  //********************** compass ***************************\\
  
 MagnetometerRaw raw = compass.ReadRawAxis();
 MagnetometerScaled scaled = compass.ReadScaledAxis();
 int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)
 float heading = atan2(scaled.YAxis, scaled.XAxis);
 float declinationAngle = 0.0215;
 heading += declinationAngle;
 if(heading < 0)
 heading += 2*PI;
 if(heading > 2*PI)
 heading -= 2*PI;
 float headingDegrees = heading * 180/M_PI; 
 Output(headingDegrees);
}
void Output(float headingDegrees)
{  
  Serial.print("Compass Heading:\t");
  Serial.print(headingDegrees);
  Serial.println(" Degrees   \t");
  
  delay(100);
}

there is another tab for KALMAN.h and I2C, u can find them here :-
Project Files
Project Libs

Do you want to print the compass direction the sensor is pointed in, or do you want the raw acceleration in the Zth direction?

P.S. Kaman Filtering, IMU, DMP, Magnetometer.......This stuff can be quite complicated. How much experience with coding, electronics, and circuitry do you have?

Power_Broker:
Do you want to print the compass direction the sensor is pointed in, or do you want the raw acceleration in the Zth direction?

P.S. Kaman Filtering, IMU, DMP, Magnetometer.......This stuff can be quite complicated. How much experience with coding, electronics, and circuitry do you have?

Both, I want to print the compass direction and the Z axis of the gyroscope, they'r different since the Z axis of the gyro starts as zero when calibrated to the start position while I need the compass to identify the north direction.

And I'm pretty sure I can go with coding, but truthfully I've never used gyros or these stuff.

Thanx for ur reply :slight_smile: