How to get raw values from the MPU9250 Magnometer sensor or "AK8963"

Hello everyone, for the past month or so I have been attempting to make a working and accurate IMU (Inertial Measurement Unit) using the GY-91 sensor, which packs the BMP280 and MPU9250 sensor into one model. I plan on using this sensor for a personalized drone controller which I will power using an Arduino pro mini. The only problem is that I only have basic programming knowledge so I have to copy/paste a lot of the code I write. I have been all over the internet looking for code that works, but none of the library's or YouTube videos have yet to fully explain all the details. I have used duckduckgo's chat bot to help me along the way, but still AI can only do so much. Here is the code that I have come up with so far for reading the raw values of the MPU9250 sensor:

#include <SoftwareWire.h>

SoftwareWire myWire(3,2); SDA pin 3, SCL pin 2

const int MPU9250_ADDRESS = 0x68; // MPU9250 I2C address
const int ACCEL_XOUT_H = 0x3B;   // Register address for accelerometer X-axis high byte
const int GYRO_XOUT_H = 0x43;    // Register address for gyroscope X-axis high byte
const int MAG_XOUT_L = 0x03;     // Register address for magnetometer X-axis low byte

void setup() {
  myWire.begin();
  Serial.begin(9600);
  
  myWire.beginTransmission(MPU9250_ADDRESS);
  myWire.write(0x6B); // PWR_MGMT_1 register
  myWire.write(0);    // Wake up the MPU-9250
  myWire.endTransmission(true);
}

void loop() {
  int16_t accelX, accelY, accelZ;
  int16_t gyroX, gyroY, gyroZ;
  int16_t magX, magY, magZ;
  
  // Read accelerometer data
  myWire.beginTransmission(MPU9250_ADDRESS);
  myWire.write(ACCEL_XOUT_H);
  myWire.endTransmission(false);
  myWire.requestFrom(MPU9250_ADDRESS, 6, true);
  
  accelX = myWire.read() << 8 | myWire.read();
  accelY = myWire.read() << 8 | myWire.read();
  accelZ = myWire.read() << 8 | myWire.read();
  
  // Read gyroscope data
  myWire.beginTransmission(MPU9250_ADDRESS);
  myWire.write(GYRO_XOUT_H);
  myWire.endTransmission(false);
  myWire.requestFrom(MPU9250_ADDRESS, 6, true);
  
  gyroX = myWire.read() << 8 | myWire.read();
  gyroY = myWire.read() << 8 | myWire.read();
  gyroZ = myWire.read() << 8 | myWire.read();
  
  // Read magnetometer data
  myWire.beginTransmission(MPU9250_ADDRESS);
  myWire.write(MAG_XOUT_L);
  myWire.endTransmission(false);
  myWire.requestFrom(MPU9250_ADDRESS, 6, true);
  
  magX = myWire.read() | myWire.read() << 8;
  magY = myWire.read() | myWire.read() << 8;
  magZ = myWire.read() | myWire.read() << 8;
  
  Serial.print("Accelerometer Data - X: ");
  Serial.print(accelX);
  Serial.print(", Y: ");
  Serial.print(accelY);
  Serial.print(", Z: ");
  Serial.println(accelZ);
  
  Serial.print("Gyroscope Data - X: ");
  Serial.print(gyroX);
  Serial.print(", Y: ");
  Serial.print(gyroY);
  Serial.print(", Z: ");
  Serial.println(gyroZ);
  
  Serial.print("Magnetometer Data - X: ");
  Serial.print(magX);
  Serial.print(", Y: ");
  Serial.print(magY);
  Serial.print(", Z: ");
  Serial.println(magZ);
  
  delay(1000); // Delay for 1 second
}

here are the results I get on the Serial monitor:

Accelerometer Data - X: -476, Y: -112, Z: 16224

Gyroscope Data - X: -330, Y: 439, Z: -98

Magnetometer Data - X: -24577, Y: -278, Z: 6624

Accelerometer Data - X: -532, Y: -96, Z: 16168

Gyroscope Data - X: -268, Y: 455, Z: -71

Magnetometer Data - X: -24577, Y: -278, Z: 6624

Accelerometer Data - X: -552, Y: -148, Z: 16132

Gyroscope Data - X: -257, Y: 416, Z: -66

Magnetometer Data - X: -24577, Y: -278, Z: 6624

