Is our code ok? Magnetometer not recognised

Hi Everyone,

Secondary or High school student here running a project with Arduino with some of my friends. We have an a working ESP32 with BME280 (so temp. pressure, humidity all fine in the serial monitor). The thing is we have a mpu9250 that is not giving readings (just N/As) and we are at a bit of a loss.

Can anyone wiser than us see anything wrong with our code. Our teacher thinks it may be a faulty sensor but we don't have a spare so hoping that's not the problem.
We are using libraries as follows

SD by Arduino, Adafruit BME280, Adafruit BusIO, Adafruit GFX, Adafruit GPS, Adafruit ssf1306, Adafruit Unified Sensor, Bolder Flight Systems Eigen, Bolder Flight Systems MPU9250, Bolder Flight Systems Unit Conversions.

Our code is below.

Thanks for reading this and thanks for any advice!

CODE-

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_GPS.h>
#include <mpu9250.h>
#include <HardwareSerial.h>
#include "driver/ledc.h"

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme; // I2C
float BMEPressure, BMETemp, BMEAltitude, BMEHumidity;

// MPU9250 and Magnetometer
#define MPU_ADDR 0x68
#define ACCEL_XOUT_H 0x3B
#define GYRO_XOUT_H  0x43
#define MAGNETOMETER_ADDR 0x0C
#define MAGNETOMETER_XOUT 0x03

float ax, ay, az, gx, gy, gz;
float ax_ms2, ay_ms2, az_ms2, gx_dps, gy_dps, gz_dps;
float magX, magY, magZ;

float accelBiasX = 0, accelBiasY = 0, accelBiasZ = 0;
float gyroBiasX = 0, gyroBiasY = 0, gyroBiasZ = 0;

#define GPSSerial Serial2
Adafruit_GPS GPS(&GPSSerial);
float deg_lat, deg_lon, Altitude, Speed;
int Satellites;

const int TONE_OUTPUT_PIN = 32;
const int TONE_PWM_CHANNEL = 0;

unsigned long timer;

void calibrateIMU(int samples = 1000);
void scanI2C();
void Read_BME();
void Read_IMU();
void Start_GPS();
void Print_results();
void tone_gen();
void initializeMPU9250();

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

  bool status = bme.begin(0x76);  
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  GPS.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  delay(1000);

  Wire.begin();
  initializeMPU9250();
  calibrateIMU();
  scanI2C();
  tone_gen();

  timer = millis();
}

void loop() {
  Read_BME();
  Read_IMU();
  Start_GPS();

  if (millis() - timer > 1000) {
    timer = millis();
    Print_results(); // Print readings with labels
  }

  delay(500);
}

void Read_BME() {
  BMETemp = bme.readTemperature() - 2.0; // Apply temperature offset
  BMEPressure = bme.readPressure() / 100.0;
  BMEAltitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
  BMEHumidity = bme.readHumidity() * 1.8; // Adjust humidity correction factor
}

void Read_IMU() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(ACCEL_XOUT_H);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 6);
  if (Wire.available() == 6) {
    ax = (Wire.read() << 8) | Wire.read();
    ay = (Wire.read() << 8) | Wire.read();
    az = (Wire.read() << 8) | Wire.read();
  }

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(GYRO_XOUT_H);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 6);
  if (Wire.available() == 6) {
    gx = (Wire.read() << 8) | Wire.read();
    gy = (Wire.read() << 8) | Wire.read();
    gz = (Wire.read() << 8) | Wire.read();
  }

  // Sanity check for gyro values to avoid erroneous high readings
  if (abs(gx) > 500 || abs(gy) > 500 || abs(gz) > 500) {
    gx = 0;
    gy = 0;
    gz = 0;
  }

  Wire.beginTransmission(MAGNETOMETER_ADDR);
  Wire.write(MAGNETOMETER_XOUT);
  Wire.endTransmission(false);
  Wire.requestFrom(MAGNETOMETER_ADDR, 6);
  if (Wire.available() == 6) {
    magX = ((Wire.read() << 8) | Wire.read()) * 0.15; // Apply scaling factor
    magY = ((Wire.read() << 8) | Wire.read()) * 0.15; // Adjust based on sensitivity
    magZ = ((Wire.read() << 8) | Wire.read()) * 0.15;
  }

  // Handle cases where magnetometer reads all zeros
  if (magX == 0 && magY == 0 && magZ == 0) {
    magX = magY = magZ = NAN; // Set to NaN if not reading correctly
  }

  ax_ms2 = (ax - accelBiasX) / 16384.0 * 9.81;
  ay_ms2 = (ay - accelBiasY) / 16384.0 * 9.81;
  az_ms2 = (az - accelBiasZ) / 16384.0 * 9.81;

  gx_dps = (gx - gyroBiasX) / 131.0;
  gy_dps = (gy - gyroBiasY) / 131.0;
  gz_dps = (gz - gyroBiasZ) / 131.0;
}

