#1 2023-08-05 14:11:29

Timoha_k
Учасник
Зареєстрований: 2023-04-08
Повідомлень: 3

Допомога по модулю GY-86, а саме HMC5883L (магнітометр)

Всім привіт! Придбав от такий модуль датчиків (Модуль GY-86 комбінованих 10-DOF датчиків IMU - MPU6050 / HMC5883L / MS5611)
https://arduino.ua/prod1026-modyl-gy-86 … 83l-ms5611
Код взяв тут:
https://forum.arduino.cc/t/extracting-a … -86/185955
Біблітеки з того ж ресурсу:
Ця https://github.com/jrowberg/i2cdevlib/t … no/MPU6050
І ця: https://github.com/jrowberg/i2cdevlib/t … o/HMC5883L

Під'єдную до Arduino Due

Сама проблема:
Код працює, в серійний порт виводить данні, але heading (напрямок по компасу) постіно коливається в діапазоні 190-230, хоча повинен змінюватись від 0 до 360. При тому що повертаю датчик на 360 градусів навколо вертикальної осі

Дякую за допомогу!

Код:

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include "HMC5883L.h"


MPU6050 accelgyro;
HMC5883L mag;

int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t mx, my, mz;

#define LED_PIN 13
bool blinkState = false;

void setup() {
   
    Wire.begin();
    accelgyro.setI2CMasterModeEnabled(false);
    accelgyro.setI2CBypassEnabled(true) ;
    accelgyro.setSleepEnabled(false);

    Serial.begin(38400);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();
    mag.initialize();
    Serial.println(mag.testConnection() ? "HMC5883L connection successful" : "HMC5883L connection failed");

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    // configure Arduino LED for
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    mag.getHeading(&mx, &my, &mz);

    // display tab-separated accel/gyro x/y/z values
    Serial.print("a/g:t");
    Serial.print(ax); Serial.print("t");
    Serial.print(ay); Serial.print("t");
    Serial.print(az); Serial.print("t");
    Serial.print(gx); Serial.print("t");
    Serial.print(gy); Serial.print("t");
    Serial.print(gz); Serial.print("t");
    
    Serial.print("mag:t");
    Serial.print(mx); Serial.print("t");
    Serial.print(my); Serial.print("t");
    Serial.print(mz); Serial.print("t");
    delay(500);
    
// To calculate heading in degrees. 0 degree indicates North
    //float heading = atan2(my, mx);
    float heading = atan2(mx, my);
    if(heading < 0)
      heading += 2 * M_PI;
    Serial.print("heading:t");
    Serial.println(heading * 180/M_PI);

    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

Скрін:
Screenshot-2023-08-05-135142.png

Неактивний

#2 2023-08-05 18:02:40

KAS
Учасник
Зареєстрований: 2020-10-05
Повідомлень: 27

Re: Допомога по модулю GY-86, а саме HMC5883L (магнітометр)

Нету датчика на руках, но вроде как сырые данные (mx, my) не должны быть отрицательными, попробуй откалибровать датчик:

#include "Wire.h"
#include "HMC5883L.h"

HMC5883L mag;

void setup() {
  Wire.begin();
  Serial.begin(9600);
  mag.initialize();
  Serial.println("Move the magnetometer in all directions to calibrate...");
  delay(2000);
}

void loop() {
  static int16_t minX = 0, minY = 0, minZ = 0;
  static int16_t maxX = 0, maxY = 0, maxZ = 0;

  int16_t x, y, z;
  mag.getHeading(&x, &y, &z);

  if (x < minX) minX = x;
  if (x > maxX) maxX = x;

  if (y < minY) minY = y;
  if (y > maxY) maxY = y;

  if (z < minZ) minZ = z;
  if (z > maxZ) maxZ = z;

  // Print the raw values and the calibration range
  Serial.print("Raw: X="); Serial.print(x);
  Serial.print(" Y="); Serial.print(y);
  Serial.print(" Z="); Serial.print(z);
  Serial.print(" Calibrated Range: X["); Serial.print(minX); Serial.print(", "); Serial.print(maxX); Serial.print("]");
  Serial.print(" Y["); Serial.print(minY); Serial.print(", "); Serial.print(maxY); Serial.print("]");
  Serial.print(" Z["); Serial.print(minZ); Serial.print(", "); Serial.print(maxZ); Serial.println("]");

  delay(200);
}

}

после чего запиши максимальные и минимальные значения для каждой оси в новый код:

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include "HMC5883L.h"

MPU6050 accelgyro;
HMC5883L mag;

int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t mx, my, mz;

#define LED_PIN 13
bool blinkState = false;

// Задайте значения из калибровки для коррекции
int16_t minX = -100; // Замените значения на те, что получены в калибровке
int16_t maxX = 100;
int16_t minY = -100;
int16_t maxY = 100;
int16_t minZ = -100;
int16_t maxZ = 100;

