3軸加速度センサーLIS3DHから加速度データを読み取る方法を紹介します。
使用するマイコンはRaspberry Pi、プログラム言語はPythonです。
サンプルプログラムは、センサーからデータを読み取るだけでなく測定条件設定も行います。
また通信方式は、I2C通信とSPI通信の2種類を記載しています。
LIS3DHの主な仕様
測定範囲:±2g、±4g、±8g、±16g
分解能:1mg、2mg、4mg、12mg
温度特性:±0.01%/℃
零G時のオフセット:±40mg
通信方式:I2C通信/SPI通信
準備
LIS3DHの購入
LIS3DHはSOICと呼ばれる形状です。
人の手ではんだ付けするのは困難なのでモジュールの購入になると思います。
下の写真は秋月電子通商で購入したLIS3DHモジュールです。今回はこのモジュールを使った紹介になります。
I2C通信とSPI通信のどちらの通信方式にも対応しており、通信方式の切り替えはジャンパーの接続で行います。
I2C通信でデータを読み取る
Raspberry Piの通信設定とPythonの操作方法
Raspberry PiのI2C通信とSPI通信設定を有効にします。
下の記事でRaspberry Piの通信設定とPythonの基本操作を説明しています。
モジュールとRaspberry Piの接続
接続図
接続写真
I2C通信プログラミング
プログラムコード
Pythonのプログラムコードです。
import smbus
import time
#I2C設定
i2c = smbus.SMBus(1)
address = 0x18
#LIS3DH設定
i2c.write_byte_data(address, 0x20, 0x57)
i2c.write_byte_data(address, 0x23, 0x08)
#繰り返し
while True:
#データ読み込み
xl = i2c.read_byte_data(address, 0x28)
xh = i2c.read_byte_data(address, 0x29)
yl = i2c.read_byte_data(address, 0x2A)
yh = i2c.read_byte_data(address, 0x2B)
zl = i2c.read_byte_data(address, 0x2C)
zh = i2c.read_byte_data(address, 0x2D)
#データ変換
out_x = (xh << 8 | xl) >> 4
out_y = (yh << 8 | yl) >> 4
out_z = (zh << 8 | zl) >> 4
#極性判断
if out_x >= 2048:
out_x -= 4096
if out_y >= 2048:
out_y -= 4096
if out_z >= 2048:
out_z -= 4096
#物理量(加速度)に変換
out_x = out_x / 1024
out_y = out_y / 1024
out_z = out_z / 1024
#表示
print('X: ' + str(out_x))
print('Y: ' + str(out_y))
print('Z: ' + str(out_z))
#一時停止
time.sleep(1)
プログラムの説明
プログラムの流れは以下の通りです。
- I2C通信の設定
- センサーの設定
- センサーから3軸加速度データを取得
- データを物理量に変換し画面に表示
- 3.~4.を繰り返します
1.I2C通信の設定
#I2C設定
i2c = smbus.SMBus(1)
address = 0x18
i2c = smbus.SMBus(1)
インスタンス生成です。使用するBus1を指定します。
address = 0x18
アドレス指定です。LIS3DHのアドレスは0x18(16進数)で、通信時に指定します。
Raspberry PiにLIS3DHを接続した状態で、LXTerminalから「i2cdetect -y 1」コマンドを実行すると、アドレスが0x18であることを確認出来ます。
2.センサーの設定
#LIS3DH設定
i2c.write_byte_data(address, 0x20, 0x57)
i2c.write_byte_data(address, 0x23, 0x08)
設定は write_byte_data(adr, reg, dat)関数を使用します。
第1引数 adr:I2C通信のアドレス
第2引数 reg:レジスタ(設定したい項目の記憶場所)
第3引数 dat:データ(レジスタに設定する内容)
サンプルプログラムは、
・CTRL_REG1レジスタ
・CTRL_REG4レジスタ
上の2つのレジスタ設定をしています。レジスタの設定内容は以下の通りです。
i2c.write_byte_data(address, 0x20, 0x57)
0x20(CTRL_REG1レジスタ)
Xen(X軸の有効/無効)
Yen(Y軸の有効/無効)
Zen(Z軸の有効/無効)
Lpen(ローパワーモードの有効/無効)
ODR3-ODR0(出力データレート)
0x57
Xen(1:有効)
Yen(1:有効)
Zen(1:有効)
Lpen(0:ノーマルモード(デフォルト))
ODR3-ODR0(0101:100Hz)
データシートの『8.8 CTRL_REG1(20h)』で詳細を確認できます。
ODR3 | ODR2 | ODR1 | ODR0 | Lpen | Zen | Yen | Xen |
0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 |
5 | 7 |
i2c.write_byte_data(address, 0x23, 0x08)
0x23(CTRL_REG4レジスタ)
SIM(SPIモード 4wire/3wire)
ST1-ST0(セルフテストの有効/無効)
HR(高分解能出力モードの有効/無効)
FS1-FS0(フルスケール選択)
BLE(Big/Little endian data選択)
BDU(Block data update)
0x08
SIM(0:SPIモード 4wire(デフォルト))
ST1-ST0(00:セルフテスト無効(デフォルト))
HR(1:高分解能出力モード有効)
FS-1-FS0(00:±2G(デフォルト))
BLE(0:Data LSB(デフォルト))
BDU(0:continuous update(デフォルト))
データシートの『8.11 CTRL_REG4(23h)』で詳細を確認できます。
BDU | BLE | FS1 | FS0 | HR | ST1 | ST0 | SIM |
0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
0 | 8 |
3.センサーから3軸加速度データを取得
#データ読み込み
xl = i2c.read_byte_data(address, 0x28)
xh = i2c.read_byte_data(address, 0x29)
yl = i2c.read_byte_data(address, 0x2A)
yh = i2c.read_byte_data(address, 0x2B)
zl = i2c.read_byte_data(address, 0x2C)
zh = i2c.read_byte_data(address, 0x2D)
取得は read_byte_data(adr, reg)関数を使用します。
第1引数 adr:I2C通信のアドレス
第2引数 reg:レジスタ(測定データの記憶場所)
サンプルプログラムでは6つのレジスタからデータの取得をしています。
xl = i2c.read_byte_data(address, 0x28)
xh = i2c.read_byte_data(address, 0x29)
yl = i2c.read_byte_data(address, 0x2A)
yh = i2c.read_byte_data(address, 0x2B)
zl = i2c.read_byte_data(address, 0x2C)
zh = i2c.read_byte_data(address, 0x2D)
各軸の加速度データが格納されているレジスタアドレスは以下の通りです。
X軸加速度データ:0x28と0x29
Y軸加速度データ:0x2Aと0x2B
Z軸加速度データ;0x2Cと0x2D
各軸の加速度データは12bitです。上位8bit、下位4bitで下位4bitは左詰めです。
4.データを物理量に変換し画面に表示
#データ変換
out_x = (xh << 8 | xl) >> 4
out_y = (yh << 8 | yl) >> 4
out_z = (zh << 8 | zl) >> 4
out_x = (xh << 8 | xl) >> 4
16bitの入れ物に左詰めで12bitデータが入っているので、右に4bitシフトします。
#極性判断
if out_x >= 2048:
out_x = out_x - 4096
if out_y >= 2048:
out_y = out_y - 4096
if out_z >= 2048:
out_z = out_z - 4096
if(out_x >= 2048):
out_x = out_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 = out_x / 1024
out_y = out_y / 1024
out_z = out_z / 1024
out_x = out_x / 1024
加速度に変換するために1024で割ります。
#表示
print('X: ' + str(out_x))
print('Y: ' + str(out_y))
print('Z: ' + str(out_z))
print(‘X: ‘ + str(out_x))
X軸、Y軸、Z軸の加速度データを画面に表示します。
#一時停止
time.sleep(1)
time.sleep(1)
1秒間、一時停止します。
5.3.~4.を繰り返します
#繰り返し
while True:
while True:
Stopボタンが押されるまで繰り返します。
※この『while True:』は、13行目のwhile文です。
プログラムの実行結果
以下の手順でプログラムを実行します。
①Runボタンを押します。
②X軸、Y軸、Z軸の加速度データを1秒間隔で画面に表示します。
③Stopボタンを押すとプログラムを終了します。
センサーの設置を上の接続写真の様にした場合は、X軸とY軸の加速度データは 0g付近となり、Z軸の加速度は 1g付近となります。
ブレッドボードを90°傾けるとX軸もしくはY軸が1g付近になります。逆に傾けると-1gです。
重力加速度1gを検出しています。
90°で1gなので、これを利用すれば加速度計で角度の検出が可能です。
LIS3DHの動作確認動画(1分45秒)の紹介です。
ExcelのVBAを使ってRaspberry PiとWiFi通信しています。
VBAからのコマンドをPythonプログラムで受信して測定データをVBAに返送します。VBAは受け取った測定データをExcelに波形表示します。
動画はこの記事のVBAプログラムを使っています。
Excelのグラフをアニメーションで動かす方法を紹介しています。
以上、LIS3DHからI2C通信で加速度データを読み込んで画面に表示するサンプルプログラムでした。
SPI通信でデータを読み取る
モジュールとRaspberry Piの接続
接続図
接続写真
SPI通信プログラミング
プログラムコード
Pythonのプログラムコードです。
import spidev
import time
#SPI設定
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 10000
spi.mode = 3
s_dat = [0x00, 0x00]
x_dat = [0x00, 0x00, 0x00]
y_dat = [0x00, 0x00, 0x00]
z_dat = [0x00, 0x00, 0x00]
#LIS3DH設定
s_dat[0] = 0x20
s_dat[1] = 0x57
readByteArry = spi.xfer2(s_dat)
s_dat[0] = 0x23
s_dat[1] = 0x08
readByteArry = spi.xfer2(s_dat)
while True:
#読み込み設定
x_dat[0] = 0x28
x_dat[0] |= 0x80
x_dat[0] |= 0x40
y_dat[0] = 0x2A
y_dat[0] |= 0x80
y_dat[0] |= 0x40
z_dat[0] = 0x2C
z_dat[0] |= 0x80
z_dat[0] |= 0x40
#データ読み込み
readByteArry = spi.xfer2(x_dat)
readByteArry = spi.xfer2(y_dat)
readByteArry = spi.xfer2(z_dat)
#データ変換
out_x = ((x_dat[2] << 8) | x_dat[1]) >> 4
out_y = ((y_dat[2] << 8) | y_dat[1]) >> 4
out_z = ((z_dat[2] << 8) | z_dat[1]) >> 4
#極性判断
if out_x >= 2048:
out_x = out_x - 4096
if out_y >= 2048:
out_y = out_y - 4096
if out_z >= 2048:
out_z = out_z - 4096
#物理量(加速度)に変換
out_x = out_x / 1024
out_y = out_y / 1024
out_z = out_z / 1024
#表示
print('x: ' + str(out_x))
print('y: ' + str(out_y))
print('z: ' + str(out_z))
#一時停止
time.sleep(1)
spi.close
プログラムの説明
プログラムの流れは以下の通りです。
- SPI通信の初期設定
- センサーの設定
- センサーから3軸加速度データを取得
- データを物理量に変換し画面に表示
- 3.~4.を繰り返します
1.SPI通信の初期設定
#SPI設定
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 10000
spi.mode = 3
spi.open(0,0)
Bus0をチップセレクト0でオープンします。
spi.max_speed_hz = 100000
クロックのスピードを10kHzにします。
spi.mode = 3
SPI通信のハードウェア設定です。(mode 3は負論理の立下りエッジ検出)
SPI通信の詳しい説明はこちら
「シリアル・ペリフェラル・インタフェース」(2021年10月21日 (木) 02:31 UTCの版)『ウィキペディア日本語版』
2.センサーの設定
#LIS3DH設定
s_dat[0] = 0x20
s_dat[1] = 0x57
readByteArry = spi.xfer2(s_dat)
s_dat[0] = 0x23
s_dat[1] = 0x08
readByteArry = spi.xfer2(s_dat)
s_dat[0] = 0x20
CTRL_REG1レジスタを指定します。
s_dat[1] = 0x57
指定したレジスタの内容を設定します。
s_dat[0] = 0x23
CTRL_REG4レジスタを指定します。
s_dat[1] = 0x08
指定したレジスタの内容を設定します。
CTRL1レジスタとCTRL4レジスタは、I2C通信の2.センサーの設定に詳しい説明があります。
3.センサーから3軸加速度データを取得
#読み込み設定
x_dat[0] = 0x28
x_dat[0] |= 0x80
x_dat[0] |= 0x40
y_dat[0] = 0x2A
y_dat[0] |= 0x80
y_dat[0] |= 0x40
z_dat[0] = 0x2C
z_dat[0] |= 0x80
z_dat[0] |= 0x40
x_dat[0] = 0x28
y_dat[0] = 0x2A
z_day[0] = 0x2C
X軸、Y軸、Z軸の加速度データのレジスタアドレスを設定します。
共通:0x80
[読み込み/書き込み] を [読み込み]に設定します。
共通:0x04
読み込みを自動インクリメントに設定します。
レジスタアドレスは、I2C通信の3.センサーから3軸加速度データを取得に詳しい解説があります。
#データ読み込み
readByteArry = spi.xfer2(x_dat)
readByteArry = spi.xfer2(y_dat)
readByteArry = spi.xfer2(z_dat)
readByteArry = spi.xfer2(x_dat)
各軸の加速度データは12bitデータで、上位8bit、下位4bitです。下位4bitは左詰めです。
4.データを物理量に変換し画面に表示
(I2C通信の4.データを物理量に変換し画面に表示で詳しい解説をしています。)
#データ変換
out_x = ((x_dat[2] << 8) | x_dat[1]) >> 4
out_y = ((y_dat[2] << 8) | y_dat[1]) >> 4
out_z = ((z_dat[2] << 8) | z_dat[1]) >> 4
out_x = ((x_dat[2] << 8) | x_dat[1]) >> 4
16bitの入れ物に左詰めで12bitデータが入っているので、右に4bitシフトします。
#極性判断
if out_x >= 2048:
out_x = out_x - 4096
if out_y >= 2048:
out_y = out_y - 4096
if out_z >= 2048:
out_z = out_z - 4096
if(out_x >= 2048):
out_x = out_x – 4096
2の補数表現を符号ありに変換します。
#物理量(加速度)に変換
out_x = out_x / 1024
out_y = out_y / 1024
out_z = out_z / 1024
out_x = out_x / 1024
加速度に変換するために1024で割ります。
#表示
print('x: ' + str(out_x))
print('y: ' + str(out_y))
print('z: ' + str(out_z))
print(‘x: ‘ + str(out_x))
X軸、Y軸、Z軸の加速度を画面に表示します。
#一時停止
time.sleep(1)
time.sleep(1)
1秒間、一時停止します。
5.3.~4.を繰り返します
while True:
while True:
Stopボタンが押されるまで繰り返します。
※この『while True:』は、24行目のwhile文です。
プログラムの実行結果
プログラムの実行結果は、I2C通信時の実行結果と同じなので割愛します。
まとめ
LIS3DHモジュールからRaspberry Piにデータを読み込んで表示するサンプルでした。如何でしたでしょうか。
LIS3DHは、出力データレート設定、フルスケールの変更、ローパワーモードなど、今回使っていない設定や機能がまだまだあります。興味があれば是非チャレンジしてください。
プログラミングやソフトウェアの記事です。
コメント
質問なのですが、キャリブレーションはいらないのでしょうか?
自分はラズベリーパイとか初心者で、あまり理解してないです。
よろしくお願いします。
質問ありがとうございます。
可能であればキャリブレーションをした方が良いかと思います。
データシートの『Sensitivity』や『Typical zero-g level offset accuracy』の項目が Typ.表記であることなどが、キャリブレーションをした方が良いかとと思う理由です。
ただし、要求される測定精度のレベルにもよりますし、それによってキャリブレーション方法も変わってくるかと思います。
的外れな回答でしたらすみません。よろしくお願いします。
返信ありがとうございます。
返事が遅くなり申し訳ありません。
聞きたいことが聞けたので、助かりました。
ありがとうございます。
よかったです。