3軸加速度センサーMMA8452Qから加速度データを読み取る方法を紹介します。
使用するマイコンはRaspberry Pi、プログラム言語はPythonです。
サンプルプログラムは、センサーからデータを読み取るだけでなく測定条件設定も行います。
センサーの主な仕様
測定範囲:±2g、±4g、±8g
分解能:1/1024g、1/512g、1/256g
温度特性:±0.008%/℃
零G時のオフセット:±17mg
通信方式:I2C通信
その他の機能
プログラム可能な割り込み
自由落下やパルスの検出
自動ウェイクとスリープ状態に戻るための自動出力データレート変更
リアルタイムで利用可能なハイパスフィルターデータ
準備
MMA8452Qの購入
MMA8452Qは16端子のQFNと呼ばれる形状です。
センサーを手ではんだ付けするのは不可能なので、モジュールの購入になると思います。
下の写真は秋月電子通商で購入したMMA8452Qモジュールです。今回は、このモジュールを使ったサンプルプログラムを紹介します。
モジュールとRaspberry Piの接続
接続図
接続写真
Raspberry Piの通信設定とPythonの操作方法
Raspberry PiのI2C通信設定を有効にします。
下の記事でRaspberry Piの通信設定と、Pythonの基本操作を説明しています。
I2C通信プログラミング
プログラムコード
Pythonプログラムです。
import smbus
import time
#I2C設定
i2c = smbus.SMBus(1)
address = 0x1D
#センサーの設定
ret = i2c.write_byte_data(address, 0x0E, 0x00)
ret = i2c.write_byte_data(address, 0x2A, 0x01)
#繰り返し
while True:
#データ読み込み
dat = i2c.read_i2c_block_data(address, 0x01, 0x06)
#データ変換
dat_x = (dat[0] << 8 | dat[1]) >> 4
dat_y = (dat[2] << 8 | dat[3]) >> 4
dat_z = (dat[4] << 8 | dat[5]) >> 4
#極性判断
if dat_x >= 2048:
dat_x -= 4096
if dat_y >= 2048:
dat_y -= 4096
if dat_z >= 2048:
dat_z -= 4096
#物理量(加速度)に変換
out_x = dat_x / 1024.0
out_y = dat_y / 1024.0
out_z = dat_z / 1024.0
#表示
print('x: ' + str(out_x))
print('y: ' + str(out_y))
print('z: ' + str(out_z))
#一時停止
time.sleep(0.5)
※修正(2023.10.5)
①極性判断【>2048】から【>=2048】に修正
if dat_x > 2048: → if dat_x >= 2048:
if dat_y > 2048: → if dat_y >= 2048:
if dat_z > 2048: → if dat_z >= 2048:
②物理量(加速度)に変換【512.0】から【1024.0】に修正
out_x = dat_x / 512.0 → out_x = dat_x / 1024.0
out_y = dat_x / 512.0 → out_y = dat_x / 1024.0
out_z = dat_x / 512.0 → out_z = dat_x / 1024.0
プログラムの説明
プログラムの流れです。
- I2C通信の設定
- センサーの設定
- センサーから加速度データを取得
- データを物理量に変換し画面に表示
- 3.~4.を繰り返します
1.I2C通信の設定
#I2C設定
i2c = smbus.SMBus(1)
address = 0x1D
i2c = smbus.SMBus(1)
インスタンス生成です。使用するBus1を指定します。
address = 0x1D
アドレス指定です。MMA8452Qのアドレスは0x1D(16進数)で、通信時に指定します。
Raspberry PiにMMA8452Qを接続した状態で、LXTerminalから「i2cdetect -y 1」コマンドを入力すると、アドレスが0x1Dであることを確認出来ます。
2.センサーの設定
#センサーの設定
ret = i2c.write_byte_data(address, 0x0E, 0x00)
ret = i2c.write_byte_data(address, 0x2A, 0x01)
設定は write_byte_data(adr, reg, dat)関数を使用します。
第1引数 adr:I2C通信のアドレス
第2引数 reg:レジスタ(設定したい項目の記憶場所)
第3引数 dat:データ(レジスタに設定する内容)
サンプルプログラムは、
・XYZ_DATA_CFGレジスタ
・CTRL_REG1レジスタ
上の2つのレジスタ設定をしています。レジスタの設定内容は以下の通りです。
i2c.write_byte_data(address, 0x0E, 0x00)
0x0E(XYZ_DATA_CFGレジスタ)
FS1-FS0(フルスケールレンジ 2g/4g/8g)
HPF_OUT(ハイパスフィルタ出力 有効/無効)
0x00
FS1-FS0(00:2g(デフォルト))
HPF_OUT(0:無効(デフォルト))
※この設定は省略可能です。測定範囲を変更するときは0x00の値を変えます。
データシート『6.1 Data registers』の『0x0E: XYZ_DATA_CFG register』で、詳細を確認できます。
HPF_OUT | FS1 | FS0 | |||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 |
i2c.write_byte_data(address, 0x2A, 0x01)
0x2A(CTRL_REG1レジスタ)
ACTIVE(モード スタンバイ / アクティブ)
F_READ(モード ノーマル / ファスト)
LNOISE(モード ノーマル / ノイズ低減)
DR0-DR2(データレート)
ASLP_RATE0-ASLP_RATE1(自動ウェイクサンプル周波数)
0x01
ACTIVE(1:アクティブ)
F_READ(0:ノーマル (デフォルト))
LNOISE(0:ノーマル (デフォルト))
DR0-DR2(000:800Hz(デフォルト))
ASLP_RATE0-ASLP_RATE1(00:50Hz(デフォルト))
※電源投入後はスタンバイモードなので、初期設定後にアクティブモードにします。
データシート『6.7 Control registers』の『0x2A: CTRL_REG1 system control 1 register』で、詳細を確認できます。
ASLP_RATE1 | ASLP_RATE0 | DR2 | DR1 | DR0 | LNOISE | F_READ | ACTIVE |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
0 | 1 |
3.センサーから加速度データを取得
#データ読み込み
dat = i2c.read_i2c_block_data(address, 0x01, 0x06)
dat=i2c.read_i2c_block_data(address, 0x01, 0x06)
0x01:読み込みを開始するアドレス(X軸加速度データのMSB)
0x06:読み込むバイト数
データシート『6 Register Descriptions』の『Table 11. Register address map』で、詳細を確認できます。
4.データを物理量に変換しShellに表示
#データ変換
dat_x = (dat[0] << 8 | dat[1]) >> 4
dat_y = (dat[2] << 8 | dat[3]) >> 4
dat_z = (dat[4] << 8 | dat[5]) >> 4
dat_x = (dat[0] << 8 | dat[1]) >> 4
各軸の加速度データは、16bitの入れ物に左詰めで12bit分のデータが入っています。
これを右に4bitシフトします。
#極性判断
if dat_x >= 2048:
dat_x -= 4096
if dat_y >= 2048:
dat_y -= 4096
if dat_z >= 2048:
dat_z -= 4096
if dat_x >= 2048:
dat_x -= 4096
2の補数表現を符号ありに変換します。
12bitデータ | 符号なし | 符号あり |
100000000000 | 2048 | -2048 |
100000000001 | 2049 | -2047 |
: | : | : |
111111111110 | 4094 | -2 |
111111111111 | 4095 | -1 |
000000000000 | 0 | 0 |
000000000001 | 1 | 1 |
000000000010 | 2 | 2 |
: | : | : |
011111111110 | 2046 | 2046 |
011111111111 | 2047 | 2047 |
2の補数の詳しい説明はこちら
「2の補数」(2021年10月12日 (火) 17:00 UTCの版)『ウィキペディア日本語版』
#物理量(加速度)に変換
out_x = dat_x / 1024.0
out_y = dat_y / 1024.0
out_z = dat_z / 1024.0
out_x = dat_x / 1024.0
測定範囲±2gで分解能が4096です。1024で割って物理量に変換します。
#表示
print('X: ' + str(out_x))
print('Y: ' + str(out_y))
print('Z: ' + str(out_z))
print(‘X: ‘ + str(out_x))
X軸、Y軸、Z軸の加速度を画面に表示します。
5.3.~4.を繰り返します
#繰り返し
while True:
while True:
Stopボタンが押されるまで繰り返します。
※この『while True:』は、13行目のwhile文です。
プログラムの実行結果
プログラムを実行します。
①Runボタンを押します
② X軸、Y軸、Z軸の加速度データを1秒間隔で画面に表示します。
③Stopボタンを押すとプログラムを終了します
センサーの設置を、上記『モジュールとRaspberry Piの接続』の『接続写真』の様にした場合は、X軸、Y軸ともにほぼ0g付近となり、Z軸は1g付近となります。
ブレッドボードを90°傾けるとX軸もしくはY軸が1g付近になります。
逆に傾けると-1gです。
これは重力加速度1gを検出しています。
90°で1gなので、これを利用すれば加速度計でも角度の検出が可能です。
以上、MMA8452QからI2C通信で加速度データを読み込んで画面に表示するサンプルでした。
まとめ
3軸加速度センサーMMA8452Qのサンプルプログラムと、その動作について紹介しました。
如何でしたでしょうか。
データシートを見ると、沢山の設定項目があったり、低消費電力化のためにモードの切替が出来たりします。まだまだこのセンサーで試せることがいっぱいあります。
加速度センサーは、測りたい事象を捉えるためのサンプリング周波数が重要で、Raspberry PiのPythonで、どこまでの周波数の測定ができるか確認するのも面白いかと思います。
プログラミングやソフトウェアの記事です。
コメント
z軸が1.98となり1g(9.8m/s^2)と同値になりません。なぜでしょうか?
もちろん水平面かつこのプログラム通りで何度も読み直しても間違いはありません
横山様
問い合わせありがとうございます。
X軸とY軸は正常な値を示していますでしょうか?
横山様
連投ですみません。
プログラムを確認したところ加速度へ変換する計算で512で除算していますが、±2gで4096分解能なので1Gは1024分解能であり、1024で除算する必要がありました。
現状のプログラムではX軸もY軸も倍の2g付近の結果となると思います。
記事は修正しておきます。混乱させてすみません。
ご回答ありがとうございます。
x軸,y軸に関しては0付近の値を示していました。
ご指摘の通り1024で除算をした値を見てみると、z軸は”0.98….”との値を示しました。ありがとうございます。
(この質問とは関係ないのですが、極性判断のコード部分で「dat_x < 2048」は不等号は「≦」が適切かと思われます。)
全体を通して非常に参考になりました。改めてありがとうございます!
横山様
新たな間違いの指摘もしていただきすごく助かります。
ありがとうございます。
こちらも修正しておきます。