M5StickC用に磁気センサーHMC5883のHATを自作してみた

M5StickC用に磁気センサーHMC5883のHATを自作してみた。
PROTO-HATを使ってみた。

磁気センサーのHMC5883は電子コンパス用の高精度なもので、Amazonで売っているブレークアウト基板モジュールを買った。

GY-271 QMC5883L 3軸磁気センサー 磁場センサー 電子 デジタル コンパス モジュール 地磁気センサー (Amazon)

なぜHMC5883かというと、他の磁気センサーよりも高精度に地磁気を測定したかったからだ。
M5StickCの本体に内蔵されている強力な磁石が邪魔なので、前もってM5StickCを分解して磁石を取り除いた

HMC5883のブレークアウト基板をPROTO-HATの基板に実装しようとすると、PROTOの中の基板が小さいので ちょっと取り付け方法で悩む。

ちょっと考えて、このようなL字型の部品を使って実装してみることにした。

基板の反対側の面で配線を繋ぐ。

電源の3.3VとGND、I2CのSDAとSCLをIOピン番号0と26に接続した。

ケースに入れて、完成だ。

M5StickCに取り付けると、こんな感じだ。


ソフトは、Adafruit_HMC5883_Uというライブラリを使用した。ただし、I2CのピンをHAT用の割り当て直しをしないといけないので、ライブラリの本体を書き換える必要がある。

GitHubのこのライブラリのページからソースコードを取得して、Arduinoのプロジェクトフォルダーにライブラリのソースを入れて、それを書き換えるというやり方で書き換えた。

書き換えた箇所は、I2Cの初期化処理の
Wire.begin();
という部分を、
Wire.begin(0,26);
と変更した。I2Cに使用するI/OピンをHATコネクタのピンに変更するという変更だ。

とりあえず、以下のようなソースコードで動作させてみた。
前にM5StickCとENV-HATの磁気センサーを組み合わせて動かすソフトを作っていたので、それを元に改造してソフトを書いた。
磁気センサーの出力値の物理単位(μT)とかは合ってないかもしれないので、あとで調べて直したほうがよさそうだ。

#include <M5StickC.h>
#include <Wire.h>

#include <Adafruit_Sensor.h>
#include "Adafruit_HMC5883_U.h"
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);

float gyroX,gyroY,gyroZ;
float accX,accY,accZ;
float magX,magY,magZ;
float t,t0;
float magXofs,magYofs,magZofs;
float magXmax,magYmax,magZmax;
float magXmin,magYmin,magZmin;
int calibration_mode;
int error=0;

void setup() {
  // put your setup code here, to run once:
  M5.begin();
  Serial.begin(115200);
  Wire.begin(0,26);
  M5.IMU.Init();

  /* Initialise the sensor */
  if(!mag.begin())
  {
    /* There was a problem detecting the HMC5883 ... check your connections */
    Serial.println("Ooops, no HMC5883 detected ... Check your wiring!");
    while(1);
  }
  
  pinMode(M5_BUTTON_HOME, INPUT);
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(20, 0);
  M5.Lcd.println("9DoF TEST (w/ENV-HAT)");
  M5.Lcd.setCursor(0, 10);
  M5.Lcd.println("  X       Y       Z");

  t=0; t0=0;
  calibration_mode=0;
  magXofs=0;
  magYofs=0;
  magZofs=0;
}

void loop() {
  // put your main code here, to run repeatedly:
  M5.IMU.getGyroData(&amp;gyroX,&amp;gyroY,&amp;gyroZ);
  M5.IMU.getAccelData(&amp;accX,&amp;accY,&amp;accZ);
  
  /* Get a new sensor event */ 
  sensors_event_t event; 
  mag.getEvent(&amp;event);

  magX = event.magnetic.x;
  magY = event.magnetic.y;
  magZ = event.magnetic.z;

  if (calibration_mode==1) {
    if (magX>magXmax) { magXmax=magX; }
    if (magX<magXmin) { magXmin=magX; }
    if (magY>magYmax) { magYmax=magY; }
    if (magY<magYmin) { magYmin=magY; }
    if (magZ>magZmax) { magZmax=magZ; }
    if (magZ<magZmin) { magZmin=magZ; }
  }
  if (digitalRead(M5_BUTTON_HOME) == LOW) {
    if (calibration_mode==0) {
      calibration_mode=1;
      magXmax=magX; magXmin=magX;
      magYmax=magY; magYmin=magY;
      magZmax=magZ; magZmin=magZ;
    } else {
      calibration_mode=0;
      magXofs=(magXmax+magXmin)/2;
      magYofs=(magYmax+magYmin)/2;
      magZofs=(magZmax+magZmin)/2;
    }
    delay(500);
  }

  magX = magX - magXofs;
  magY = magY - magYofs;
  magZ = magZ - magZofs;

  t0=t; t=millis();

  M5.Lcd.setCursor(0, 20);
  M5.Lcd.printf("%6.2f  %6.2f  %6.2f      ", gyroX, gyroY, gyroZ);
  M5.Lcd.setCursor(140, 20);
  M5.Lcd.print("o/s");
  M5.Lcd.setCursor(0, 30);
  M5.Lcd.printf(" %5.2f   %5.2f   %5.2f   ", accX, accY, accZ);
  M5.Lcd.setCursor(140, 30);
  M5.Lcd.print("G");
  M5.Lcd.setCursor(0, 40);
  M5.Lcd.printf(" %5.0f   %5.0f   %5.0f   ", magX, magY, magZ);
  M5.Lcd.setCursor(140, 40);
  M5.Lcd.print("uT");
  M5.Lcd.setCursor(0, 70);
  M5.Lcd.printf("  dt=%.0f    ", t-t0);
  M5.Lcd.setCursor(140, 70);
  if (calibration_mode==1) {
    M5.Lcd.printf("CAL");
  } else {
    M5.Lcd.printf("   ");
  }

  Serial.print(gyroX); Serial.print(",");
  Serial.print(gyroY); Serial.print(",");
  Serial.print(gyroZ); Serial.print(",");
  Serial.print(accX); Serial.print(",");
  Serial.print(accY); Serial.print(",");
  Serial.print(accZ); Serial.print(",");
  Serial.print(magX); Serial.print(",");
  Serial.print(magY); Serial.print(",");
  Serial.print(magZ); Serial.println("");
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Time limit is exhausted. Please reload CAPTCHA.

+ 78 = 86