傾斜計 > MPU-9250の加速度の校正方法 (おそらく)

```txt:動作環境
ESP-WROOM-02
MPU-9250 https://strawberry-linux.com/catalog/items?code=12250
ライブラリ https://github.com/jrowberg/i2cdevlib/
```

MPU-9250で加速度の校正ができたようだ。方法に関する資料はなく、結果を見ながらの推測。

手順は以下の通り。

`1. Arduino\libraries\MPU9150\MPU9150.hのレジスタの値を変更する
  (これはレジスタマップを参照した)

```MPU9150.h
/*
#define MPU9150_RA_XA_OFFS_H        0x06 //[15:0] XA_OFFS
#define MPU9150_RA_XA_OFFS_L_TC     0x07
#define MPU9150_RA_YA_OFFS_H        0x08 //[15:0] YA_OFFS
#define MPU9150_RA_YA_OFFS_L_TC     0x09
#define MPU9150_RA_ZA_OFFS_H        0x0A //[15:0] ZA_OFFS
#define MPU9150_RA_ZA_OFFS_L_TC     0x0B
*/
#define MPU9150_RA_XA_OFFS_H        0x77 //[15:0] XA_OFFS
#define MPU9150_RA_XA_OFFS_L_TC     0x78
#define MPU9150_RA_YA_OFFS_H        0x7A //[15:0] YA_OFFS
#define MPU9150_RA_YA_OFFS_L_TC     0x7B
#define MPU9150_RA_ZA_OFFS_H        0x7D //[15:0] ZA_OFFS
#define MPU9150_RA_ZA_OFFS_L_TC     0x7E
```

`2. getXAccelOffset()などで元の値を取得する
    (例: XOFFSET:-5170, YOFFSET:5390. ZOFFSET:8424)

```
  Serial.println(accelgyro.getXAccelOffset());
  Serial.println(accelgyro.getYAccelOffset());
  Serial.println(accelgyro.getZAccelOffset());
```

`3. 元の値に2の倍数を足し引きする
    測定値と正負反対の値を8で割った値に近い2の倍数とする。
    (奇数を足し引きすると全く異なる値になる)

```
  accelgyro.setXAccelOffset(-5170 - 8); // divide by 8, but should be even not odd number
  accelgyro.setYAccelOffset(5390 - 38); // divide by 8, but should be even not odd number 
  accelgyro.setZAccelOffset(8424 + 16); // divide by 8, but should be even not odd number
```

## code v0.2

[v0.2 @ github](https://github.com/yasokada/esp8266_160703_calibMPU9250/releases/tag/v0.2)

```c:esp8266_160703_calibMPU9250.ino
/*
 * v0.2 2016 Jul. 05
 *   - add calibration example
 * v0.1 2016 Jul. 03
 *   - remove Calibration()
 *   - use Interrupt
 *   - import for MPU-9250
 *   - based on the code at
 *   http://www.i2cdevlib.com/forums/topic/96-arduino-sketch-to-automatically-calculate-mpu6050-offsets/
 */

#include "I2Cdev.h"
#include "MPU9150_9Axis_MotionApps41.h"
#include "Wire.h"
#include <ESP8266WiFi.h>
MPU9150 accelgyro;

#define INTERRUPT_PIN 14  // ESP8266

int buffersize = 1000;     //Amount of readings used to average, make it higher to get more precision but sketch will be slower  (default:1000)
int16_t ax, ay, az,gx, gy, gz;

int mean_ax, mean_ay, mean_az;
int mean_gx, mean_gy, mean_gz;
int state=0;
int ax_offset, ay_offset, az_offset;
int gx_offset, gy_offset, gz_offset;

uint16_t packetSize;
uint16_t fifoCount;

void meansensors();
void showData();

volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}

void setup() {
  WiFi.disconnect();
  Wire.begin();
  Wire.setClock(400000L); // 400kHz
  Serial.begin(115200);

  accelgyro.initialize();
  pinMode(INTERRUPT_PIN, INPUT);

  while (Serial.available() && Serial.read()); // empty buffer
  while (!Serial.available()){
    Serial.println(F("Send any character to start sketch.\n"));
    delay(1500);
  }                
  while (Serial.available() && Serial.read()); // empty buffer again

  packetSize = accelgyro.dmpGetFIFOPacketSize();

  Serial.println("\nYour MPU-9250 should be placed in horizontal position, with package letters facing up. \nDon't touch it until you see a finish message.\n");
  delay(3000);
//  // verify connection
//  Serial.println(accelgyro.testConnection() ? "MPU9250 connection successful" : "MPU9250 connection failed");
//  delay(1000);
}

