どーでも日記

工作の備忘録や映画の感想を書いてきます

【Arduino】六軸センサMPU-6050の設定方法

前回の記事でまったく理解できていなかったarduinoにおけるセンサの設定方法について理解が進んだのでまとめておく.マイコンをよく使っている人からすると当たり前のことを書いている気がする.

 

・基本スケッチ

I2C通信にはwireライブラリ使う.以下,前回の記事のスケッチから,センサからのデータをarduinoで取得する部分までを抜粋した.このスケッチをもとに解説していく.

#include <Wire.h>

int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, temperature;

void setup() {
  Serial.begin(9600);  //転送速度を9600bpsに設定
  Wire.begin();
  TWBR = 12;

  Wire.beginTransmission(0x68);
  Wire.write(0x6B);
  Wire.write(0x00);
  Wire.endTransmission();

  //Gyro初期設定
  Wire.beginTransmission(0x68);
  Wire.write(0x1C);
  Wire.write(0x10);
  Wire.endTransmission();

  //加速度センサー初期設定
  Wire.beginTransmission(0x68);
  Wire.write(0x1B);
  Wire.write(0x08);
  Wire.endTransmission();

  //LPF設定
  Wire.beginTransmission(0x68);
  Wire.write(0x1A);
  Wire.write(0x05);
  Wire.endTransmission();
  
}


void loop() {
  Wire.beginTransmission(0x68);
  Wire.write(0x3B);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 14);
  while (Wire.available() < 14);
  axRaw = Wire.read() << 8 | Wire.read();
  ayRaw = Wire.read() << 8 | Wire.read();
  azRaw = Wire.read() << 8 | Wire.read();
  temperature = Wire.read() << 8 | Wire.read();
  gxRaw = Wire.read() << 8 | Wire.read();
  gyRaw = Wire.read() << 8 | Wire.read();
  gzRaw = Wire.read() << 8 | Wire.read();

}

  

・初期設定

まず,setupの中身から

Wire.begin();

Wireを開始する.今回はarduino側がI2C通信におけるmastarなので引数は省略.slave側とする場合は7bitの引数を入れると,それがslave側のアドレスとなる.

TWBR = 12;

いきなりで申し訳ないが不明.わかり次第追記する.

 

Wire.beginTransmission(0x68);

0x68というアドレスのslaveデバイスと通信を開始する.MPU-6050のアドレスはデフォルトで0x68である.(MPU-6050レジスタマップ資料p.45参照) 指定するアドレスは16進数,10進数,2進数のどれでもok.

 

Wire.write(0x1B);

Wire.write(0x00);

引数に入っている数値を送る.arduino側からはMPU-6050に数値を送っているだけであるが,MPU-6050側では

最初のWire.write(0x1B)でレジスタアドレスを0x6Bに指定,

二つ目のWire.write(0x00)でレジスタアドレス0x6Bの8bitのレジスタに0x00格納する作業を行っている.(と思われる.あくまで自分の理解)

f:id:dodemo_yoshi:20190302132103p:plain

↑アドレス0x6Bのレジスタ0~7bitに0x00を格納する.つまり,すべて0になる.

MPU-6050レジスタマップ資料p.40によると,0~2bitのCLKSELに数値を格納することで内部クロックを設定する.とりあえず,ここに0を格納すると,I2C通信がスタートするらしい.

 

Wire.endTransmission();

この関数をもってはじめてMPU-6050にWire.beginTransmission(0x68),Wire.write(0x1B),Wire.write(0x00)の内容を送信する.

 

ここまででI2C通信の設定が完了である.とはいっても内部クロックしか設定していないが...

 

//Gyro初期設定
  Wire.beginTransmission(0x68);
  Wire.write(0x1C);
  Wire.write(0x10);
  Wire.endTransmission();

次のかたまりではGyro(角加速度)のデータ取得に関する初期設定(レンジの設定)を行っている.

先ほどと同じ流れで上から,

・0x68というアドレスのslaveデバイス(MPU-6050)と通信を開始する.

・引数に入っている数値を送る.最初のWire.write(0x1C)でレジスタアドレスを0x1Cに指定,二つ目のWire.write(0x10)でレジスタアドレス0x1Cの8bitのレジスタに0x10格納する.0x1Cのアドレスは,角加速度計測に関する数値を格納しているレジスタを示している.(MPU-6050レジスタマップ資料p.15参照)アドレス0x1CのレジスタのBit4に1を格納し,そのほかのBitには0を格納する.

 

その後は同様のやり方で加速度センサとLPF(ローパスフィルタ)の初期設定を行っている.

後は資料を読んで好みの設定にしていこう.

 

・データの取得

センサで計測されたデータは,センサ内のレジスタに一旦格納される.そのデータを指定してarduinoで受け取る必要がある.

 

改めてloopの中身

void loop() {
  Wire.beginTransmission(0x68);
  Wire.write(0x3B);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 14);
  while (Wire.available() < 14);
  axRaw = Wire.read() << 8 | Wire.read();
  ayRaw = Wire.read() << 8 | Wire.read();
  azRaw = Wire.read() << 8 | Wire.read();
  temperature = Wire.read() << 8 | Wire.read();
  gxRaw = Wire.read() << 8 | Wire.read();
  gyRaw = Wire.read() << 8 | Wire.read();
  gzRaw = Wire.read() << 8 | Wire.read();

}

 

Wire.beginTransmission(0x68);

初期設定と同じで0x68というアドレスのslaveデバイス(MPU-6050)と通信を開始す.

Wire.write(0x3B);

レジスタアドレスを0x3Bに指定.

Wire.endTransmission();

レジスタアドレスを指定だけして送信. 

 

Wire.requestFrom(0x68, 14);

0x3Bのレジスタから14byteのレジスタには加速度,温度,角加速度のデータが格納されている.この関数でMPU-6050のアドレス0x3B(Wire.write(0x3B);で指定済み)のレジスタから以下14byteのデータを要求する.

 

while (Wire.available() < 14);

取得できる(readで読める)データが14より小さければ次のプログラムを行う.無くてもいい?

axRaw = Wire.read() << 8 | Wire.read();

x軸加速度を取得し,変数(axRaw)に格納する.

最初のWire.read()によってWire.requestFromで要求したデータの最初の1byte(指定したアドレス0x3Bに格納されたデータ)を読み込む.この8bitはビットシフトすることでaxRawの上位8bit(15~8bit)に格納.

二回目のWire.read()で先ほど読み込んだデータの次の1byte(アドレス0x3Cのデータを読み込む.この8bitはaxRawの下位8bit(7~0bit)に格納する.

 

Wire.read()について

1Byteずつデータを読み込む関数.Wire.read()で任意のアドレスのデータを読みこんだ後,もう一度Wire.read()を使うと,その前に読み込んだデータの次のアドレスのデータ(1Byte)となる.つまり,Wire.write()でアドレスを指定しないかぎり,Wire.read()で読み込まれるデータのアドレスは関数を使うたびに移動する.

 

この後はayRaw, azRaw, gxRaw, gyRaw, gzRaw, temperatureもそれぞれ同様にデータを取得する.

 

あとはSerial.print()などで表示するなり,計算に使うなどすればよい.

 

 

参考:https://qiita.com/MergeCells/items/20c3c1a0adfb222a19cd

↑I2C通信のmasterとslaveの関係などをわかりやすく書かれている