void setup() {
  Wire.begin();
  accelgyro.setI2CMasterModeEnabled(false);
  accelgyro.setI2CBypassEnabled(true);
  accelgyro.setSleepEnabled(false);

  Serial.begin(38400);

  // initialize device
  Serial.println("Initializing I2C devices...");
  accelgyro.initialize();
  mag.initialize();
  Serial.println(mag.testConnection() ? "HMC5883L connection successful" : "HMC5883L connection failed");

  // verify connection
  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

  // configure Arduino LED for
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  // Чтение данных с акселерометра и гироскопа
  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  // Чтение данных с магнетометра
  mag.getHeading(&mx, &my, &mz);

  // Коррекция сырых данных магнетометра с помощью значений из калибровки
  mx = constrain(mx, minX, maxX);
  my = constrain(my, minY, maxY);
  mz = constrain(mz, minZ, maxZ);

  // Вывод данных на монитор последовательного порта
  Serial.print("a/g: ");
  Serial.print(ax); Serial.print("t");
  Serial.print(ay); Serial.print("t");
  Serial.print(az); Serial.print("t");
  Serial.print(gx); Serial.print("t");
  Serial.print(gy); Serial.print("t");
  Serial.print(gz); Serial.print("t");

  Serial.print("mag: ");
  Serial.print(mx); Serial.print("t");
  Serial.print(my); Serial.print("t");
  Serial.print(mz); Serial.print("t");

  // Вычисление и вывод направления (heading) в градусах
  float heading = atan2(my, mx);
  if (heading < 0)
    heading += 2 * PI;
  Serial.print("heading: ");
  Serial.println(heading * 180 / PI);

  // Мигание светодиода для индикации активности
  blinkState = !blinkState;
  digitalWrite(LED_PIN, blinkState);

  delay(500);
}

Неактивний

#3 2023-08-08 23:58:50

Timoha_k
Учасник
Зареєстрований: 2023-04-08
Повідомлень: 3

Re: Допомога по модулю GY-86, а саме HMC5883L (магнітометр)

KAS

К сожаление метод не сработал, но ты меня натолкнул на мысль, что используются "сырые" значения. Взял твой калибровщик и с помощью него перевел "сырые" в калиброваные. Компас начал показывать полный круг в 360 градусов, всё же на точный север не показывает (хотя угол склонения тоже добавил). В моем проекте это не важно, мне нужно только направление. Ну и добавлю что датчик очень чувствителен к магнитным полям, телефон лежащий в 10см от датчика дает погрешность в 10-15 градусов.

Формула перевода значений:
offset = (minimum + maxmum) / 2  //minimum, maxmum - из калибровщика
value = valueRaw - offset                //valueRaw - сырое значение с датчика, value - значение для расчёта heading

Может кому понадобится код:

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include "HMC5883L.h"


MPU6050 accelgyro;
HMC5883L mag;

int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t mx, my, mz;

float offsetMx, offsetMy, offsetMz;
float scaledMx, scaledMy, scaledMz;

#define LED_PIN 13
#define DA 0,146608 //Declination angle in RAD

bool blinkState = false;

void setup() {
   
    Wire.begin();
    accelgyro.setI2CMasterModeEnabled(false);
    accelgyro.setI2CBypassEnabled(true) ;
    accelgyro.setSleepEnabled(false);

    Serial.begin(38400);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();
    mag.initialize();
    Serial.println(mag.testConnection() ? "HMC5883L connection successful" : "HMC5883L connection failed");

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    // configure Arduino LED for
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    mag.getHeading(&mx, &my, &mz);

    // display tab-separated accel/gyro x/y/z values
    Serial.print("a/g:t");
    Serial.print(ax); Serial.print("t");
    Serial.print(ay); Serial.print("t");
    Serial.print(az); Serial.print("t");
    Serial.print(gx); Serial.print("t");
    Serial.print(gy); Serial.print("t");
    Serial.print(gz); Serial.print("t");
    
    Serial.print("mag:t");
    Serial.print(mx); Serial.print("t");
    Serial.print(my); Serial.print("t");
    Serial.print(mz); Serial.print("t");
    delay(100);

    offsetMx = (-762 + 276)/2; // Min and Max values taken from calibrator
    offsetMy = (-892 + 155)/2; // Used formula to get scaled values: offset = (minimum + maxmum) / 2; value = valueRaw - offset
    offsetMz = (-701 + 256)/2; //

    scaledMx = mx - offsetMx;
    scaledMy = my - offsetMy;
    scaledMz = mz - offsetMz;

    
// To calculate heading in degrees. 0 degree indicates North
    
    float heading = atan2(scaledMy, scaledMx);
    heading += DA;         //including declination angle
    
    if(heading < 0)
      heading += 2 * M_PI;
    Serial.print("heading:t");
    Serial.println(heading * 180/M_PI);

    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

Остання редакція Timoha_k (2023-08-09 00:04:26)

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму