ArduinoでGY-521: MPU6050 (3軸 加速度・角速度センサ)から加速度と角速度を読み出す仕様を調べました

この記事で学習できること

GY‑521(MPU6050)を色々な場面で使えるように基本的な動作から細かなレジスタの設定までを網羅的に記事にしています。自分のプロジェクトに合わせて関連項目を参照ください。

  • GY‑521(MPU6050)モジュールの仕組みと特徴が理解できる
  • Arduino と GY‑521 の正しい配線方法がわかる
  • I2C アドレスの確認方法とトラブル対処ができる
  • 加速度・角速度データの読み取り方法を習得できる
  • MPU6050 の主要レジスタ(PWR_MGMT_1 / ACCEL_CONFIG / GYRO_CONFIG / DLPF)の役割を理解できる
  • DLPF(デジタル・ローパス・フィルタ)の設定によるノイズ変化を比較できる
  • 加速度データから傾斜角度を計算する方法がわかる
  • 生データのノイズ対策やフィルタリングの基礎が理解できる
  • 実際に動作する Arduino コードを使ってセンサーを扱えるようになる
  • 姿勢制御・ロボット制御など応用分野への発展イメージがつかめる

GY‑521(MPU6050)モジュールとは

GY‑521 はMPU6050 を基板化したモジュールです。MPU6050 は 3軸加速度センサー + 3軸角速度センサー を 1 チップに統合した IMU(Inertial Measurement Unit)です。

  • 3軸加速度(Accelerometer)X, Y, Z 方向の加速度および3軸角速度(Gyroscope)X, Y, Z 方向の角速度の測定ができます。

姿勢推定(Pitch / Roll / Yaw)、動きの検出(Motion Detection)、角度の積分による回転量の計測に使えます。

  • 具体的な用途としては、以下の様な具体例が考えられます。
    • 自作ドローンの姿勢制御
    • 自立バランスロボット(倒立振子)の姿勢制御
    • 衝撃検出(落下検知)
    • ゲームコントローラ(Wii リモコンのような動き検出)

GY-521を使った電子工作の具体例

  • Arduinoを使った電子工作で、自立型のバランスを取るロボットがあり、GY-521が姿勢制用途に使われることがあります。
  • GY-521の加速度センサは地球の重力加速度を計測し、ロボットの傾きを計算するのに使われます。
  • GY-521の角速度センサはロボットが倒れている角速度を計測し、ロボットの傾斜を適切に補正する制御のために使われます。
— 自己バランスロボット(倒立振子)の動作の概念図 —
  • 自立型ロボットにGY-521を使うと、垂直の位置ではZ軸方向のみ重力加速度が検出されますが、傾くとY軸方向にも重力加速度が検出されます。Z軸のみ重力加速度が検出されるように制御することで自立動作が可能になります。

GY-521(MPU6050)の加速度・角速度の測定の仕組みと変位の呼称は?

  • MPU6050 は MEMS(Micro Electro Mechanical Systems)技術で作られた 超小型の機械構造を使って加速度と角速度を測定します。
  • MPU6050内部の質量が重力加速度を受けたり回転時のコリオリ力を受けたりするとひずみます。このひずみが容量の変化となります。MPU6050はこの容量変化を測定しX,Y,Z軸の加速度と角速度に変換します。
— MPU6050のMEMS部の概念図 —
  • 船が進行している状況考えた場合、波や風で前後左右上下の軸方向と軸の回転方向に動きます。3次元を、X,Y,Z軸で考えた場合、その6種類の動きに名称が付けられています。GY-521の使用方法に関わる記事を探すと、動きをこれらの用語で説明していることがあります。
— 物体の変位の呼称 —

ArduinoとGY-521の接続方法は?

  • ArduinoのI2C用の2つのポート(SCL、SDA)と電源(5V)、グランドの合計4本の簡単な接続です。
  • GY-521のfritzing用のデータがインターネットで見つかりましたので使わさせて頂きました。
  • fritzingの回路図(配線図)を基に実際に配線しました。
— Arduino UNO R3 とGY-521(MPU6050)の接続 —

