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(&gyroX,&gyroY,&gyroZ);
M5.IMU.getAccelData(&accX,&accY,&accZ);
/* Get a new sensor event */
sensors_event_t event;
mag.getEvent(&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("");
}