入手しやすいデバイスを使って作業効率アップ

M5StackやM5Paperなどを使って効率アップデバイスを作ります。

昔買ったM5GOで移動計を作る

昔買ったまま放置していたM5GOで何か出来ないかと考えていたところ、初期のM5GOには地磁気センサーが標準搭載されている事に気づきました。
(M5GOには昔から搭載されていないと思い違いをしていました)

加速度センサーで歩数を、地磁気センサーで方位を測定して、1歩ごとの方位を記録すれば簡易移動ロガーができそうです。
GPSが無かった頃の初期のカーナビみたいなやり方です。
加速度センサーは標準のライブラリを使い、地磁気センサーのBMM150はライブラリマネージャでインストールします。私は、M5_BMM150を使用しました。
作り方を調べてみましたが、歩数計の部分の作り方は大体同じです。
方位磁石もサンプルスケッチを参考にしました。

どちらのデータもちらつくので、直前までのデータを何個か保存しておいて、平均をとります。保存する個数はソフトを作りながら決定しました。
1歩ごとに方位を記録していきます。
M5GOの仕事はここまでで、データはCSVファイルにしてパソコンで加工します。

BMM150のサンプルスケッチがベースになっています。追加した部分のみ掲載します。
データ保存とかはそれぞれだと思いますので掲載していません。
加速度センサーは使う前に平らな場所で補正する必要があります。
地磁気センサーは毎回補正しなくてもいいようです。

補正値を計測する部分と、それを適用する部分です。
私はいつも、サンプルコードのオリジナル部分と区別するため、{}の付け方とタブ数を変えています。

float acc[3];
float gyro[3];
float aOfs[3];
float gOfs[3];

void readGyro()
{
 M5.MPU6886.getGyroData(&gyro[0], &gyro[1], &gyro[2]);
 M5.MPU6886.getAccelData(&acc[0], &acc[1], &acc[2]);
}

void mpu6886_calibrate()
{
 float gSum[3];
 float aSum[3];
 for(int i = 0; i < 500; i++)
 {
  readGyro();
  gSum[0] += gyro[0];
  gSum[1] += gyro[1];
  gSum[2] += gyro[2];
  aSum[0] += acc[0];
  aSum[1] += acc[1];
  aSum[2] += acc[2];
  delay(2);
 }
 gOfs[0] = gSum[0]/500;
 gOfs[1] = gSum[1]/500;
 gOfs[2] = gSum[2]/500;
 aOfs[0] = aSum[0]/500;
 aOfs[1] = aSum[1]/500;
 aOfs[2] = aSum[2]/500 - 1.0;
}

void apply_mpu6886_calibrate()
{
 gyro[0] -= gOfs[0];
 gyro[1] -= gOfs[1];
 gyro[2] -= gOfs[2];
 acc[0] -= aOfs[0];
 acc[1] -= aOfs[1];
 acc[2] -= aOfs[2];
}

読み出したデータはちらつくので平滑化します。
バッファして平均をとります。

#define ACC_CNT_MAX 8
#define ACC_LOW 1040
float accBuf[ACC_CNT_MAX];

以下、セットアップ部分になります。
まずは加速度センサーMPU6886の初期化です。

void setup(void){
 M5.begin();
 M5.Power.begin();  //Init Power module.
 Wire.begin();
 M5.Lcd.setTextSize(2);
 adc_power_acquire();

 M5.Mpu6886.Init();
 M5.Mpu6886.setAccelFsr(M5.Mpu6886.AFS_2G);

地磁気センサーBMM150の初期化です。
地磁気センサーも補正が必要なのですが、サンプルスケッチでは補正値はNVS領域に保存されています。

 M5.Lcd.println("BMM150 INIT ...");
 if(bmm150_initialization() != BMM150_OK)
 {
  M5.Lcd.println("BMM150 ERROR ...");
  for(;;)
  {
   delay(100);
  }
 }
 M5.Lcd.println("BMM150 OFFSET LOAD ...");
 bmm150_offset_load();

最初に加速度センサーの補正を行います。

 M5.Lcd.println("MPU6886 CALIBRATION ...");
 mpu6886_calibrate();

地磁気センサーの補正を行います。毎回やらないくてもいいので、スキップできるようにしています。

 M5.Lcd.println("");
 M5.Lcd.println("BMM150 CALIBRATION btnC");
 M5.Lcd.println("      CANCEL btnB");

 for(;;)
 {
  M5.update();
  if(M5.BtnC.wasPressed())
  {
   M5.Lcd.println("FLIP AND ROTATE");
   M5.Lcd.println("for 10 seconds");
   bmm150_calibrate(10000);
   break;
  }
  if(M5.BtnB.wasPressed())
  {
   break;
  }
 }

 M5.Lcd.fillScreen(BLACK);
 M5.Lcd.setTextSize(4);

以下ループ部分です。地磁気センサーと加速度センサーを読み出します。
地磁気は±180度に変換し、10度単位にします。
加速度はXYZ軸全部を2乗して足して平方根をとります。

int max0=-10000;
int min0=10000;
float a0;
float ax, ay, az;
int mark=0;
int accCnt=0;
int flg0=0;
int pedometer=0;
int acc0=0;
int stepNum=0;

struct pedoStruct
{
 int cnt;
 int tm;
 int head;
 int pre;
 int mrk;
} pedoData[3600];

unsigned long tm0=0;

void loop(void){
 tm0=millis()/1000;
 M5.update();  //Read the press state of the key.
 bmm150_read_mag_data(&dev);
 float head_dir=atan2(dev.data.x-mag_offset.x,dev.data.y-mag_offset.y)*180.0/M_PI;
 int head_dir2=((int)head_dir/10)*10;
 readGyro();
 apply_mpu6886_calibrate();

 ax=acc[0];
 ay=acc[1];
 az=acc[2];
 a0=sqrt(ax*ax+ay*ay+az*az);

平滑化するためにバッファします。
計算結果が閾値以上なら歩数カウントアップします。
最大値と最小値も保存しておきます。

 accBuf[accCnt]=a0;
 accCnt++;
 if(accCnt>=ACC_CNT_MAX)
 {
  accCnt=0;
 }

 float accSum=0;
 for(int j=0; j<ACC_CNT_MAX; j++)
 {
  accSum+=accBuf[j];
 }
 acc0=(accSum/ACC_CNT_MAX)*1000;

 if(acc0>max0)
 {
  max0=acc0;
 }
 if(acc0<min0)
 {
  min0=acc0;
 }

 if((flg0==0)&&(acc0>ACC_LOW))
 {
  pedometer++;

歩数カウントがアップしたら測定データを保存し、一時データを初期化します。
フラグをONして、加速度が1G以下になるまでスルーさせます。

  max0=-10000;
  min0=10000;
  for(int j=0; j<ACC_CNT_MAX; j++)
  {
   accBuf[j]=1;
  }
  pedoData[pedometer].cnt=pedometer;
  pedoData[pedometer].tm=millis()/1000;
  pedoData[pedometer].head=head_dir2;
  accCnt=0;
  flg0=1;
 }

 if((flg0==1)&&(acc0<1000))
 {
  flg0=0;
 }