GY-521のI2Cアドレスは?

  • GY-521はI2Cインターフェースを介して操作します。I2Cのアドレスを確認します。
  • I2C LCDデバイスのアドレスを調べるには、Aduinoのウェブで公開されているI2C Scannerを使用します。
// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    https://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
// 
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//

#include <Wire.h>


void setup()
{
  Wire.begin();

  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}
  • I2C Scannerを使うとシリアルモニタにGY-521モジュールのアドレスが表示されます。アドレスが”0x68”であることが解りました。
I2C device found at address 0x68  !
  • もし検出できなった場合は、Arduinoとモジュール接続を確認ください。

GY-521の出力を読み出すスケッチの例

  • スケッチを使ってどのような計測値が出力されるか調べます。GY-521(MPU6050)のアドレスは”0x68”でしたから、このアドレスをI2Cの通信に使います。
  • I2C通信にWire.hライブラリを使います。
// MPU-6050 Short Example Sketch

#include<Wire.h>
const int MPU_addr=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
}
void loop(){
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)    
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  Serial.print("AcX = "); Serial.print(AcX);
  Serial.print(" | AcY = "); Serial.print(AcY);
 Serial.print(" | AcZ = "); Serial.print(AcZ);
 Serial.print(" | Tmp = "); Serial.print(Tmp/340.00+36.53);  //equation for temperature in degrees C from datasheet
Serial.print(" | GyX = "); Serial.print(GyX);
  Serial.print(" | GyY = "); Serial.print(GyY);
 Serial.print(" | GyZ = "); Serial.println(GyZ);
  delay(333);
}
  • シリアルモニタを9600bps設定して出力を表示します。
  • 加速度(AcX, AcY,AcZ)、温度(Tmp)、角速度(GyX,GyY,GyZ) の値が出力されます。
— シリアルモニタからの出力 —

GY-521(MPU6050)のレジスタマッピングとアクセスを理解する

  • GY-521の出力は読み出せましたが、GY-521をスケッチでどのように操作するかを理解しないと電子工作に使えません。GY-521に内蔵されるMPU-6050が加速度センサ、角速度センサ、温度センサの機能を持っています。開発元のデータシートとレジスタマッピングの仕様書を調べ、スケッチの記述を理解します。
MPU-6050 のデータシートとレジスタマッピングの資料は?
  • MPU-60X0は、3軸のジャイロスコープと3軸の加速度計とデジタルモーションプロセッサを4x4x0.9mmの小さなパッケージに集積した世界初の6軸動作追従デバイスです。
  • MPU-60X0は16ビットのADコンバータで3軸のジャイロスコープ出力(角速度出力)と3軸の加速度出力をデジタル化し、早い動きと遅い動きに正確に追従する、ユーザーがプログラム可能な +/-250, +/-500, +/-1000, +/-2000°/sec(dsp)のジャイロスコープと、+/-2g, +/-4g, +/-8g, +/-16gの加速度計を持つ特徴を備えています
  • レジスターの詳細説明の冒頭部です。注釈で、MP-U6050は電源ON後はスリープモードになっていると書かれています。
  • PWR_MGMT_1 レジスターのアドレスは0x6Bで、この中のSLEEPビットが0ならスリープの解除状態、1ならスリープ状態です。
  • GY-521から測定値を読み出すスケッチで0x6Bに0x00を書き込む箇所があります。この操作で電源ON後にスリープ状態になっているMPU-6050を動作状態にしています。
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  • MPU-6050に加速度、温度、角速度の測定値が書かれているレジスタは、0x3Bから0x48になります。
  • GY-521から測定値を読み出すスケッチでは、0x3B以降のレジスタの値を呼び出していることが解ります。
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)    
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  • AcXはX軸方向の加速度で、sureg(サージ)です。またGyXはX軸方向の角速度でroll(ロール)です。温度はTmpの変数名で読みだされます。
  • 読み出された値はArduino IDEのSerial.print()関数とSerial.println()関数を使ってシリアルモニタに表示されます。

