Проблема со чтением данных с HMC5883L в GY-86

Я пытаюсь считать данные с GY-86 с помощью Arduino UNO. При чтении MPU6050 и MS5611 работает достаточно хорошо. Но что-то не могу ничего прочитать с HMC5883L. Вот код, который я использовал:

#include <Wire.h>
#include <HMC5883L.h>

HMC5883L compass;

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

  // Инициализировать HMC5883L
  Serial.println("Initialize HMC5883L");
  while (!compass.begin())
  {
    Serial.println("Could not find a valid HMC5883L sensor, check wiring!");
    delay(500);
  }

  // Установить диапазон измерения
  // +/- 0,88 млрд лет: HMC5883L_RANGE_0_88GA
  // +/- 1,30 млрд лет: HMC5883L_RANGE_1_3GA (по умолчанию)
  // +/- 1,90 млрд лет: HMC5883L_RANGE_1_9GA
  // +/- 2,50 млрд лет: HMC5883L_RANGE_2_5GA
  // +/- 4,00 млрд лет: HMC5883L_RANGE_4GA
  // +/- 4,70 млрд лет: HMC5883L_RANGE_4_7GA
  // +/- 5,60 млрд лет: HMC5883L_RANGE_5_6GA
  // +/- 8,10 млрд лет: HMC5883L_RANGE_8_1GA
  compass.setRange(HMC5883L_RANGE_1_3GA);

  // Установить режим измерения
  // Режим ожидания: HMC5883L_IDLE
  // Одно измерение: HMC5883L_SINGLE
  // Непрерывное измерение: HMC5883L_CONTINOUS (по умолчанию)
  compass.setMeasurementMode(HMC5883L_CONTINOUS);

  // Установить скорость передачи данных
  // 0,75 Гц: HMC5883L_DATARATE_0_75HZ
  // 1,50 Гц: HMC5883L_DATARATE_1_5HZ
  // 3,00 Гц: HMC5883L_DATARATE_3HZ
  // 7,50 Гц: HMC5883L_DATARATE_7_50HZ
  // 15,00 Гц: HMC5883L_DATARATE_15HZ (по умолчанию)
  // 30,00 Гц: HMC5883L_DATARATE_30HZ
  // 75,00 Гц: HMC5883L_DATARATE_75HZ
  compass.setDataRate(HMC5883L_DATARATE_15HZ);

  // Установить количество усредненных выборок
  // 1 образец: HMC5883L_SAMPLES_1 (по умолчанию)
  // 2 образца: HMC5883L_SAMPLES_2
  // 4 образца: HMC5883L_SAMPLES_4
  // 8 образцов: HMC5883L_SAMPLES_8
  compass.setSamples(HMC5883L_SAMPLES_1);

  // Проверить настройки
  checkSettings();
}

void checkSettings()
{
  Serial.print("Selected range: ");

  switch (compass.getRange())
  {
    case HMC5883L_RANGE_0_88GA: Serial.println("0.88 Ga"); break;
    case HMC5883L_RANGE_1_3GA:  Serial.println("1.3 Ga"); break;
    case HMC5883L_RANGE_1_9GA:  Serial.println("1.9 Ga"); break;
    case HMC5883L_RANGE_2_5GA:  Serial.println("2.5 Ga"); break;
    case HMC5883L_RANGE_4GA:    Serial.println("4 Ga"); break;
    case HMC5883L_RANGE_4_7GA:  Serial.println("4.7 Ga"); break;
    case HMC5883L_RANGE_5_6GA:  Serial.println("5.6 Ga"); break;
    case HMC5883L_RANGE_8_1GA:  Serial.println("8.1 Ga"); break;
    default: Serial.println("Bad range!");
  }

  Serial.print("Selected Measurement Mode: ");
  switch (compass.getMeasurementMode())
  {  
    case HMC5883L_IDLE: Serial.println("Idle mode"); break;
    case HMC5883L_SINGLE:  Serial.println("Single-Measurement"); break;
    case HMC5883L_CONTINOUS:  Serial.println("Continuous-Measurement"); break;
    default: Serial.println("Bad mode!");
  }

  Serial.print("Selected Data Rate: ");
  switch (compass.getDataRate())
  {  
    case HMC5883L_DATARATE_0_75_HZ: Serial.println("0.75 Hz"); break;
    case HMC5883L_DATARATE_1_5HZ:  Serial.println("1.5 Hz"); break;
    case HMC5883L_DATARATE_3HZ:  Serial.println("3 Hz"); break;
    case HMC5883L_DATARATE_7_5HZ: Serial.println("7.5 Hz"); break;
    case HMC5883L_DATARATE_15HZ:  Serial.println("15 Hz"); break;
    case HMC5883L_DATARATE_30HZ: Serial.println("30 Hz"); break;
    case HMC5883L_DATARATE_75HZ:  Serial.println("75 Hz"); break;
    default: Serial.println("Bad data rate!");
  }

  Serial.print("Selected number of samples: ");
  switch (compass.getSamples())
  {  
    case HMC5883L_SAMPLES_1: Serial.println("1"); break;
    case HMC5883L_SAMPLES_2: Serial.println("2"); break;
    case HMC5883L_SAMPLES_4: Serial.println("4"); break;
    case HMC5883L_SAMPLES_8: Serial.println("8"); break;
    default: Serial.println("Bad number of samples!");
  }

}

