3軸加速度センサーLIS3DHの使い方(I2C通信/SPI通信)

LIS3DH 加速度センサー センサー

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通信のどちらの通信方式にも対応しており、通信方式の切り替えはジャンパーの接続で行います。

LIS3DHモジュール写真

I2C通信でデータを読み取る

Raspberry Piの通信設定とPythonの操作方法

Raspberry PiのI2C通信とSPI通信設定を有効にします。
下の記事でRaspberry Piの通信設定とPythonの基本操作を説明しています。

モジュールとRaspberry Piの接続

接続図

ブレッドボードを使用したLIS3DHモジュールとRaspberryPiの接続【I2C】

接続写真

ブレッドボードを使用したLIS3DH【I2C通信】モジュールの接続写真 1
ブレッドボードを使用したLIS3DH【I2C通信】モジュールの接続写真 2

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)

プログラムの説明

プログラムの流れは以下の通りです。

  1. I2C通信の設定
  2. センサーの設定
  3. センサーから3軸加速度データを取得
  4. データを物理量に変換し画面に表示
  5. 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であることを確認出来ます。

.センサーの設定

#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 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軸加速度データ:0x280x29
Y軸加速度データ:0x2A0x2B
Z軸加速度データ;0x2C0x2D

LIS3DH 12ビットデータのアドレス

各軸の加速度データは12bitです。上位8bit、下位4bitで下位4bitは左詰めです。

12bitデータ左詰め

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シフトします。

16bitデータ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なので、これを利用すれば加速度計で角度の検出が可能です。

PythonのRunボタンとStopボタン
LIS3DHのプログラムの実行結果

LIS3DHの動作確認動画(1分45秒)の紹介です。
ExcelのVBAを使ってRaspberry PiとWiFi通信しています。

VBAからのコマンドをPythonプログラムで受信して測定データをVBAに返送します。VBAは受け取った測定データをExcelに波形表示します。

動画はこの記事のVBAプログラムを使っています

Excelのグラフをアニメーションで動かす方法を紹介しています。

以上、LIS3DHからI2C通信で加速度データを読み込んで画面に表示するサンプルプログラムでした。

SPI通信でデータを読み取る

モジュールとRaspberry Piの接続

接続図

ブレッドボードを使用したLIS3DHモジュールとRaspberryPiの接続【SPI】

接続写真

ブレッドボードを使用したLIS3DH【SPI通信】モジュールの接続写真 1
ブレッドボードを使用したLIS3DH【SPI通信】モジュールの接続写真 2

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

プログラムの説明

プログラムの流れは以下の通りです。

  1. SPI通信の初期設定
  2. センサーの設定
  3. センサーから3軸加速度データを取得
  4. データを物理量に変換し画面に表示
  5. 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は、出力データレート設定、フルスケールの変更、ローパワーモードなど、今回使っていない設定や機能がまだまだあります。興味があれば是非チャレンジしてください。

プログラミングやソフトウェアの記事です。

コメント

  1. 名無し より:

    質問なのですが、キャリブレーションはいらないのでしょうか?
    自分はラズベリーパイとか初心者で、あまり理解してないです。
    よろしくお願いします。

    • ワッホー ワッホー より:

      質問ありがとうございます。
      可能であればキャリブレーションをした方が良いかと思います。
      データシートの『Sensitivity』や『Typical zero-g level offset accuracy』の項目が Typ.表記であることなどが、キャリブレーションをした方が良いかとと思う理由です。
      ただし、要求される測定精度のレベルにもよりますし、それによってキャリブレーション方法も変わってくるかと思います。
      的外れな回答でしたらすみません。よろしくお願いします。