【M5Stack】M5StickCで地磁気モニタリングシステムを作成:地磁気の取得

  • URLをコピーしました!
目次

M5StickC

前回、M5StickCでシリアル通信に出力、そしてボタン操作におけるdelayの重要性について勉強してみました。

今回からArduino言語を勉強した目的のプログラムを作っていきます。

その目的のプログラムとは「地磁気モニタリングシステム」です。

それも単に今現在の地磁気を測定するのではなく、移動中の地磁気の変化を一定時間ごとに保存するシステムです。

地球の磁場というのはみなさんご存知の通り、北極をS極、南極をN極とした磁石になっています。

ただその地球全体の大きな磁場だけでなく、場所によって地場が異なるなんて話を聞いて、本当だろうかと思い試してみたくなったというのが今回のきっかけです。

ということでM5StickCを使って、地磁気モニタリングシステムを作っていきましょう。

フォルダ構成

今回は前に使ったENV II HATを使います。

こちらの記事でもやりましたが、ENV II HATを使うには、ENV II HATを使うためのスケッチに、「Adafruit_Sensor.h」、「bmm150_defs.h」、「bmm150.h」、「SHT3X.h」をインクルードする必要があります。

またそのうち「”SHT3X.h”」、「”Adafruit_Sensor.h”」、「”bmm150.h”」、「”bmm150_defs.h”」はヘッダーファイルを同じフォルダに置いてやる必要がありました。

ということで前回と同様、こちらのGitHubのページからスケッチ例をダウンロードして、「Hat > ENVII_HAT > Arduino > ENVII_HAT」にある必要ファイルを、これからスケッチを入れるフォルダにコピーしておきましょう。

ファイルをコピーできたら、スケッチの作成を始めていきましょう。

スケッチ作成の流れ

とは言ってもいきなり全部を作るのはなかなかしんどいので、少しずつ確認をしつつ、作成していきます。

流れとしてはこんな感じ。

  1. 地磁気データの取得(と表示して確認)
  2. 取得したデータをSPIFFS領域に保存
  3. SPIFFS領域に保存したデータをボタンを押した際にシリアル通信に出力

ということで今回は地磁気データの取得し、表示して確認してみることにします。

ちなみに表示して確認が括弧書きになっているのは、後々電池の消費を抑えるため、画面表示はOFF(かOFFに近い状態)にするため、あくまでも確認用という意味合いが強いからです。

プログラム全体

ということで地磁気データの取得のプログラム全体です。

#include <M5StickC.h>
#include "SHT3X.h"
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "bmm150.h"
#include "bmm150_defs.h"
SHT3X sht3x; 
BMM150 bmm = BMM150();
bmm150_mag_data value_offset;
Adafruit_BMP280 bme;

float tmp = 0.0;
float hum = 0.0;
float pressure = 0.0;

int cycle = 0;

void calibrate(uint32_t timeout)
{
  int16_t value_x_min = 0;
  int16_t value_x_max = 0;
  int16_t value_y_min = 0;
  int16_t value_y_max = 0;
  int16_t value_z_min = 0;
  int16_t value_z_max = 0;
  uint32_t timeStart = 0;

  bmm.read_mag_data();  
  value_x_min = bmm.raw_mag_data.raw_datax;
  value_x_max = bmm.raw_mag_data.raw_datax;
  value_y_min = bmm.raw_mag_data.raw_datay;
  value_y_max = bmm.raw_mag_data.raw_datay;
  value_z_min = bmm.raw_mag_data.raw_dataz;
  value_z_max = bmm.raw_mag_data.raw_dataz;
  delay(100);

  timeStart = millis();
  
  while((millis() - timeStart) < timeout)
  {
    bmm.read_mag_data();
    
    /* Update x-Axis max/min value */
    if(value_x_min > bmm.raw_mag_data.raw_datax)
    {
      value_x_min = bmm.raw_mag_data.raw_datax;
      // Serial.print("Update value_x_min: ");
      // Serial.println(value_x_min);

    } 
    else if(value_x_max < bmm.raw_mag_data.raw_datax)
    {
      value_x_max = bmm.raw_mag_data.raw_datax;
      // Serial.print("update value_x_max: ");
      // Serial.println(value_x_max);
    }

    /* Update y-Axis max/min value */
    if(value_y_min > bmm.raw_mag_data.raw_datay)
    {
      value_y_min = bmm.raw_mag_data.raw_datay;
      // Serial.print("Update value_y_min: ");
      // Serial.println(value_y_min);

    } 
    else if(value_y_max < bmm.raw_mag_data.raw_datay)
    {
      value_y_max = bmm.raw_mag_data.raw_datay;
      // Serial.print("update value_y_max: ");
      // Serial.println(value_y_max);
    }

    /* Update z-Axis max/min value */
    if(value_z_min > bmm.raw_mag_data.raw_dataz)
    {
      value_z_min = bmm.raw_mag_data.raw_dataz;
      // Serial.print("Update value_z_min: ");
      // Serial.println(value_z_min);

    } 
    else if(value_z_max < bmm.raw_mag_data.raw_dataz)
    {
      value_z_max = bmm.raw_mag_data.raw_dataz;
      // Serial.print("update value_z_max: ");
      // Serial.println(value_z_max);
    }
    
    Serial.print(".");
    delay(1);

  }

  value_offset.x = value_x_min + (value_x_max - value_x_min)/2;
  value_offset.y = value_y_min + (value_y_max - value_y_min)/2;
  value_offset.z = value_z_min + (value_z_max - value_z_min)/2;
}

void setup() {
  M5.begin();
  Wire.begin(0,26);
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.println("ENV TEST");
  pinMode(M5_BUTTON_HOME, INPUT);

  if(bmm.initialize() == BMM150_E_ID_NOT_CONFORM) {
    Serial.println("Chip ID can not read!");
    while(1);
  } else {
    Serial.println("Initialize done!");
  }
  if (!bme.begin(0x76)){  
      Serial.println("Could not find a valid BMP280 sensor, check wiring!");
      while (1);
  }
  calibrate(10);
  Serial.print("\n\rCalibrate done..");

  M5.Lcd.println("ENV TEST Done!\n");
  delay(5000);
  M5.Lcd.fillScreen(BLACK);
}
uint8_t setup_flag = 1;

void loop() {
  M5.Lcd.fillScreen(BLACK);
  bmm150_mag_data value;
  bmm.read_mag_data();

  value.x = bmm.raw_mag_data.raw_datax;
  value.y = bmm.raw_mag_data.raw_datay;
  value.z = bmm.raw_mag_data.raw_dataz;

  Serial.printf("%d, %d, %d, %d\n", cycle, value.x, value.y, value.z);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.printf("X; %i", value.x);
  M5.Lcd.setCursor(0, 20, 2);
  M5.Lcd.printf("Y; %i", value.y);
  M5.Lcd.setCursor(0, 40, 2);
  M5.Lcd.printf("Z; %i", value.z);

  cycle ++;
  delay(500);

  if(!setup_flag){
     setup_flag = 1;

     if(bmm.initialize() == BMM150_E_ID_NOT_CONFORM) {
    Serial.println("Chip ID can not read!");
    while(1);
  } else {
    Serial.println("Initialize done!");
  }
  if (!bme.begin(0x76)){  
      Serial.println("Could not find a valid BMP280 sensor, check wiring!");
      while (1);
  }
  calibrate(10);
  Serial.print("\n\rCalibrate done..");
 }


 if(digitalRead(M5_BUTTON_HOME) == LOW){
  setup_flag = 0;
  while(digitalRead(M5_BUTTON_HOME) == LOW);
 }
}

正直かなりの部分がスケッチ例からのコピーです。

ということで順に見ていきましょう。

インクルードと初期設定、calibrate関数

まずはヘッダーファイルのインクルードと初期設定の部分です。

#include <M5StickC.h>
#include "SHT3X.h"
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "bmm150.h"
#include "bmm150_defs.h"
SHT3X sht3x; 
BMM150 bmm = BMM150();
bmm150_mag_data value_offset;
Adafruit_BMP280 bme;

float tmp = 0.0;
float hum = 0.0;
float pressure = 0.0;

int cycle = 0;

ここは最後の「int cycle = 0;」を除いてスケッチ例そのままです。

「int cycle = 0;」は後ほどloop関数部分で繰り返しの回数を数えるために使用しています。

次にcalibrate関数ですが、この部分もスケッチ例そのままですので、解説は割愛します。

setup関数

setup関数もほとんどがスケッチ例そのままです。

void setup() {
  M5.begin();
  Wire.begin(0,26);
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.println("ENV TEST");
  pinMode(M5_BUTTON_HOME, INPUT);

  if(bmm.initialize() == BMM150_E_ID_NOT_CONFORM) {
    Serial.println("Chip ID can not read!");
    while(1);
  } else {
    Serial.println("Initialize done!");
  }
  if (!bme.begin(0x76)){  
      Serial.println("Could not find a valid BMP280 sensor, check wiring!");
      while (1);
  }
  calibrate(10);
  Serial.print("\n\rCalibrate done..");

  M5.Lcd.println("ENV TEST Done!\n");
  delay(5000);
  M5.Lcd.fillScreen(BLACK);
}
uint8_t setup_flag = 1;