void loop() {
  if (state==0){
    Serial.println("\nReading sensors for first time...");
    meansensors();
    state++;
    delay(1000);
  }

  if (state==1) {
    Serial.println("\nMeasuring...");
    showData(); 
    state++;
    delay(1000);
  }

  if (state==2) {
    meansensors();
    Serial.print("\nSensor readings with zero offsets:\t");
    Serial.print(mean_ax); 
    Serial.print("\t");
    Serial.print(mean_ay); 
    Serial.print("\t");
    Serial.print(mean_az); 
    Serial.print("\t");
    Serial.print(mean_gx); 
    Serial.print("\t");
    Serial.print(mean_gy); 
    Serial.print("\t");
    Serial.println(mean_gz);
    Serial.println("\nData is printed as: acelX acelY acelZ giroX giroY giroZ");
    Serial.println("Check that your sensor readings are close to 0 0 16384 0 0 0");
    state++;
  }
}

///////////////////////////////////   FUNCTIONS   ////////////////////////////////////
void meansensors(){
  long i=0;
  int buff_ax=0;
  int buff_ay=0;
  int buff_az=0;
  int buff_gx=0;
  int buff_gy=0;
  int buff_gz=0;

  while (i < (buffersize + 101) ){
    fifoCount = accelgyro.getFIFOCount();
    if (!mpuInterrupt && fifoCount < packetSize) {
      continue;
    }
    mpuInterrupt = false;
    
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
        
    if ( (i > 100) && i <= (buffersize + 100) ){ // First 100 discarded
      buff_ax = buff_ax + ax;
      buff_ay = buff_ay + ay;
      buff_az = buff_az + az;
      buff_gx = buff_gx + gx;
      buff_gy = buff_gy + gy;
      buff_gz = buff_gz + gz;
    }
    if ( i == (buffersize + 100) ) {
      mean_ax = buff_ax / buffersize;
      mean_ay = buff_ay / buffersize;
      mean_az = buff_az / buffersize;
      mean_gx = buff_gx / buffersize;
      mean_gy = buff_gy / buffersize;
      mean_gz = buff_gz / buffersize;
    }
    i++;
  }
}

void showData()
{
  Serial.println(accelgyro.getXAccelOffset());
  Serial.println(accelgyro.getYAccelOffset());
  Serial.println(accelgyro.getZAccelOffset());
  
//  accelgyro.setXAccelOffset(0);
//  accelgyro.setYAccelOffset(0);
//  accelgyro.setZAccelOffset(0);
//  accelgyro.setXGyroOffset(0);
//  accelgyro.setYGyroOffset(0);
//  accelgyro.setZGyroOffset(0);

  for(int loop = 0; loop < 10; loop++) {
    meansensors();
    Serial.print(" ,mean_ax:");
    Serial.print(mean_ax);
    Serial.print(" ,mean_ay:");
    Serial.print(mean_ay);
    Serial.print(" ,mean_az:");
    Serial.print(mean_az);
    //
    Serial.print(" ,mean_gx:");
    Serial.print(mean_gx);
    Serial.print(" ,mean_gy:");
    Serial.print(mean_gy);
    Serial.print(" ,mean_gz:");
    Serial.print(mean_gz);
    //
    Serial.println();
  }

  accelgyro.setXAccelOffset(-5170 - 8); // divide by 8, but should be even not odd number
  accelgyro.setYAccelOffset(5390 - 38); // divide by 8, but should be even not odd number 
  accelgyro.setZAccelOffset(8424 + 16); // divide by 8, but should be even not odd number
  accelgyro.setXGyroOffset( 80 / 4); // divide by 4 
  accelgyro.setYGyroOffset( 8 / 4); // divide by 4
  accelgyro.setZGyroOffset( 286 / 4); // divide by 4

  for(int loop = 0; loop < 10; loop++) {
    meansensors();
    Serial.print(" ,mean_ax:");
    Serial.print(mean_ax);
    Serial.print(" ,mean_ay:");
    Serial.print(mean_ay);
    Serial.print(" ,mean_az:");
    Serial.print(mean_az);
    //
    Serial.print(" ,mean_gx:");
    Serial.print(mean_gx);
    Serial.print(" ,mean_gy:");
    Serial.print(mean_gy);
    Serial.print(" ,mean_gz:");
    Serial.print(mean_gz);
    //
    Serial.println();
  }
  
}
```

```txt:結果
Send any character to start sketch.