GY-521(MPU6050)の設定方法を詳しく調べます

  • GY-521(MPU6050)で測定する加速度と角速度を読み出す方法を学習しましたが、MPU6050のレジスタマッピング仕様書に、レジスタを使った加速度計と角速度計(ジャイロ)の自己診断、出力レンジ、フィルタの設定の説明がありました。
  • MPU6050 のレジスターの0x1CのBit7,Bit6とBit5を使用して、指定する軸の加速度計の自己診断を実行します。
  • MPU6050 のレジスターの0x1CのBit4とBit3を使用して加速度センサの自己診断の実行と加速度測定レンジを+/-2g, +/-4g, +/-8g, +/-16gから選択できます。
  • 自己診断した値が、製品規格の最大・最小値以内であれば合格と判断されます
  • 設定した加速度測定レンジを実際の数値に換算する係数が記載されています。
  • MPU6050 のレジスターの0x1BのBit7,Bit6とBit5を使用して、指定する軸のジャイロスコープの自己診断を実行します。
  • MPU6050 のレジスターの0x1BのBit4とBit3を使用して角速度センサの自己診断の実行と角速度測定レンジを+/-250, +/-500, +/-1000, +/-2000°/sec(dsp)から選択できます。
  • 自己診断した値が、製品規格の最大・最小値以内であれば合格と判断されます
  • 設定した角速度測定レンジを実際の数値に換算する係数が記載されています。
  • MPU6050 のレジスターの0x1AのBit2,Bit1とBit0を使用して、加速度センサと角速度センサ(ジャイロ)のDLP(デジタルローパスフィルター)を設定します。

MPU6050のレジスタを読み書きするスケッチを作成します

  • MPU6050のレジスタから1Byteを読み出す関数を作ります。
  • MPU6050のアドレスと読み出したいレジスタアドレスをint型で設定して関数を呼び出します。
  • レジスタの値がuint_8型で返ってきます。
// Furntion to read a byte from a register
uint8_t MPU6050_ReadRegister_Byte (int MPUAdd, int Reg){

  uint8_t Value;

  Wire.beginTransmission(MPUAdd);
  Wire.write(Reg);  // starting with register ReadReg
  Wire.endTransmission(true);

  Wire.beginTransmission(MPUAdd);  
  Wire.requestFrom(MPUAdd,1,true);  // request a total of 1 register
  Value=Wire.read();  // Value of ReadReg    
  Wire.endTransmission(true);

  return  Value;
}
  • MPU6050のレジスタに1Byteを書き込む関数を作ります。
  • MPU6050のアドレスと読み出したいレジスタアドレスをint型で設定します。書き込みたい値をuint_8型で設定します。関数を呼び出して1Byteのデータを書き込みます。
// Furntion to write a byte to a register
uint8_t MPU6050_WriteRegister_Byte (int MPUAdd, int Reg, uint8_t Value){

  Wire.beginTransmission(MPUAdd);
  Wire.write(Reg);  // Register for writing
  Wire.write(Value);  // Write value     
  Wire.endTransmission(true);
}
  • MPU6050のレジスタに1Byteデータを読み書きする関数を作りました。これらの関数を使って、MPU6050の13番から117番のレジスタを読出します。
  • 一覧の読み込みは1回実行すれば良いのでsetup()のみ使用しています。
// MPU-6050のレジスタを読み出し表示する

#include<Wire.h>
const int MPU_addr=0x68;  // I2C address of the MPU-6050
const int WR_MGMT_1_addr=0x6B;  // MPU-6050 PWR_MGMT_1 register
int ReadReg=0x1C;   // Register in MPU-6050
uint8_t ReadRegValue;     // Register Value

// Furntion to write a byte to a register
uint8_t MPU6050_WriteRegister_Byte (int MPUAdd, int Reg, uint8_t Value){

  Wire.beginTransmission(MPUAdd);
  Wire.write(Reg);  // Register for writing
  Wire.write(Value);  // Write value     
  Wire.endTransmission(true);
}

