Lesson 16 GY-521 Module
今回は、IMU(inertial measurement unit:慣性計測装置)センサーの接続。GY-521には、加速度センサーと、ジャイロ(角速度)センサーが入ってます。加速度/ジャイロセンサーは最近のスマホやゲーム機でも使われてますね。
Arduinoとの接続はI2C(Inter-Integrated Circuit)で行います。ELEGOO LessonではI2C初登場。2本の信号線、SDA(シリアルデータ)とSCL(シリアルクロック)を用いて通信します。
Arduinoがマスター、接続する機器がスレーブとなり、同じ信号線上に、複数のスレーブを接続することが可能です。
各スレーブ機器にはアドレスが割り当てられていて、これを指定することで、どの機器と通信するのかを選択できます。
なので、I2C機器を連結するためのハブは、単純に線がつながってるだけでいいんですね。
GROVE – I2Cハブ
(https://www.switch-science.com/catalog/796/)
GY-521 は、前後左右上下の「3軸」と、X軸回転、Y軸回転、Z軸回転の「3軸」で、合計6軸のデータを取得できます。いわゆる6DoFというやつです。
Arduinoとの接続は、VCC(3.3V) / GND / SDA / SCL の4本。SDA / SCL は、Arduinoボード上に2か所ありますが、どちらに繋いでも大丈夫でした。電源は3.3Vに繋ぎましたが、パーツ内部にレギュレータ搭載してて、入力 3~5V でOKです。
ライブラリは「MPU-6050」ライブラリを使用します。MPU-6050というのが、GY-521に搭載されているチップです。
M5Stack Gray / FIRE / M5GO に搭載されているのは、これにコンパス(磁気)センサーも付いた9軸のMPU-9250ってやつですね。
Lessonのスケッチはこちら。スケッチは「ライブラリのAPI呼び出し」の形式じゃなくて、MPU-6050ライブラリ内で行っている処理をスケッチ側にも実装してました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | // MPU-6050 Short Example Sketch //www.elegoo.com //2016.12.9 #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); } |
順番に見ていきます。
I2C通信のためにWire.hをinclude。
1 | #include<Wire.h> |
MPU-6050 のアドレスを 0x68 に設定。アドレスは基本的に機器ごとに決まっています。
1 | const int MPU_addr=0x68; // I2C address of the MPU-6050 |
setup() 内では、まずは I2C処理をスタート。
1 | Wire.begin(); |
送信処理を行う時は、beginTransmission ~ endTransmission で挟んで処理します。
beginTransmission の引数でアドレス指定。
endTransmission の引数で、コネクション維持を停止するかどうかの指定。(true で停止、falseで継続。この後に受信を継続する場合には、falseを指定。)
1 2 3 4 | 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 ); |
[0x6B]、[0] と順に送ることで、[0x6B] レジスタに [0] が書き込まれます。
これにより、動作に内部クロックを用いる設定でMPU-6050の動作開始します。
loop()内で、値の読出しを継続して行います。
1 2 3 | Wire.beginTransmission(MPU_addr); Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission( false ); |
レジスタアドレスを[0x3B]に設定します。この後、読出しを行うと、レジスタアドレス[0x3B]以降に格納されているデータを順に読み込みます。
データは、加速度センサー(3軸)、デバイス温度、ジャイロ(3軸)がそれぞれ2バイトずつ、合計14バイトで格納されています。
14バイト読み込みをリクエストして、
1 | Wire.requestFrom(MPU_addr,14, true ); // request a total of 14 registers |
そこから順番に2バイトずつで値を読み込み。
1 2 3 4 5 6 7 | 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) |
あとは読み込んだ値を表示するだけです。(温度は計算して表示してますね)
1 2 3 4 5 6 7 | 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); |
それでは実行!
センサー側の基板にもLED付いてました。
加速度、ジャイロデータは、生データ表示してるだけなのですが、実際に使うにはイロイロ計算必要になりそう。
MPU-6050ライブラリでは、そのへんの処理をあるていどやってくれる便利関数が用意されてるみたいです。このあたりは、MPU-6050ライブラリのexamples見てみるのがいいですね。
MPU-6050動作理解のために、こちらのページがとても参考になりました。
自作のいろいろ:Arduinoから MPU6050の値を取得してみる
https://garchiving.com/how-to-use-mpu6050-in-arduino/