LoginSignup
8

More than 3 years have passed since last update.

posted at

updated at

M5Stackの回転データが勝手に回り続けることになる問題の対策

回転情報がおかしい...

M5Stackで回転情報を使おうとした時にこんな問題に遭遇しました。
一応の対策は取れたので、もし同じ現象に悩む人がいた時のためにメモ代わりとして記事に残してみます。


現象は↑の通りですが、M5StackのIMUサンプルコードをとりあえず動かしてみたら、pitch・roll・yawの回転情報のうち、静止していてもyawがずっと動き続ける問題に悩まされてしまいました。

対策を探る

他のセンサー値をよくよく見ると、Z軸のgyro情報が常に-15〜-17になっていることに気付きました。
止まっているのに、Z軸方向に常に回転加速度が加えられている状態のようです。
ここが怪しい気配です。
これが故障なのかどうかはわかりませんが、似たようなissueは発見しました。

↑のissueでは、BMM150を組み合わせてどうにかする的なことが書いてますが、BMM150のサンプルコード見てもいまいち解決に繋がるのか不明でした...。

どうしたものかと思ったけど、gyroのセンサーデータの狂いはどうやらほぼ一定のようです。
pitch・roll・yawは加速度と回転加速度を使って算出するので、gyroのデータに補正をかけてから計算してやると対策できるのでは?と思って試したところ、効果アリでした。

M5StackはGitHubにソースが上がっているので、その中から該当する計算箇所を探してみると、utility/MahonyAHRS.hでpitch・roll・yawを計算している箇所を発見。
https://github.com/m5stack/M5Stack/tree/master/src

これで対策が取れそうだと思って、実際に↓のようなことを試しました。(記事下にコード載せてます)

対策できた

というわけでコレができました。
やってることはシンプルですが、物が動くとちょっと楽しい。

対策したコード

M5StackのIMUサンプルコードを今回の対策用に改造した際のコードを載せておきます。
この方法の場合、起動時に補正用の平均データが溜まるまでは静止させておく必要があります。
あと、根本的な解決策がわかる方いたら教えてくれると嬉しいです。

IMU.ino
// define must ahead #include <M5Stack.h>
#define M5STACK_MPU6886 
// #define M5STACK_MPU9250 
// #define M5STACK_MPU6050
// #define M5STACK_200Q

#include <M5Stack.h>
//[追加]MahonyAHRSupdateIMU()を呼べるようにするため
#include <utility/MahonyAHRS.h>

float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;

float gyroX = 0.0F;
float gyroY = 0.0F;
float gyroZ = 0.0F;

float pitch = 0.0F;
float roll  = 0.0F;
float yaw   = 0.0F;

float temp = 0.0F;

//[追加]GyroZのデータを蓄積するための変数
float stockedGyroZs[10];
int stockCnt=0;
float adjustGyroZ=0;
int stockedGyroZLength=0;

// the setup routine runs once when M5Stack starts up
void setup(){

  stockedGyroZLength=sizeof(stockedGyroZs)/sizeof(int);

  // Initialize the M5Stack object
  M5.begin();
  /*
    Power chip connected to gpio21, gpio22, I2C device
    Set battery charging voltage and current
    If used battery, please call this function in your project
  */
  M5.Power.begin();

  M5.IMU.Init();

  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(GREEN , BLACK);
  M5.Lcd.setTextSize(2);
}

// the loop routine runs over and over again forever
void loop() {
    // put your main code here, to run repeatedly:
  M5.IMU.getGyroData(&gyroX,&gyroY,&gyroZ);
  M5.IMU.getAccelData(&accX,&accY,&accZ);
  //[変更]これは使わない
  // M5.IMU.getAhrsData(&pitch,&roll,&yaw); 

  //[追加]起動時にstockedGyroZLengthの数だけデータを貯める
  if(stockCnt<stockedGyroZLength){
    stockedGyroZs[stockCnt]=gyroZ;
    stockCnt++;
  }else{
    if(adjustGyroZ==0){
      for(int i=0;i<stockedGyroZLength;i++){
        adjustGyroZ+=stockedGyroZs[i]/stockedGyroZLength;
      }
    }
    //貯めたデータの平均値を使ってgyroZを補正する
    gyroZ-=adjustGyroZ; 
    //ここでaccelデータと補正したgyroデータを使ってpitch・roll・yawを計算する
    MahonyAHRSupdateIMU(gyroX * DEG_TO_RAD, gyroY * DEG_TO_RAD, gyroZ * DEG_TO_RAD, accX, accY, accZ, &pitch, &roll, &yaw);
  }

  //ここから下は変更無し
  M5.IMU.getTempData(&temp);

  M5.Lcd.setCursor(0, 20);
  M5.Lcd.printf("%6.2f  %6.2f  %6.2f      ", gyroX, gyroY, gyroZ);
  M5.Lcd.setCursor(220, 42);
  M5.Lcd.print(" o/s");
  M5.Lcd.setCursor(0, 65);
  M5.Lcd.printf(" %5.2f   %5.2f   %5.2f   ", accX, accY, accZ);
  M5.Lcd.setCursor(220, 87);
  M5.Lcd.print(" G");
  M5.Lcd.setCursor(0, 110);
  M5.Lcd.printf(" %5.2f   %5.2f   %5.2f   ", pitch, roll, yaw);
  M5.Lcd.setCursor(220, 132);
  M5.Lcd.print(" degree");
  M5.Lcd.setCursor(0, 155);
  M5.Lcd.printf("Temperature : %.2f C", temp);

  delay(1);
}

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
8