// Furntion to read a byte from a register
uint8_t MPU6050_ReadRegister_Byte (int MPUAdd, int Reg){

  uint8_t Value;

  Wire.beginTransmission(MPUAdd);
  Wire.write(Reg);  // starting with register ReadReg
  Wire.endTransmission(true);

  Wire.beginTransmission(MPUAdd);  
  Wire.requestFrom(MPUAdd,1,true);  // request a total of 1 register
  Value=Wire.read();  // Value of ReadReg    
  Wire.endTransmission(true);

  return  Value;
}

void setup(){
  Wire.begin();
  Serial.begin(9600);
  
  //Wakeup MPU-6050  
  Wire.beginTransmission(MPU_addr);
  Wire.write(WR_MGMT_1_addr);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);

  // Read and show registers value
  int i = 13;

  while (i < 118){

    ReadReg = i; 
    ReadRegValue = MPU6050_ReadRegister_Byte(MPU_addr, ReadReg);
    Serial.print("Register = "); Serial.print(ReadReg); Serial.print("   ");
    Serial.print("ReadRegValue = "); Serial.println(ReadRegValue);
  
    delay(10);
     i = i+1;
   }
}

void loop(){
}
  • 読み出したレジスタ(#13-#117) 値です
Register = 13   ReadRegValue = 109
Register = 14   ReadRegValue = 110
Register = 15   ReadRegValue = 128
Register = 16   ReadRegValue = 97
Register = 17   ReadRegValue = 0
Register = 18   ReadRegValue = 0
Register = 19   ReadRegValue = 0
Register = 20   ReadRegValue = 0
Register = 21   ReadRegValue = 0
Register = 22   ReadRegValue = 0
Register = 23   ReadRegValue = 0
Register = 24   ReadRegValue = 0
Register = 25   ReadRegValue = 0
Register = 26   ReadRegValue = 0
Register = 27   ReadRegValue = 0
Register = 28   ReadRegValue = 0
Register = 29   ReadRegValue = 0
Register = 30   ReadRegValue = 0
Register = 31   ReadRegValue = 0
Register = 32   ReadRegValue = 0
Register = 33   ReadRegValue = 0
Register = 34   ReadRegValue = 0
Register = 35   ReadRegValue = 0
Register = 36   ReadRegValue = 0
Register = 37   ReadRegValue = 0
Register = 38   ReadRegValue = 0
Register = 39   ReadRegValue = 0
Register = 40   ReadRegValue = 0
Register = 41   ReadRegValue = 0
Register = 42   ReadRegValue = 0
Register = 43   ReadRegValue = 0
Register = 44   ReadRegValue = 0
Register = 45   ReadRegValue = 0
Register = 46   ReadRegValue = 0
Register = 47   ReadRegValue = 0
Register = 48   ReadRegValue = 0
Register = 49   ReadRegValue = 0
Register = 50   ReadRegValue = 0
Register = 51   ReadRegValue = 0
Register = 52   ReadRegValue = 0
Register = 53   ReadRegValue = 0
Register = 54   ReadRegValue = 0
Register = 55   ReadRegValue = 0
Register = 56   ReadRegValue = 0
Register = 57   ReadRegValue = 0
Register = 58   ReadRegValue = 1
Register = 59   ReadRegValue = 0
Register = 60   ReadRegValue = 244
Register = 61   ReadRegValue = 2
Register = 62   ReadRegValue = 0
Register = 63   ReadRegValue = 73
Register = 64   ReadRegValue = 84
Register = 65   ReadRegValue = 241
Register = 66   ReadRegValue = 208
Register = 67   ReadRegValue = 2
Register = 68   ReadRegValue = 113
Register = 69   ReadRegValue = 255
Register = 70   ReadRegValue = 96
Register = 71   ReadRegValue = 255
Register = 72   ReadRegValue = 253
Register = 73   ReadRegValue = 0
Register = 74   ReadRegValue = 0
Register = 75   ReadRegValue = 0
Register = 76   ReadRegValue = 0
Register = 77   ReadRegValue = 0
Register = 78   ReadRegValue = 0
Register = 79   ReadRegValue = 0
Register = 80   ReadRegValue = 0
Register = 81   ReadRegValue = 0
Register = 82   ReadRegValue = 0
Register = 83   ReadRegValue = 0
Register = 84   ReadRegValue = 0
Register = 85   ReadRegValue = 0
Register = 86   ReadRegValue = 0
Register = 87   ReadRegValue = 0
Register = 88   ReadRegValue = 0
Register = 89   ReadRegValue = 0
Register = 90   ReadRegValue = 0
Register = 91   ReadRegValue = 0
Register = 92   ReadRegValue = 0
Register = 93   ReadRegValue = 0
Register = 94   ReadRegValue = 0
Register = 95   ReadRegValue = 0
Register = 96   ReadRegValue = 0
Register = 97   ReadRegValue = 0
Register = 98   ReadRegValue = 0
Register = 99   ReadRegValue = 0
Register = 100   ReadRegValue = 0
Register = 101   ReadRegValue = 0
Register = 102   ReadRegValue = 0
Register = 103   ReadRegValue = 0
Register = 104   ReadRegValue = 0
Register = 105   ReadRegValue = 0
Register = 106   ReadRegValue = 0
Register = 107   ReadRegValue = 0
Register = 108   ReadRegValue = 0
Register = 109   ReadRegValue = 0
Register = 110   ReadRegValue = 3
Register = 111   ReadRegValue = 163
Register = 112   ReadRegValue = 0
Register = 113   ReadRegValue = 0
Register = 114   ReadRegValue = 0
Register = 115   ReadRegValue = 0
Register = 116   ReadRegValue = 0
Register = 117   ReadRegValue = 104
  • MPU6050から読み出したレジスタ値です。
レジスタ機能レジスタ値
#13 – #16診断時の値診断時の値による
#26DLPFの設定 設定値 = 0
#27角速度のフルスケール設定FS_SEL = 0, +/- 250°/sec
#28加速度のフルスケール設定AFS_SEL = 0, +/- 2g
#58割込み状況Data Ready interruptが発生した時に自動的に”1″
#59 – #64加速度測定値測定値による
#65 – #66温度測定値測定値による
#67 – #72角速度測定値測定値による
#110 – #111(仕様書に記載なし)(仕様書に記載なし)
#117I2CアドレスWHO_AM_I = 104 (0x68)

GY-521(MPU6050)の出力をシリアルプロッタで表示してみる

  • ArduinodでGY-521(3軸加速度、角速度センサ)の信号を取得し表示させる方法とGY-521に内蔵されているMPU6050のレジスタ値を読み込んだり設定する方法を学びました。学習した信号取得の方法やレジスタの設定の方法を活用して実際の測定値を調べます。
  • ArduinoとGY-521を接続し水平な台の上に置いて角速度のみ読み出します。出力をシリアルプロッタで確認します。
// GY-521/MPU-6050 角速度のみ表示させる

#include<Wire.h>
const int MPU_addr=0x68;  // I2C address of the MPU-6050
int16_t GyX,GyY,GyZ;

void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
}