違うのは最後の方のこの3行。

  M5.Lcd.println("ENV TEST Done!\n");
  delay(5000);
  M5.Lcd.fillScreen(BLACK);

この前にキャリブレーションなどの設定テストがあるのですが、それが終わったかどうか画面上に表示するコマンドがなかったので追加しました。

またその後5000ミリ秒、つまり5秒待ってから、一度画面を黒で塗りつぶして消去し、loop関数への進んでいくようにしました。

loop関数

メインはここ、loop関数です。

void loop() {
  M5.Lcd.fillScreen(BLACK);
  bmm150_mag_data value;
  bmm.read_mag_data();

  value.x = bmm.raw_mag_data.raw_datax;
  value.y = bmm.raw_mag_data.raw_datay;
  value.z = bmm.raw_mag_data.raw_dataz;

  Serial.printf("%d, %d, %d, %d\n", cycle, value.x, value.y, value.z);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.printf("X; %i", value.x);
  M5.Lcd.setCursor(0, 20, 2);
  M5.Lcd.printf("Y; %i", value.y);
  M5.Lcd.setCursor(0, 40, 2);
  M5.Lcd.printf("Z; %i", value.z);

  cycle ++;
  delay(500);

  if(!setup_flag){
     setup_flag = 1;

     if(bmm.initialize() == BMM150_E_ID_NOT_CONFORM) {
    Serial.println("Chip ID can not read!");
    while(1);
  } else {
    Serial.println("Initialize done!");
  }
  if (!bme.begin(0x76)){  
      Serial.println("Could not find a valid BMP280 sensor, check wiring!");
      while (1);
  }
  calibrate(10);
  Serial.print("\n\rCalibrate done..");
 }


 if(digitalRead(M5_BUTTON_HOME) == LOW){
  setup_flag = 0;
  while(digitalRead(M5_BUTTON_HOME) == LOW);
 }
}

まずは画面の初期化とセンサからデータの取得です。

  M5.Lcd.fillScreen(BLACK);
  bmm150_mag_data value;
  bmm.read_mag_data();

そして取得した3軸の磁気のデータを変数に格納します。

  value.x = bmm.raw_mag_data.raw_datax;
  value.y = bmm.raw_mag_data.raw_datay;
  value.z = bmm.raw_mag_data.raw_dataz;

次にデータを保存用にまとめるのと、画面に表示です。

  Serial.printf("%d, %d, %d, %d\n", cycle, value.x, value.y, value.z);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.printf("X; %i", value.x);
  M5.Lcd.setCursor(0, 20, 2);
  M5.Lcd.printf("Y; %i", value.y);
  M5.Lcd.setCursor(0, 40, 2);
  M5.Lcd.printf("Z; %i", value.z);

今回は「Serial.printf(“%d, %d, %d, %d\n”, cycle, value.x, value.y, value.z);」で3軸のデータをシリアルに出力していますが、ここは次回、SPIFFS領域への保存に変更する予定です。

後はM5StickCの画面での表示です。

次にcycleを増加させ、500ミリ秒待って一回のループを終えます。

  cycle ++;
  delay(500);

この変数cycleですが、M5StickCは時刻を扱うのに、まずWifiでインターネットに繋いで現在時刻の取得をすることが必要なようでした(Wifiを繋がずに時刻を扱えるかは未確認)。

ただ現状では持ち運ぶ用途であるため、インターネットに繋げない状況での利用がメインになります。

つまり時刻を扱えないのではないかと考えられました。

そこでループが何回回ったかを数えておくことで代用しようとしているわけです。

特に処理で時間がかかる部分もないので、時間の中で圧倒的に長いのは「delay(500)」となると予想され、単純に「delay時間xcycle数」で経過時間を知ることができると思われます。

また最終的にはdelay時間はもっと伸ばす予定なので、さらに誤差は少なくなると考えられます。

ということでとりあえずはこれでいきましょう。

loop関数の後半はセンサが抜けたりしていないかのチェック部分で、スケッチ例からコピーしてきただけなので解説は割愛します。

このスケッチをM5StickCで実行すると画面にはこのような表示がされます。

またシリアル出力ではこのような出力がされます。

正直この数字が直接地磁気の強さを示しているのかは疑問ですが、今回は移動した際の変化を見るという目的なので、値の単位に関してはそれほど気にする必要はないのかなと思います。

ということでこれで磁気データの取得をすることができました。

次回はこの磁気データをSPIFFS領域に保存していきましょう。

ではでは今回はこんな感じで。

¥2,816 (2021/07/05 10:12時点 | Amazon調べ)
\楽天ポイント5倍セール!/
楽天市場
よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次