Featured image of post Arduino UNO Qでモーションセンサーを使ってみた

Arduino UNO Qでモーションセンサーを使ってみた

はじめに

前回、Arduino App LabのBrickを使ってLEDの点灯状態をブラウザにリアルタイム表示する実験を行いました。
今回は手持ちの6軸慣性センサー MPU6050(GY-521モジュール) をUNO Qに接続し、姿勢角をWebUI上にリアルタイム表示することに挑戦してみます。

今回接続するMPU6050(GY-521モジュール)

全体の処理分担と構成方針は以下のようにシンプルにしました。

  • MCU側(sketch):MPU6050から生データを読み取り、姿勢角(roll / pitch / yaw)まで計算する
  • Python側(Linux側):Bridge経由でその計算結果を受け取り、WebUI(Socket.IO)へ配信する

100Hz程度の等間隔サンプリングが必須となる積分処理を、Linux側のスケジューラによる揺れから切り離したかったのが主な理由です。

ハードウェア構成

GY-521モジュール(MPU6050搭載)をUNO Qに接続します。

MPU6050UNO Q備考
VCC3V3UNO QのGPIOは5Vトレラントではないため3.3Vを供給
GNDGND
SDAA4 (SDA)※実はD20が正解(詳細は後述)
SCLA5 (SCL)※実はD21が正解(詳細は後述)
AD0GND または未接続未接続でも内部プルダウンによりI2Cアドレスは 0x68

MPU6050の設定パラメータは、DLPF 44Hz、±250dps、±2g といった標準的な値にしています。加速度センサから算出した絶対角と、ジャイロセンサの積分値を相補フィルタ(α=0.98)でブレンドして roll / pitch を求めました。なお、yawに関しては地磁気センサがないためジャイロ積分のみ(ドリフトを含む相対値)としています。

MPU6050のスケッチライブラリの追加

スケッチを書く前にArduinoのMPU6050のライブラリをインストールします。すでに有名なセンサーであれば便利なライブラリが揃っており、Arduino App Labでも利用できます。

Arduino App LabのAdd Sketch Libraryのアイコンをクリックするとライブラリのリストが表示されます。今回はAdafruit MPU6050を使用しました。

Sketch Librariesの画面

ライブラリが追加されるとSketch Librariesに表示されます。

Sketch Librariesの画面

I2Cが繋がらない

配線を済ませてsketchを書き込み、生値を読んでみたところLOGでは加速度もジャイロもすべて0しか返ってきていません。

[4:57:08 PM] WHO_AM_I=0xFF  acc=(0.0, 0.0, 0.0)  gyr=(0.0, 0.0, 0.0)
[4:57:06 PM] WHO_AM_I=0xFF  acc=(0.0, 0.0, 0.0)  gyr=(0.0, 0.0, 0.0)
[4:57:03 PM] WHO_AM_I=0xFF  acc=(0.0, 0.0, 0.0)  gyr=(0.0, 0.0, 0.0)

ここから原因究明のための切り分け作業を行いました。

  1. GY-521モジュールの電源LEDは点灯している → 電源供給は正常
  2. テスターによるI2Cラインの導通確認 → 配線・接触自体には問題なし
  3. Uno Qのピンアウトを見直したところ、D20/D21に別のI2Cポート(I2C2)の記載があったため、配線をD20/D21コネクタ側へ差し替えたところ、無事にセンサーの値が返ってきました。
[5:01:16 PM] WHO_AM_I=0x68  acc=(0.213, -0.409, 9.977)  gyr=(-2.908, 0.802, -0.191)
[5:01:10 PM] WHO_AM_I=0x68  acc=(0.186, -0.427, 9.972)  gyr=(-3.0, 0.779, -0.145)
[5:01:05 PM] キャリブレーション完了 (bias gx=-2.78 gy=0.748 gz=-0.17 deg/s)
[5:01:04 PM] キャリブレーション開始… 基板を静止させてください
[5:01:01 PM] 接続しました。UNO Q を静止させてからキャリブレーションしてください。

UNO QではA4/A5(I2C3)とD20/D21(I2C2)とQwiic(I2C4)はそれぞれ独立したI2Cインターフェースです。I2Cが認識されないときは、従来のArduino感覚でA4/A5を使うのではなく、もう一つのSDA/SCL(数字の付いていないピン)に接続して確認してみてください。

I2Cで通信できるようになったArduino Uno QとMPU6050

Bridge APIの設計

MCUとPython(Linux)間の通信は、メソッド名やデータ型を厳密に固定して設計しました。ここが1文字でも異なると、例外エラーも出ずに無言で通信が失敗してしまうため注意が必要です。

MCU → Python(push)

メソッド名引数説明
imu_dataroll, pitch, yaw, temp (float×4)20Hz周期で姿勢角と温度をpush

Python → MCU(call)

メソッド名引数戻り値
imu_calibratesamples: intJSON文字列でバイアス値を返却
imu_reset_yawdummy: intJSON文字列 {"ok":true}
imu_read_rawdummy: intJSON文字列で生値を返却

戻り値をJSON文字列にまとめているのは、App LabのBridge内部で使われているmsgpack-RPCの仕様上、戻り値として単一の値しか返せない制約があるためです。

WebUI表示

WebUI-HTML Brickを使用し、Socket.IO経由で10Hz程度に間引いてブラウザへbroadcast配信しました。画面上にroll/pitch/yawの数値をバー表示するだけでなく、渡すデータがすべて明確な数値型や真偽値になるよう徹底しています(前回のBlink実験で「文字列と真偽値の型不一致」にハマった反省を活かしました)。

完成したWebUI

CSSだけで3D表示

Three.jsなどのリッチな外部ライブラリは使わず、CSSの perspectiverotateX/Y/Z だけで「板が傾く」簡易3D表示を実装してみました。

CSS部分は以下のようになります。

.scene3d {
  perspective: 700px;
}
.board3d {
  transform-style: preserve-3d;
  transition: transform 0.08s linear;
}

JS部分は以下のようになります。

board.style.transform =
  `rotateZ(${d.roll}deg) rotateX(${-d.pitch}deg) rotateY(${d.yaw}deg)`;

これだけのコードですが、MPU6050モジュールを手で傾けると、WebUI画面内の板が連動してリアルタイムに同じ方向へ傾いてくれます。CSSの3Dトランスフォームだけでここまで手軽に視覚化できるのは、嬉しい発見でした。

まとめ

  • MPU6050(GY-521)自体のI2C制御や相補フィルタ計算は定番の手法で問題なく動作し、Arduino IDEでおなじみのライブラリもスケッチで利用できました。
  • 今回最大のハードルは、UNO QのI2Cピン配置が従来のArduinoシールド配置(A4/A5)とは異なっていたことでした。
  • Bridge経由でPython側にデバック情報を中継し、WebUIに表示することで、デバッグをスムーズに行うことができました。
  • Bridge APIを定義する際は、メソッド名と型をあらかじめ仕様書として固めておくことで手戻りを防げます。
  • CSSの3Dトランスフォームで、センサデータの表示を立体的に表現できました。

今回のスケッチおよびPythonスクリプト一式は、GitHubリポジトリ に公開しています。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。