void loop(){
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x43);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)

  Serial.print(GyX); Serial.print(","); 
  Serial.print(GyY); Serial.print(","); 
  Serial.println(GyZ);
}
— MPU6050の角速度値のシリアルプロッタ出力 —
  • 測定値の出力をTeratermで受信し、2000個のデータを使って平均値と標準偏差を測定しました。
  • X軸の角速度では、ゼロ点誤差が611.3、ドリフトが19.8になります。

GY-521のDLPF(デジタルローパスフィルター)を使ってみる

  • GY-521 (MPU6050)はDLPF(デジタルローパスフィルター)を内蔵しています。GY-521のDLPFの初期値は’0’に設定されていました。この設定を一番低周波の’6’に設定して、角速度の出力がどのように変化するか調べます。
  • GY-521は水平の台の上に置いて、傾斜動作させていないいない状態で出力の変化を読み出しています。
// MPU6050のDLPFを'6'に設定し角速度の測定値を表示させる

#include<Wire.h>
const int MPU_addr=0x68;  // I2C address of the MPU-6050
const int WR_MGMT_1_addr=0x6B;  // MPU-6050 PWR_MGMT_1 register
int ReadReg=0x1C;   // Register in MPU-6050
uint8_t ReadRegValue;     // Register Value
int16_t GyX,GyY,GyZ;