void initializeMPU9250() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6B);
  Wire.write(0x00);
  Wire.endTransmission();
  delay(100);

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x1C);
  Wire.write(0x00);
  Wire.endTransmission();

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x1B);
  Wire.write(0x00);
  Wire.endTransmission();

  Wire.beginTransmission(MAGNETOMETER_ADDR);
  Wire.write(0x0A); // Magnetometer control register
  Wire.write(0x16); // Continuous measurement mode 2
  Wire.endTransmission();
  delay(100);
}

void Print_results() {
  // Print labeled readings
  Serial.print("Pressure (hPa): "); Serial.print(BMEPressure); Serial.print(", ");
  Serial.print("Temperature (°C): "); Serial.print(BMETemp); Serial.print(", ");
  Serial.print("Altitude (m): "); Serial.print(BMEAltitude); Serial.print(", ");
  Serial.print("Humidity (%): "); Serial.print(BMEHumidity); Serial.print(", ");

  Serial.print("Accel X (m/s²): "); Serial.print(ax_ms2); Serial.print(", ");
  Serial.print("Accel Y (m/s²): "); Serial.print(ay_ms2); Serial.print(", ");
  Serial.print("Accel Z (m/s²): "); Serial.print(az_ms2); Serial.print(", ");

  Serial.print("Gyro X (°/s): "); Serial.print(gx_dps); Serial.print(", ");
  Serial.print("Gyro Y (°/s): "); Serial.print(gy_dps); Serial.print(", ");
  Serial.print("Gyro Z (°/s): "); Serial.print(gz_dps); Serial.print(", ");

  Serial.print("Magnetometer X (µT): ");
  if (isnan(magX)) Serial.print("N/A");
  else Serial.print(magX);
  Serial.print(", Magnetometer Y (µT): ");
  if (isnan(magY)) Serial.print("N/A");
  else Serial.print(magY);
  Serial.print(", Magnetometer Z (µT): ");
  if (isnan(magZ)) Serial.print("N/A");
  else Serial.print(magZ);
  Serial.print(", ");

  Serial.print("Latitude: "); Serial.print(deg_lat, 6); Serial.print(", ");
  Serial.print("Longitude: "); Serial.print(deg_lon, 6); Serial.print(", ");
  Serial.print("Altitude (GPS): "); Serial.print(Altitude); Serial.print(", ");
  Serial.print("Speed (m/s): "); Serial.print(Speed); Serial.print(", ");
  Serial.print("Satellites: "); Serial.println(Satellites);
}

void tone_gen() {
  ledcAttachPin(TONE_OUTPUT_PIN, TONE_PWM_CHANNEL);
  for (int x = 0; x < 5; x++) {
    ledcWriteTone(TONE_PWM_CHANNEL, 1200);
    delay(100);
    ledcWriteTone(TONE_PWM_CHANNEL, 1800);
    delay(100);
  }
  ledcDetachPin(TONE_OUTPUT_PIN);
}

