Raspberry Pi 3で、9軸センサ(BMX055)の値を取得する方法があまり見当たらなかったので、まとめてみました。
(2019/10/20) 誤り修正、参考リンク追加
環境
- Raspberry Pi Model 3+
- ubuntu mate
- 秋月電子のBMX055使用9軸センサーモジュール
センサのはんだづけ
ジャンパの設定とピンヘッダを取り付けるため、はんだづけをします。
- JP1~3 : 私の環境では各センサのアドレスを変更する必要がなかったため、どれもショートしませんでした。
- JP4~5 : ラズパイは、内部でプルアップもしくはプルダウンされているようなので必要なさそうです。
以下の記事を参考にしました。
Raspberry PiのGPIOは起動直後から内部プルダウンされている
ラズパイゼロのプルアップ抵抗を調べる - JP6~8 : GPIOは3.3Vであるため
JP7
をショートします。
ラズパイでI2Cを使う設定
この内容は他にも多くの方が記事を書いているので、詳しくは書きません。
I2Cインタフェースの有効化
$ sudo raspy-config
表示された画面で、3 Interfacing Options
-> P4 I2C
と選択したら、
Would you like the ARM I2C interface to be enabled?
と尋ねられるので、
yes
を選択し終了します。
その後、再起動します。
再起動後、以下のコマンドを入力しi2c_bcm2708``i2c_dev
があることを確認します。
$ lsmod
...
i2c_bcm2708
...
i2c_dev
...
ライブラリ、ツールのインストール
$ sudo apt-get update
$ sudo apt-get install i2c-tools python-smbus libi2c-dev
回路の作成
私はセンサの電源に5Vを使うことにしたため、以下のように接続しました。
電源を3.3Vにする場合はもう1本、線を追加する必要があると思います(未確認)。
左側がラズパイのGPIOピン、右がセンサです。
GPIO 1 (5V) -> VCC
GPIO 3 (SDA) -> SDA
GPIO 5 (SCL) -> SCL
GPIO 9 (GLD) -> GLD
軸の向き
動作確認
i2cdetect
コマンドで確認します。コマンドの詳細はこちらです。
$ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- 13 -- -- -- -- -- 19 -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- 69 -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
加速度、ジャイロ、磁気のアドレスはそれぞれ、0x19、0x69、0x13なので(※)正しく認識できています。
(※ジャンパピンの設定で変わります)
値の取得
ツールによる取得
どのアドレスにアクセスしたら何のデータが取得できるか、はBOSCHが公開しているBMX055のデータシートを見ればわかるのですが、
慣れていないとなかなか読み解くのが難しいです。簡単にですが説明します。
例えばz方向の加速度であれば、以下のように取得します。
加速度の値は12bitであり、レジスタアドレス0x06と0x07に分割して格納されています。
0x06の4~7bit目に加速度の下位4bitが、0x07に上位8bitが格納されています。
そのため、0x07の値と、0x06の4~7bit目の値を組み合わせる必要があります。
また、0x06には、0bit目には新しいデータかどうかを示すフラグが格納されています。
加速度の値は12bitですが、符号付き整数なので先頭の1bitは正負の符号です。
よって値域は -2048~2047 となります。
先頭bitが1のとき、2の補数を計算して負数にしてもいいのですが、
値が2048以上の場合は4096を引いて負の値に変換するほうが簡単です。
ここまでで求めた値はまだ物理値ではありません。
例えば、ここまでで求めた値が1であったからといって、加速度は1[m/s]ではありません。
レジスタアドレス0x0Fには値のレンジ設定が格納されており、デフォルト値は0x03なので
取得できる値のレンジは+/- 2gでLSBは0.00098[g]です。
つまり、レジスタから読み取った値が1であったとすると、それは0.00098[g]を意味するため、0.00098をかける必要があります。
また、[m/s^2]で使いたいなら、さらに9.8をかける必要があります。
i2cget
コマンドでセンサの値を取得し、物理値に変換してみます。
$ sudo i2cget -y 1 0x19 0x06
0x91
$ sudo i2cget -y 1 0x19 0x07
0x40
0x06の値は0x91なので、0bit目は1なので新しいデータであることがわかります。
0x06の4~7bit目と0x07の値を組み合わせると加速度の値は
0x409 = 0d1033
1033 x 0.00098 = 1.01234 [g] = 9.920932 [m/s^2]
となります。
なお、取得する加速度のレンジや周期など、様々なパラメータが変更できます。
詳しくはBMX055のデータシートを見てください。
python プログラム
python3で加速度を取得するプログラムです。
smbusのapiはこちらから参照できます。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import smbus
import time
ACC_ADDRESS = 0x19
ACC_REGISTER_ADDRESS = 0x02
def bmx055():
# initialize
i2c = smbus.SMBus(1)
## 指定したレジスタアドレスから、2byte分取得する
x_lsb = i2c.read_byte_data(ACC_ADDRESS, ACC_REGISTER_ADDRESS)
x_msb = i2c.read_byte_data(ACC_ADDRESS, ACC_REGISTER_ADDRESS+1)
y_lsb = i2c.read_byte_data(ACC_ADDRESS, ACC_REGISTER_ADDRESS+2)
y_msb = i2c.read_byte_data(ACC_ADDRESS, ACC_REGISTER_ADDRESS+3)
z_lsb = i2c.read_byte_data(ACC_ADDRESS, ACC_REGISTER_ADDRESS+4)
z_msb = i2c.read_byte_data(ACC_ADDRESS, ACC_REGISTER_ADDRESS+5)
x_value = (x_msb * 16) + ((x_lsb & 0xF0) / 16)
x_value = x_value if x_value < 2048 else x_value - 4096
y_value = (y_msb * 16) + ((y_lsb & 0xF0) / 16)
y_value = y_value if y_value < 2048 else y_value - 4096
z_value = (z_msb * 16) + ((z_lsb & 0xF0) / 16)
z_value = z_value if z_value < 2048 else z_value - 4096
x_acc = x_value * 0.00098
y_acc = y_value * 0.00098
z_acc = z_value * 0.00098
print ("[%f, %f, %f]" % (x_acc, y_acc, z_acc))
i2c.close()
if __name__ == '__main__':
bmx055()
参考
python以外のサンプルがこちらにありました。
こちらのGithubには、他のセンサのサンプルコードもあるようです。