// Furntion to write a byte to a register
uint8_t MPU6050_WriteRegister_Byte (int MPUAdd, int Reg, uint8_t Value){

  Wire.beginTransmission(MPUAdd);
  Wire.write(Reg);  // Register for writing
  Wire.write(Value);  // Write value     
  Wire.endTransmission(true);
}

// Furntion to read a byte from a register
uint8_t MPU6050_ReadRegister_Byte (int MPUAdd, int Reg){

  uint8_t Value;

  Wire.beginTransmission(MPUAdd);
  Wire.write(Reg);  // starting with register ReadReg
  Wire.endTransmission(true);

  Wire.beginTransmission(MPUAdd);  
  Wire.requestFrom(MPUAdd,1,true);  // request a total of 1 register
  Value=Wire.read();  // Value of ReadReg    
  Wire.endTransmission(true);

  return  Value;
}

void setup(){
  Wire.begin();
  Serial.begin(9600);
  
  //Wakeup MPU-6050  
  Wire.beginTransmission(MPU_addr);
  Wire.write(WR_MGMT_1_addr);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);

  //MPU6050のレジスタ(26)を'6'に設定しDLPFの設定を変更する 
  MPU6050_WriteRegister_Byte (MPU_addr, 26 ,6);

}

void loop(){
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x43);  // starting with register 0x43 (GYRO_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)

  Serial.print(GyX); Serial.print(","); 
  Serial.print(GyY); Serial.print(","); 
  Serial.println(GyZ);
  
}
— MPU6050の角速度値のシリアルプロッタ出力 —
  • シリアルプロッタの波形からも高周波が減っており、DLPFの効果があることが解ります。
  • X軸の角速度では、ゼロ点誤差が612.1、ドリフトが2.7になります。
  • GY-521は水平の台の上に置いて、傾斜動作させていないいない状態で出力の変化を読み出していました。実際に傾斜動作させて効果を確認しました。測定値の高周波成分が除去されています。
— MPU6050の角速度値のシリアルプロッタ出力 —
  • 次に加速度を測定しました。角速度用スケッチを変更して加速度の測定値を出力させます。
  • 重力加速度はZ軸方向に大きく、X軸、Y軸、方向に小さく出力されています。
— MPU6050の加速度値のシリアルプロッタ出力 —
  • 角速度の測定と同様にGY-521を水平のDLPFを’6’に設定し角速度を測定しましたが、平均値と標準偏差共にDLPFを’0’の設定と比較して大きな変化はありませんでした。GY-521は水平の台の上に置いて、傾斜動作させていないいない状態で出力の変化を読み出しています。
  • 実際に傾斜動作させて測定しました。測定値の高周波成分が除去されています。
— MPU6050の加速度値のシリアルプロッタ出力 —
GY-521を傾斜させて傾斜角度を計算させる記事は?

公開されているライブラリ

  • MPU6050用にライブラリが公開されています。Arduino IDEを開いて、MPU6050で検索すると何種類ものライブラリが見つかります。自分で若しくは会社でプロジェクトを立ち上げたて必要なライブラリまで作っているのでしょう。ArduinoのHPに登録されているライブサリのサンプルコードには以下のようなコードがあり、3軸の加速度データと3軸の角速度データの合計6個を同時に取得できます。
 mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  • ライブラリを活用することで完結で解り易いコードが記述できます。

まとめ

GY‑521(MPU6050)の仕組みとデータの読出し方を学習しました。レジスタの値にアクセスする関数を作りデータの読出しやレジスタの設定を学習しました。出力される加速度と角速度の測定値は内部フィルタの設定を変えて取り出せます。公開されているライブラリを使うとより簡単に測定値にアクセスできることが解りました。この学習のおかげで自己バランスロボットが完成し、結果を[Arduinoで倒立振子を作りました – プログラミング]にまとめています。


ご質問、誤植の指摘などありましたら。「問い合わせ 」のページからお願いします。