前2回のデータシートの読み込み(その1、その2)でMPU9250モーションセンサモジュールの加速度センサ部分の理解が多少深まったので、実際にプログラムを書いて実験してみたいと思います。以前と違うのは、タイマを使ってなるべく正確なインターバル時間で計測するようにした点とADコンバータの出力値をそのまま記録するようにしたことです。実験は「静止」と「落下」。実際に取れた加速度センサの出力データを見てみたいと思います。こんなに簡単に落下実験などできるのは自立しているM5Stackならではかもしれません。
※「IoT何をいまさら」投稿順Indexはこちら
まずは、タイマを使ってなるべく正確なインターバル時間で生のADC出力を測定するためのプログラムの改造。
#include <Ticker.h> ~途中略~ void recData() { if (recOK) { String dataString = String(millis()); dataString += ","; if (measureIMU()) { dataString += String(IMU.accelCount[0]); dataString += String(","); dataString += String(IMU.accelCount[1]); dataString += String(","); dataString += String(IMU.accelCount[2]); } else { dataString += "N/A"; } f.println(dataString); } } ~途中略~ measurement.attach_ms(10, recData);
Tiker.hをインクルードすることで使用できる attach_ms()関数を使用してみることにいたしました。第1の引数にミリ秒単位のインターバルを設定し、第2の引数にコールバック関数を与えます。すると指定したインターバルでコールバック関数を呼び出してくれるという仕組みです。今回、コールバック関数の中で、recOKというフラグが立っているとき、加速度センサのデルタ・シグマADコンバータの出力値を読みだしてSDカードに書き込むようにしてみました。その際、
millis()
という組み込み関数でシステム内蔵の1ミリ秒単位のタイマ値を読みだしてこれも記録しています。内蔵のRTOS側の「都合」でattach_ms()関数の呼び出しが乱れた場合にも、測定時刻が分かるようにするためです。実際には、今回9.5秒ほどの期間を10ms毎に測定してみたのですが、
-
- 1回を除き、millis()読み出しの結果とTickerの読み出しインターバルは一致した
- 1回だけ17msと長いインターバルの後Call back、3msでまたCall backというケースがあった
という結果になりました。稀に上の2のようにズレるので、millis()見てインターバルを計算すべきでしょうが、今回のような設定下でTickerでインターバルを制御するのは問題なさそうです。ただ、今回は、WiFiのような優先度が高そうなモジュールを組み込んでいないです。リアルタイム処理がバンバン走るような状況下では、Tickerによるインターバルはかなりばらつく可能性があるのではないかとも思いました。
次に念のため MPU9250.cpp内のinitMPU9250()関数での加速度センサの初期化についてソースを再確認しました。
Register 28 – Accelerometer Configuration
2つあるコンフィギュレーションレジスタの最初の方は、フルスケール±2Gで設定されています。
Register 29 – Accelerometer Configuration 2
第2のコンフィギュレーションレジスタは、ACCEL_FCHOICEビットは0(LPFは効かせない)ですが、A_DLPF_CFGフィールドには3(バンド幅41Hz)を書き込んでいます。MPU-9250 Register Map and Descriptions Revision 1.4を読む限り、ACCEL_FCHOICEビットが0のときA_DLPF_CFGフィールドに値を書いても意味ない(バンド幅は1.13kHz)筈なのですが、仔細は分かりません。ただ、後ほどご覧いただく加速度センサの出力値からはバンド幅が41Hzに制限されているようには見えない、と申し上げておきます。
静止状態
それではまず「静止」のときの生データを御覧いただきましょう。LCD画面を上に向けて平らな机の上に置いて測定したものです。x軸はミリ秒単位のmillis()関数の出力値そのままで、Y軸はADCの出力値(16ビット符号付き整数)です。
3軸とも期待どおりほぼ平らなグラフになっていますが、先頭と末尾に異常値が観測されています。測定開始、停止を制御するのに、スイッチを押すようになっているので、この影響かもしれません。安定している区間ということで、7000ミリ秒から8000ミリ秒までの区間を軸毎に拡大してみました。
X軸(画面左右方向)
X軸のこの範囲の平均は-1696(1G=16384設定)、そこを基準に上は+76、下は-108の範囲でデータがばらついています。前回、データシートからの1.13kHz帯域時の入力ノイズは140くらいばらつくという計算であったので、その範囲であるように思われます。
Y軸(画面上下方向)
Y軸のこの範囲の平均は22、そこを基準に上は+106、下は-82の範囲でデータがばらついています。ここもバラツキという点では予想通りかと思います。
Z軸(画面に対して直交する高さ方向)
Z軸のこの範囲の平均は14691、そこを基準に上は+129、下は-127の範囲でデータがばらついています。この軸はほぼ重力加速度のベクトルと一致(=16384)する筈ですが大分小さめです。X軸、Y軸の値を加味しても小さめ。だたし、バラツキという点では予想通りかと思います。
落下
次にM5Stackを自由落下させた場合です。目の前から足元のクッションの上になるべく回転しないように落としたのですが、実際には、Y方向に半回転くらいしてナナメになって止まりました。その様子がこちら。
13100ミリ秒付近から13500ミリ秒付近の3軸とも小さな値でほぼ平に見えている辺り約430ミリ秒区間が落下部分でしょう。その後、クッションの上で何度かバウンドしています。その部分の拡大グラフがこちら。
フルスケールは、-32768から+32767なので、クッションへの着地とはいえ、インパクトの瞬間には振り切れていることが分かります。その後、時間はかかっていますが、2回ほどの揺れで落ち着いているのはクッション性のためかと思います。
まあ、データシート読んで予想できたような波形ではあります。しかし、生のADC出力から加速度の絶対値を求めると10%くらいは小さかったり、大きかったりする感じ。ちゃんとキャリブレーションを経た計算をすれば良いのかな?