void loop()
{
  Vector raw = compass.readRaw();
  Vector norm = compass.readNormalize();

  Serial.print(" Xraw = ");
  Serial.print(raw.XAxis);
  Serial.print(" Yraw = ");
  Serial.print(raw.YAxis);
  Serial.print(" Zraw = ");
  Serial.print(raw.ZAxis);
  Serial.print(" Xnorm = ");
  Serial.print(norm.XAxis);
  Serial.print(" Ynorm = ");
  Serial.print(norm.YAxis);
  Serial.print(" ZNorm = ");
  Serial.print(norm.ZAxis);
  Serial.println();  

  delay(100);
}

Я загружаю его с https://github.com/jarzebski/Arduino-HMC5883L.

Программа всегда зависала на

  while (!compass.begin())
  {
    Serial.println("Could not find a valid HMC5883L sensor, check wiring!");
    delay(500);
  }

Вот функция начала в HMC5883L.cpp

bool HMC5883L::begin()
{
    Wire.begin();

    if ((fastRegister8(HMC5883L_REG_IDENT_A) != 0x48)
    || (fastRegister8(HMC5883L_REG_IDENT_B) != 0x34)
    || (fastRegister8(HMC5883L_REG_IDENT_C) != 0x33))
    {
    return false;
    }

    setRange(HMC5883L_RANGE_1_3GA);
    setMeasurementMode(HMC5883L_CONTINOUS);
    setDataRate(HMC5883L_DATARATE_15HZ);
    setSamples(HMC5883L_SAMPLES_1);

    mgPerDigit = 0.92f;

    return true;
}

Похоже, что функция begin всегда возвращает False. Что мне делать, чтобы решить эту проблему?

Вот как я подключаю GY-86 к UNO:

VCC-IN -> 5 В

Земля -> Земля

ПДД -> 4А

SLC -> 5А

, 👍3


2 ответа


Лучший ответ:

2

Запускали ли вы сканер i2c? Обнаружен ли он с адресом i2c 0x1E?

Глядя на схему, магнитометр HMC5883L подключен к XDA и XCL. Это не обычная шина I2C, а вторая шина I2C от MPU- 6050.

Причина этого в том, что прошивка dmp в MPU-6050 может считывать показания магнитометра и выполнять с ним вычисления в MPU-6050.

Если вы хотите обмениваться данными с магнитометром через обычную шину I2C, вам необходимо включить режим обхода.

Библиотеки Джеффа Роуберга и Яржебски большие. Я предлагаю включить обходной режим и запустить сканер i2c.

Есть ли у вас логический анализатор? Возможно, вы можете использовать простой мультиметр. Держите SDA на низком уровне (замкните его на GND) и попытайтесь измерить, низкий ли уровень на XDA в режиме байпаса.

Возможно, что-то сломалось.

,

Здесь может быть проблема. Сканер i2c нашел только 0x68 и 0x77. Означает ли это, что мой GY-86 сломан?, @Yichen

