obnizでMPU9250モジュール(MPU6500, AK8963内蔵)を使ってみた(1:基本編)

今回はobnizで加速度センサ，ジャイロセンサ，磁気センサを全て内蔵したMPU9250を使ってみたので忘備録とobnizの宣伝を兼ねて記事書いてみた．

#obnizとは
今回は通信するのに以下に挙げる[obniz](https://obniz.io/ja/)というマイコンボードを用いました．
obnizっていうマイコンボードは

- htmlとjava scriptでプログラムを書けるので，ブラウザで操作コンソールなどを自分で作れる
- ブロックプログラムを作れるプラットフォームを完備，しかもブロックプログラムで書いたプログラムをhtmlにコンバート出来る！！(ここ重要)
- ESP-WROOM-32搭載なので，Wifi経由で書き込みでき，どこからでも調整可能！
- モータードライバ無しでモーター駆動可能，OLED搭載でデバックしやすい，どのIOピンでも大体の機能をアサイン可能

など，初めてマイコンを触る人やWeb系の人がIoTを手軽に始められる便利なツールです．詳しい説明はAmazonの説明欄分かりやすいから見て．
[obniz - 現実をソフトウェア化する](https://www.amazon.co.jp/obniz-%E3%82%AA%E3%83%96%E3%83%8A%E3%82%A4%E3%82%BA-%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%81%AB%E3%81%A4%E3%81%AA%E3%81%8C%E3%81%A3%E3%81%9FEaaS%E9%96%8B%E7%99%BA%E3%83%9C%E3%83%BC%E3%83%89-%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%81%AE%E6%B0%B8%E4%B9%85%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E4%BB%98%E3%81%8D/dp/B07DD6FK8G/ref=sr_1_3?adgrpid=57063038767&gclid=CjwKCAjw8e7mBRBsEiwAPVxxiDOwkOtweQulBiYw1slUyPDxzAufn_OtXqQGepYo9PhAIRBRw73CIBoCZzgQAvD_BwE&hvadid=338570288792&hvdev=c&hvlocphy=1009310&hvnetw=g&hvpos=1t1&hvqmt=e&hvrand=14126131591264252139&hvtargid=kwd-457296702181&hydadcr=27302_11561686&jp-ad-ap=0&keywords=obniz&qid=1557972592&s=gateway&sr=8-3)
イメージ的にはこんな感じ．

**Atmelマイコンを使いやすくしたArduino ⇔ ESP-WROOM-32を使いやすくしたobniz**

個人的にはブロックプログラムが優秀なのでArduinoより使いやすいし，htmlコンバートしてからの詳細編集によってより発展的で複雑な内容にも移行しやすいと思ってます．
(あとESPコマンドめんどいのをobnizで楽に書けるってのも利点かも)

#MPU9250とは
###特徴
適当にstrawberry linuxからデータシートを取ってくる．このページが全てまとまってて分かりやすい．感謝．
https://strawberry-linux.com/support/12250/1703893
加速度センサ，ジャイロセンサのMPU6500と，磁気センサAK8963を内蔵した徹底的に角度，傾きを測るモジュールです．本体は実装チップだけど，モジュールが色んな形で売ってるのでそれ買うのが楽でいいと思います．
通信もアドレスなどを自分で調べて書かないといけない，設定もレジスタを読んでデータを書き込まないといけない，などとまあまあ難しいので説明をちょっと細かめに書いていきたいと思います．

#ハードの設定
今回の通信はI2Cでやりました(楽なんで)．
I2Cって何？って人は[このサイト](http://memes.sakura.ne.jp/memes/?page_id=1791)が分かりやすい．
高速通信したい人とかはSPI使えばいいんじゃないですかね．暇だったら今度使って載せます．
ただ，高速SPI(10MHz～25MHz以上)は，ノイズの関係できちんとした実装基板以外ではやめといた方が良いとかいう噂を聞いたことがあるので気を付けて．
I2Cは簡単．SCLとSDAというピンをMPU9250，obnizそれぞれの同じ名前のところに繋ぐだけ(Arduinoも同じ)．
obnizはどのIOピンにもI2Cを設定出来るので以下の様に書けばどのピンでもI2Cが出来ます．(今回は2ピン：SDA，3ピン：SCL)

```js:obniz_I2C.html
      var i2c = obniz.getFreeI2C();     //get I2C address
      i2c.start({ mode: "master", sda: 2, scl: 3, clock: 100000, pull: "3v" }); //I2C start
```
MPU9250は5Vトレラントではないため，通信のピンは3Vでプルアップしておきます．
またobnizから電源供給する場合は，5Vを出力してレギュレータで3.3Vに落として使いましょう．obnizの仕様です(威圧)．

(追記：接続図せっかくあったのに上げ忘れました．大変申し訳ない)
![MPU9250配線図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246335/4a00502f-56d6-7de3-da4f-d9814c597811.jpeg)

###アドレスへの通信
ジャイロなどのデータは，かなーり低レイヤーのデータ処理を行わないとなので適当に解説．
bit, byte, hexの話は説明する気ないので，もしこの後の話分からないようなら[これとか読んでね](https://www.uquest.co.jp/embedded/learning/lecture01.html)．

MPU9250のチップの中にはレジスタマップという下の様な表が広がっています．
![registor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246335/683165ca-435b-f954-340b-5e0fbbd4e8ea.png)

アドレスは中の住所を表しています．
また，MPU9250にはobnizとI2C通信するために0x68というアドレスが振られてます．これはほかにもI2C機器を接続していた時に見分ける為です．
これによって上の図で言うと
0x68(MPU9250)にアクセス→0x6B(電源設定)にアクセス→設定を書きこみ/データを読み取り
という流れでセットしたい部分にアクセスできます．
書き込み方は0x80だと7bit目のみ1になるので，例えば今言った電源設定ではリセットがかかります．ちなみに0x00を書き込むとMPU9250が起動します．
このようにして0と1を書き込んで自分の使いたい機能をON/OFFします．
obnizでは以下のように書いて今言った事を実現します．

```js:obniz_I2C_write.html
i2c.write(0x68, [0x6B, 0x00]);    //activate MPU9250
```

他にもレジスタには機能があるのでもっと知りたい人は[どうぞ](https://strawberry-linux.com/pub/RM-MPU-9250A-00.pdf)．

#加速度を読む
それでは基本編．
まずは加速度を読んでいきましょう．
MPU6500の加速度のアドレスにアクセス(0x68→0x3B)して14バイトのデータを読みます．こうすることで0x3Bのアドレス以降にある
0~5 byte:加速度x,y,z軸
6,7 byte:チップ温度
8~13byte:ジャイロx,y,z軸
のデータが一気に読めて楽です．
2バイトのデータは読むときは1バイトずつ読むので，その後1つに連結する処理が必要です．そこでビットシフトやOR演算子という手段を使います．分からない人は[詳しい話](http://www9.plala.or.jp/sgwr-t/c/sec14.html)をチェック．
実際のプログラムは下みたいな感じで，これを全ての2バイトデータに適用すればいいだけです．

```js:MPU9250_I2.html
var A_raw = new Int16Array(3);  //accel x, y, z raw data
Ax_raw[0] = (data[0] << 8) | data[1];
```
出したデータは
16bit(2byte) = -32,768‬~32,767
なのでこれを加速度のレンジ-16G~16Gに直します．

```js:MPU9250_accel_range
Accel[i] = A_raw[i] * 16 / 32768;       //divide 16bit(±32768) & multiply ±16G
```


#プログラム
Obnizは[オンラインエディタ](https://obniz.io/ja/program?obniz_id_reset=1)があるので，そこに以下のコードをコピー．
もしVS codeで書きたい人は以下をチェック．
[VS Codeで簡単にJava Script, HTMLの統合開発環境を作ってみた(obnizに応用してみた)](https://qiita.com/k_zoo/items/49f39de232037de5036b)
実行すると画面に加速度の値が出ます．
重力加速度があるので，該当の軸を下に向ければ1Gになるのが確認できるはずです．
次回は加速度以外の値(磁気，ジャイロ等)の設定したり，値を安定させるためにフィルタ処理したりします．
ではまた．

```html:obniz_MPU9250.html
<html>

<head>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
	<script src="https://unpkg.com/obniz@2.0.2/obniz.js"></script>
</head>

<body>
	<div id="obniz-debug"></div>

	<script>
		//define
		var A_raw = new Int16Array(3);  //accel x, y, z raw data
		var Accel = new Array(3);       //accel x, y, z vaule

		var obniz = new Obniz("ID"); //obniz ID here
		//if obniz connect
		obniz.onconnect = async function () {
			//setup
			obniz.io0.output(false);          //IO0 use as GND
			obniz.io1.output(true);           //IO1 use as VCC
			await obniz.wait(20);             //wait for oscillation stabilize & power supply (not necessary)
			var i2c = obniz.getFreeI2C();     //get I2C address
			i2c.start({ mode: "master", sda: 2, scl: 3, clock: 100000, pull: "3v" }); //I2C start
			i2c.write(0x68, [0x6B, 0x00]);    //activate MPU9250
			i2c.write(0x68, [0x1C, 0x18]);    //accel range set (0x00:2g, 0x08:4g, 0x10:8g, 0x18:16g)
			//loop
			obniz.repeat(async function () {  //repeat every 100msec (Callback)
				i2c.write(0x68, [0x3B]);        //access MPU6050 data
				var data = await i2c.readWait(0x68, 14);//read 14byte
				//Accel value calc
				for (var i = 0; i < 3; i++) {
					A_raw[i] = (data[2 * i] << 8) | data[2 * i + 1];
					Accel[i] = A_raw[i] * 16 / 32768;       //divide 16bit(±32768) & multiply ±16G
				}
				//print to browzer
				document.write("Accel =", Accel[0].toFixed(2).fontcolor("red"), ' ', Accel[1].toFixed(2).fontcolor("blue"), ' ', Accel[2].toFixed(2).fontcolor("fuchsia"), "<br>");
				window.scroll(0, $(document).height()); //auto scroll (x,y)
			}, 100);
		};
	</script>

</body>

</html>
```