As you can see, the Gyroscope and Accelerometer have error while at rest which mean they are working. But the Magnetometer data stays the same meaning it is not working. Do I need to initialize the Magnetometer sensor? Do I need to write a different address to the Magnetometer sensor?

What am I missing here?

The Sparkfun MPU-9250 library should work, but make sure to use the correct I2C address.
https://learn.sparkfun.com/tutorials/mpu-9250-hookup-guide/all

Thank you for your comment, I will try it.

Unfortunately, I got this on the Serial monitor when the Arduino tried to set up the sensor:

{ MPU9250 I AM 0xFF I should be 0x71

Could not connect to MPU9250: 0xFF

Communication failed, abort! }

In the code the mpu9250 address is 0x68, which is right and the magnetometer is 0x0C which is also right, so somehow the code is not working as it should. I have double checked wiring and its good and the sensor I am very sure is also good as it gives me back raw gyro and accelerometer data. I have tried to stay away from the mpu9250 library as I have never had any success with it. As I said in my post I have been everywhere on the internet looking for an answer. I would like to only use the SoftwareWire library since only having one library simplifies things considerably and I can understand the inner workings of the code better. I have hit a block wall and am very much in need of answers. Thank you for trying to help me. :slight_smile:

This says that either communications are not working, your MPU9250 clone is defective, or it is a fake. The original manufacturer stopped making those sensors a number of years ago.

I strongly recommend to buy one of the modern 9DOF replacements, from a reputable supplier who supports their products.

The sensor I bought was from eBay and shipped from china so I can see how it could be a fake or clone, but then how could the mpu6050 that is integrated into the mpu9250 still apparently work. I really don't want to pay 30$ on a mpu9250 that I might still encounter programming issues on. I'm not ready to give up on the model I have at the moment. Is there any way of really finding out if its a defective clone or fake?

On the original, genuine MPU-9250, the magnetometer and the accel/gyro are two completely separate ICs, in the same molded package.

Assuming that you have some sort of clone with the same internal arrangement, it is therefore possible that the magnetometer IC is defective while the accel/gyro IC works.

Ok, that makes sense. I also ended up doing a I2C scan on the sensor and I ended up with only two address', which I think there should be three. One for the mpu6050, AK8963, and BMP280 since this is the GY-91 model which comes with a barometer. But since there is only two address', and both of them are not the address 0x0C which is the magnetometer's, then that would line up with your theory. However, I was looking at another arduino forum, here's the link: [MPU - 9250 - Can't Figure Out How to Read Magnetometer Values] and post #2 and #3 mention a way to configure a couple of registers that would then make the magnetometer work properly. Also where could I find a reliable mpu9250 sensor?

No idea, but why would you or anyone else want one? The newer 9DOF sensors all significantly outperform it, and if purchased from a reputable supplier, are guaranteed to work.

Cheap sensor modules of the "GY-" variety are throw-aways built from obsolete, clone or substandard parts, intended for hobbyists having fun putting things together on a breadboard, not for any serious use. They are often sold in multiples, so that there is a good chance that one or two will be fully functional.

Thank you so much for your help. I have one more question, was I right about the fact that there should be a separate address that appears on the I2C scanner for the AK8963?

Impossible to say. The MPU-9250 passes through the magnetometer I2C communications, and that may not functioning correctly. There might not even be a magnetometer on your board, as the chip might just be an MPU-6050 clone or imitation.

Your sensor module is not fully functional, and you should not waste any more time on it.

You MUST connect AD0/SDO to VCC or GND, using a resistor, to ensure the board I2C address (VCC 0x69 or GND 0x68). I've been fighting with this issue for the last two months. Just decided to full connect the MPU (Vin, GND, SDA, SCL) and now, AD0/SDO. All the libraries that were not workind decided to come to life. I am using a 100 ohms resistor. Connecting AGND to GND is also a good idea for more stable readings.

If you do not connect AD0/SDO, the board will answer with the other sensors, but the AK8963, missgiding you about the correcteness of the connections. The diagrams that you find on the web do not show this wiring tip.

Thank you for the Input, I will definitely try this. However, I already bought a sensor from Pololu, (a 10DOF sensor v5). This sensor works perfectly and I am very pleased with it. Thank you again, I will post my results.

The AK8963 still does not respond to an I2C scan.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.