Кстати, я также пытаюсь использовать код обхода I2C на этом сайте. [ссылка](https://stackoverflow.com/questions/37966638/mpu6050-read-accel-gyro-and-magnetometer) mpu.setI2CMasterModeEnabled (ложь); mpu.setI2CBypassEnabled (истина); mpu.setSleepEnabled(false); Но тем не менее, он снова застрял в begin()., @Yichen

Вам все равно придется вызывать mpu.begin перед включением обхода. Я добавил в свой ответ некоторую справочную информацию и информацию о том, как протестировать вторую шину I2C., @Jot


3

Спасибо Джоту, ваш ответ действительно помогает мне. Теперь я использую этот код, и он работает очень хорошо.

#include <Wire.h>
#include <HMC5883L.h>
#include <MPU6050.h>

HMC5883L compass;
MPU6050 mpu;

int previousDegree;

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

  // Инициализировать MPU6050
  mpu.initialize();

  // Включить режим обхода
  mpu.setI2CMasterModeEnabled(false);
  mpu.setI2CBypassEnabled(true);
  mpu.setSleepEnabled(false);

  // Инициализировать HMC5883L
  while (!compass.begin())
  {
    delay(500);
  }

  // Установить диапазон измерения
  compass.setRange(HMC5883L_RANGE_1_3GA);

  // Установить режим измерения
  compass.setMeasurementMode(HMC5883L_CONTINOUS);

  // Установить скорость передачи данных
  compass.setDataRate(HMC5883L_DATARATE_30HZ);

  // Установить количество усредненных выборок
  compass.setSamples(HMC5883L_SAMPLES_8);

  // Установить смещение калибровки. См. HMC5883L_caulibration.ino.
  compass.setOffset(0, 0); 
}

void loop()
{
  long x = micros();
  Vector norm = compass.readNormalize();

  // Вычислить заголовок
  float heading = atan2(norm.YAxis, norm.XAxis);

  // Установите угол склонения на ваше местоположение и зафиксируйте курс
  // Вы можете найти свое склонение на: http:// Magnetic-declination.com/
  // (+) положительный или (-) отрицательный
  // Для Бытома / Польши угол склонения 4'26E (положительный)
  // Формула: (град + (мин/60,0))/(180/M_PI);
  float declinationAngle = (4.0 + (26.0 / 60.0)) / (180 / M_PI);
  heading += declinationAngle;

  // Правильный заголовок < 0deg и заголовок > 360 градусов
  if (heading < 0)
  {
    heading += 2 * PI;
  }

  if (heading > 2 * PI)
  {
    heading -= 2 * PI;
  }

  // Преобразование в градусы
  float headingDegrees = heading * 180/M_PI; 

  // Исправление проблемы HMC5883L с углами
  float fixedHeadingDegrees;

  if (headingDegrees >= 1 && headingDegrees < 240)
  {
    fixedHeadingDegrees = map(headingDegrees, 0, 239, 0, 179);
  } else
  if (headingDegrees >= 240)
  {
    fixedHeadingDegrees = map(headingDegrees, 240, 360, 180, 360);
  }

  // Плавное вращение углов на +/- 3 градуса
  int smoothHeadingDegrees = round(fixedHeadingDegrees);

  if (smoothHeadingDegrees < (previousDegree + 3) && smoothHeadingDegrees > (previousDegree - 3))
  {
    smoothHeadingDegrees = previousDegree;
  }

  previousDegree = smoothHeadingDegrees;

  // Выход
  Serial.print(norm.XAxis);
  Serial.print(":");
  Serial.print(norm.YAxis);
  Serial.print(":");
  Serial.print(norm.ZAxis);
  Serial.print(":");
  Serial.print(headingDegrees);
  Serial.print(":");
  Serial.print(fixedHeadingDegrees);
  Serial.print(":");
  Serial.print(smoothHeadingDegrees);  
  Serial.println();

  // Один цикл: ~5 мс @ 115200 серийный номер.
  // Нам нужна задержка ~ 28 мс для разрешения скорости передачи данных 30 Гц (~ 33 мс)
  delay(30);
}

Кстати, код на https://github.com/jarzebski/Arduino-HMC5883L должен добавить

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

в начале установки.

,