Send any character to start sketch.


Your MPU-9250 should be placed in horizontal position, with package letters facing up. 
Don't touch it until you see a finish message.


Reading sensors for first time...

Measuring...
-5170
5390
8424
 ,mean_ax:63 ,mean_ay:304 ,mean_az:16262 ,mean_gx:-78 ,mean_gy:-10 ,mean_gz:-287
 ,mean_ax:63 ,mean_ay:306 ,mean_az:16261 ,mean_gx:-78 ,mean_gy:-10 ,mean_gz:-285
 ,mean_ax:60 ,mean_ay:307 ,mean_az:16264 ,mean_gx:-77 ,mean_gy:-8 ,mean_gz:-285
 ,mean_ax:60 ,mean_ay:308 ,mean_az:16264 ,mean_gx:-78 ,mean_gy:-8 ,mean_gz:-286
 ,mean_ax:62 ,mean_ay:309 ,mean_az:16267 ,mean_gx:-78 ,mean_gy:-9 ,mean_gz:-285
 ,mean_ax:65 ,mean_ay:309 ,mean_az:16263 ,mean_gx:-77 ,mean_gy:-8 ,mean_gz:-286
 ,mean_ax:66 ,mean_ay:309 ,mean_az:16255 ,mean_gx:-77 ,mean_gy:-7 ,mean_gz:-286
 ,mean_ax:64 ,mean_ay:309 ,mean_az:16258 ,mean_gx:-79 ,mean_gy:-8 ,mean_gz:-285
 ,mean_ax:65 ,mean_ay:304 ,mean_az:16260 ,mean_gx:-79 ,mean_gy:-9 ,mean_gz:-285
 ,mean_ax:55 ,mean_ay:305 ,mean_az:16256 ,mean_gx:-78 ,mean_gy:-8 ,mean_gz:-285
 ,mean_ax:-3 ,mean_ay:7 ,mean_az:16388 ,mean_gx:2 ,mean_gy:0 ,mean_gz:-2
 ,mean_ax:-4 ,mean_ay:1 ,mean_az:16388 ,mean_gx:1 ,mean_gy:0 ,mean_gz:-1
 ,mean_ax:0 ,mean_ay:3 ,mean_az:16388 ,mean_gx:1 ,mean_gy:0 ,mean_gz:-2
 ,mean_ax:0 ,mean_ay:7 ,mean_az:16390 ,mean_gx:1 ,mean_gy:0 ,mean_gz:-2
 ,mean_ax:0 ,mean_ay:4 ,mean_az:16387 ,mean_gx:1 ,mean_gy:-2 ,mean_gz:-1
 ,mean_ax:0 ,mean_ay:6 ,mean_az:16389 ,mean_gx:2 ,mean_gy:-1 ,mean_gz:-1
 ,mean_ax:-1 ,mean_ay:5 ,mean_az:16388 ,mean_gx:0 ,mean_gy:0 ,mean_gz:-1
 ,mean_ax:0 ,mean_ay:1 ,mean_az:16390 ,mean_gx:1 ,mean_gy:0 ,mean_gz:-1
 ,mean_ax:0 ,mean_ay:5 ,mean_az:16383 ,mean_gx:0 ,mean_gy:0 ,mean_gz:0
 ,mean_ax:-3 ,mean_ay:1 ,mean_az:16391 ,mean_gx:0 ,mean_gy:-2 ,mean_gz:-2

Sensor readings with zero offsets:	0	9	16387	2	-2	-2

Data is printed as: acelX acelY acelZ giroX giroY giroZ
Check that your sensor readings are close to 0 0 16384 0 0 0
```

### 補足

- 加速度の補正値を8で割ったり、ジャイロの補正値を4で割る理由は不明だが、MPU-6050の補正でも8や4で割っていた。

- 補正値を奇数にすると値がおかしくなる
  - [レジスタマップ](https://strawberry-linux.com/pub/RM-MPU-9250A-00.pdf)のp.44, XA_OFFS_Lの説明にBIT[7:1]とあり、LSB([0]のこと)については設定しないようになっている。奇数の場合(LSB=1)おかしな測定値が出力されるのと関係があるのかもしれない

- azは16384に近ければ補正できている。他の値は0に近いこと。

- 一番最初に加速度のオフセットを0にしてしまうと、元の値とまったく異なる値になり、32768や-32768の測定値になってしまう。元の値からの補正にすること。