void scanI2C() {
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    byte error = Wire.endTransmission();
    if (error == 0) {
      Serial.print("I2C device found at 0x");
      if (addr < 16) Serial.print("0");
      Serial.println(addr, HEX);
    }
  }
}

void calibrateIMU(int samples) {
  long sumAx = 0, sumAy = 0, sumAz = 0;
  long sumGx = 0, sumGy = 0, sumGz = 0;

  for (int i = 0; i < samples; i++) {
    Wire.beginTransmission(MPU_ADDR);
    Wire.write(ACCEL_XOUT_H);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU_ADDR, 6);
    int16_t rawAx = (Wire.read() << 8) | Wire.read();
    int16_t rawAy = (Wire.read() << 8) | Wire.read();
    int16_t rawAz = (Wire.read() << 8) | Wire.read();

    Wire.beginTransmission(MPU_ADDR);
    Wire.write(GYRO_XOUT_H);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU_ADDR, 6);
    int16_t rawGx = (Wire.read() << 8) | Wire.read();
    int16_t rawGy = (Wire.read() << 8) | Wire.read();
    int16_t rawGz = (Wire.read() << 8) | Wire.read();

    sumAx += rawAx;
    sumAy += rawAy;
    sumAz += rawAz;
    sumGx += rawGx;
    sumGy += rawGy;
    sumGz += rawGz;

    delay(3);
  }

  accelBiasX = sumAx / (float)samples;
  accelBiasY = sumAy / (float)samples;
  accelBiasZ = (sumAz / (float)samples) - 16384.0;

  gyroBiasX = sumGx / (float)samples;
  gyroBiasY = sumGy / (float)samples;
  gyroBiasZ = sumGz / (float)samples;

  Serial.println("IMU calibration complete.");
  Serial.print("Accel Bias Z: "); Serial.println(accelBiasZ);
}

void Start_GPS() {
  while (GPS.available()) {
    char c = GPS.read();
    if (GPS.newNMEAreceived()) {
      if (GPS.parse(GPS.lastNMEA())) {
        deg_lat = GPS.latitudeDegrees;
        deg_lon = GPS.longitudeDegrees;
        Altitude = GPS.altitude;
        Speed = GPS.speed;
        Satellites = GPS.satellites;
      }
    }
  }
}

Welcome to the forum

Thank you for using code tags in your first post on the forum

As your topic does not relate directly to the installation or operation of the IDE it has been moved to the Programming category of the forum

Did you actually do any testing of the sensor with a program that only uses the sensor? They are available, you know.

1 Like

OK thanks for that.
We tested the sensor with this code (using MPU9250_asukiaaa library) and are getting readings and detection of a magnet near the sensor. Yeahhhh!

We then merged the 2 pieces of code and everything seems good.
Now we will do some calibrations.

This can be marked as solved and thank you again.

#include <Wire.h>
#include <MPU9250_asukiaaa.h>

MPU9250_asukiaaa mySensor;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  mySensor.setWire(&Wire);
  mySensor.beginAccel();
  mySensor.beginGyro();
  mySensor.beginMag();

  Serial.println("MPU9250 test initialized");
}

void loop() {
  mySensor.accelUpdate();
  mySensor.gyroUpdate();
  mySensor.magUpdate();

  Serial.print("Accel: ");
  Serial.print(mySensor.accelX()); Serial.print(", ");
  Serial.print(mySensor.accelY()); Serial.print(", ");
  Serial.println(mySensor.accelZ());

  Serial.print("Gyro: ");
  Serial.print(mySensor.gyroX()); Serial.print(", ");
  Serial.print(mySensor.gyroY()); Serial.print(", ");
  Serial.println(mySensor.gyroZ());

  Serial.print("Mag: ");
  Serial.print(mySensor.magX()); Serial.print(", ");
  Serial.print(mySensor.magY()); Serial.print(", ");
  Serial.println(mySensor.magZ());

  delay(1000);
}

Did you singly test ALL the sensors (GPS last) If true, then take your sketch and comment out all but one sensor and test one at a time ...... etc etc, standard divide and conquer debug protocol.

1 Like