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

ADXL345 加速度センサー センサー

3軸加速度センサーADXL345から加速度データを読み取る方法を紹介します。

使用するマイコンはRaspberry Pi、プログラム言語はPythonです。

サンプルプログラムは、センサーからデータを読み取るだけでなく測定条件設定も行います。
また通信方式は、I2C通信とSPI通信の2種類を記載しています。

ADXL345の主な仕様
測定範囲:±2g、±4g、±8g、±16g
分解能:3.9mg/LSB

ADXL345の特長
超消費電力
タップ/ダブルタップの検出
自由落下の検出
耐衝撃性10000g

準備

ADXL345の購入

ADXL345は14端子のLGAと呼ばれる形状です。
センサーを手ではんだ付けするのは不可能なのでモジュールの購入になると思います。

下の写真は秋月電子通商で購入したADXL345モジュールです。 I2C通信とSPI通信のどちらの通信方式でも使用可能です。今回はこのモジュールを使ってデータを読み込む方法を紹介します。

ADXL345 モジュール写真

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

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

I2C通信でデータを取得する

モジュールとRaspberry Piの接続

接続図

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

接続写真

ブレッドボードを使用したADXL345の接続写真 1
ブレッドボードを使用したADXL345の接続写真 2

I2C通信プログラミング

プログラムコード

Pythonプログラムです。

import smbus
import time

#I2C設定
i2c = smbus.SMBus(1)
address = 0x53

#センサーの設定
ret = i2c.write_byte_data(address, 0x2C, 0x0B)
ret = i2c.write_byte_data(address, 0x31, 0x09)
ret = i2c.write_byte_data(address, 0x2D, 0x08)

while True:
    
    #データ読み込み
    xl = i2c.read_byte_data(address, 0x32)
    xh = i2c.read_byte_data(address, 0x33)
    yl = i2c.read_byte_data(address, 0x34)
    yh = i2c.read_byte_data(address, 0x35)
    zl = i2c.read_byte_data(address, 0x36)
    zh = i2c.read_byte_data(address, 0x37)
    
    #データ変換
    out_x = xh << 8 | xl
    out_y = yh << 8 | yl
    out_z = zh << 8 | zl
    
    #極性判断
    if out_x >= 32768:
        out_x = out_x - 65536
    
    if out_y >= 32768:
        out_y = out_y - 65536
    
    if out_z >= 32768:
        out_z = out_z - 65536
    
    #物理量(加速度)に変換
    out_x = out_x * 0.004
    out_y = out_y * 0.004
    out_z = out_z * 0.004
    
    #表示
    print('X: ' + str(out_x))
    print('Y: ' + str(out_y))
    print('Z: ' + str(out_z))
    
    #一時停止
    time.sleep(0.5)

プログラムの説明

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

  1. I2C通信の設定
  2. センサーの設定
  3. センサーから3軸加速度データを取得
  4. データを物理量に変換し画面に表示
  5. 3.~4.を繰り返します

1.I2C通信の設定

#I2C設定
i2c = smbus.SMBus(1)
address = 0x53

i2c = smbus.SMBus(1)
インスタンス生成です。使用するBus1を指定します。

address = 0x53
アドレス指定です。モジュールのSDO/ADDRESSピンをGNDへ接続して0x53になります。
通信時にこのアドレスを指定します。

Raspberry PiにADXL345を接続した状態で、LXTerminalから「i2cdetect -y 1」コマンドを入力すると、アドレスが0x53であることを確認出来ます。

2.センサーの設定

#センサーの設定
ret = i2c.write_byte_data(address, 0x2C, 0x0B)
ret = i2c.write_byte_data(address, 0x31, 0x09)
ret = i2c.write_byte_data(address, 0x2D, 0x08)

設定は write_byte_data(adr, reg, dat)関数を使用します。

第1引数 adr:I2C通信のアドレス
第2引数 reg:レジスタ(設定したい項目の記憶場所)
第3引数 dat :データ(レジスタに設定する内容)

サンプルプログラムは、
・BW_RATEレジスタ
・DATA_FORMATレジスタ
・POWER_CTLレジスタ
上の3つのレジスタ設定をしています。レジスタの設定内容は以下の通りです。

i2c.write_byte_data(address, 0x2C, 0x0B)

0x2C(BW_RATEレジスタ)
D4(低消費電力動作)
D3-D0(帯域幅と出力データレート)

0x0B
D4(0:通常動作(デフォルト))
D3-D0(1100:帯域幅200Hz、データ出力レート400Hz)

データシートの『レジスタ 0x2C-BW_RATE(読み出し/書き込み)』に、より詳しい情報があります。

D7 D6 D5 D4 D3 D2 D1 D0
LOW_POWER Rate
0 0 0 0 1 1 0 0
0 B

i2c.write_byte_data(address, 0x31, 0x09)

0x31(DATA_FORMATレジスタ)
D7(セルフテスト 有効/無効)
D6(SPIモード 3線式/4線式)
D5(割り込み アクティブハイ/ロー)
D3(最大分解能モード)
D2(左寄せ右寄せモード)
D1-D0(gレンジ)

0x09
D7(0:無効(デフォルト))
D6(0:4線式(デフォルト))
D5(0:アクティブハイ(デフォルト))
D3(1:最大分解能)
D2(0:右寄せ(デフォルト))
D1-D0(01:±4g)

データシートの『レジスタ 0x31 – DATA_FORMAT(読み出し/書き込み)』に、よりで詳しい情報があります。

D7 D6 D5 D4 D3 D2 D1 D0
SELF_TEST SPI INT_INVERT FULL_RES Justify Range
0 0 0 0 1 0 0 1
0 9

i2c.write_byte_data(address, 0x2D, 0x08)

0x2D(POWER_CTLレジスタ)
D5(リンクモード)
D4(自動スリープ機能 有効/無効)
D3(スタンバイモード/測定モード)
D2(スリープモード)
D1-D0(データ読み出し周波数)

0x08
D5(0:インアクティブ、アクティブ同時動作(デフォルト))
D4(0:自動スリープ無効(デフォルト))
D3(1:測定モード)
D2(0:通常動作モード(デフォルト))
D1-D0(00:8Hz(デフォルト))

データシートの『レジスタ 0x2D – POWER_CTL(読み出し/書き込み)』に、より詳しい情報があります。

D7 D6 D5 D4 D3 D2 D1 D0
    Link AUTO_SLEEP Measure Sleep Wakeup
0 0 0 0 1 0 0 0
0 8

3.センサーから3軸加速度データを取得

#データ読み込み
xl = i2c.read_byte_data(address, 0x32)
xh = i2c.read_byte_data(address, 0x33)
yl = i2c.read_byte_data(address, 0x34)
yh = i2c.read_byte_data(address, 0x35)
zl = i2c.read_byte_data(address, 0x36)
zh = i2c.read_byte_data(address, 0x37)

取得は read_byte_data(adr, reg)関数を使用します。

第1引数 adr:I2C通信のアドレス
第2引数 reg:レジスタ(測定データの記憶場所)

サンプルプログラムは、6つのレジスタからデータを取得しています。

xl = i2c.read_byte_data(address, 0x32)
xh = i2c.read_byte_data(address, 0x33)
yl = i2c.read_byte_data(address, 0x34)
yh = i2c.read_byte_data(address, 0x35)
zl = i2c.read_byte_data(address, 0x36)
zh = i2c.read_byte_data(address, 0x37)

0x320x37は、データが格納されているレジスタアドレスです。

Address Name Type Reset Value Description
0x32 DATAX0 Read 00000000 X-Axis DATA0
0x33 DATAX1 Read 00000000 X-Axis DATA1
0x34 DATAY0 Read 00000000 Y-Axis DATA0
0x35 DATAY1 Read 00000000 Y-Axis DATA1
0x36 DATAZ0 Read 00000000 Z-Axis DATA0
0x37 DATAZ1 Read 00000000 Z-Axis DATA1

4.データを物理量に変換し画面に表示します

#データ変換
out_x = xh << 8 | xl
out_y = yh << 8 | yl
out_z = zh << 8 | zl

out_x = xh << 8 | xl
out_y = yh << 8 | yl
out_z = zh << 8 | zl

上位のデータを左に8bitシフトして、下位8ビットとorで16bitのデータにします。

16bitデータ
#極性判断
if out_x >= 32768:
    out_x = out_x - 65536
    
if out_y >= 32768:
    out_y = out_y - 65536
    
if out_z >= 32768:
    out_z = out_z - 65536

if(out_x >= 32768):
out_x = out_x – 65536

2の補数表現を符号ありに変換します。

16bitデータ 符号なし 符号あり
1000000000000000 32768 -32768
1000000000000001 32769 -32767
1111111111111110 65534 -2
1111111111111111 65535 -1
0000000000000000 0 0
0000000000000001 1 1
0000000000000010 2 2
0111111111111110 32766 32766
0111111111111111 32767 32767

2の補数の詳しい説明はこちら
2の補数」(2021年10月12日 (火) 17:00 UTCの版)『ウィキペディア日本語版』

#物理量(加速度)に変換
out_x = out_x * 0.004
out_y = out_y * 0.004
out_z = out_z * 0.004

out_x = out_x * 0.004
最大分解能は、4mg/LSBです。0.004を掛けて加速度に変換します。

#表示
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ボタンを押します。
②3軸加速度データを0.5秒間隔で画面に表示します。
③Stopボタンを押すとプログラムは終了します。

センサーの設置を、上記『モジュールとRaspberry Piの接続』の『接続写真』の様にした場合は、X軸、Y軸ともにほぼ0g付近となり、Z軸は1g付近となります。

ブレッドボードを90°傾けるとX軸もしくはY軸が1g付近になります。
逆に傾けると-1gです。
重力加速度1gを検出しています。

90°で1gなので、これを利用すれば加速度計で角度検出が可能です。

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

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

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

以上、ADXL345からI2C通信で加速度データを読み込んで表示するサンプルでした。

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

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

SPI通信でデータを取得する

モジュールとRaspberry Piの接続

接続図

接続写真

SPI通信プログラミング

プログラムコード

Pythonプログラムです。

import spidev
import time

#SPI初期設定
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 100000
spi.mode = 3

s_dat = [0x00, 0x00]
x_dat = [0x00, 0x00, 0x00]
y_dat = [0x00, 0x00, 0x00]
z_dat = [0x00, 0x00, 0x00]

#ADXL345初期設定
s_dat[0] = 0x2C
s_dat[1] = 0x0B
readByteArry = spi.xfer2(s_dat)

s_dat[0] = 0x31
s_dat[1] = 0x09
readByteArry = spi.xfer2(s_dat)

s_dat[0] = 0x2D
s_dat[1] = 0x08
readByteArry = spi.xfer2(s_dat)

#繰り返し
while True:
    
    #設定
    x_dat[0] = 0x32
    x_dat[0] |= 0x80
    x_dat[0] |= 0x40
    
    y_dat[0] = 0x34
    y_dat[0] |= 0x80
    y_dat[0] |= 0x40
    
    z_dat[0] = 0x36
    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]
    out_y = y_dat[2] << 8 | y_dat[1]
    out_z = z_dat[2] << 8 | z_dat[1]
    
    #極性判断
    if out_x >= 32768:
        out_x = out_x - 65536
    
    if out_y >= 32768:
        out_y = out_y - 65536
    
    if out_z >= 32768:
        out_z = out_z - 65536
    
    #物理量(加速度)に変換
    out_x = out_x * 0.004
    out_y = out_y * 0.004
    out_z = out_z * 0.004
    
    #表示
    print('X: ' + str(out_x))
    print('Y: ' + str(out_y))
    print('Z: ' + str(out_z))
    
    #一時停止
    time.sleep(0.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 = 100000
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.センサーの設定

#ADXL345設定
s_dat[0] = 0x2C
s_dat[1] = 0x0B
readByteArry = spi.xfer2(s_dat)

s_dat[0] = 0x31
s_dat[1] = 0x09
readByteArry = spi.xfer2(s_dat)

s_dat[0] = 0x2D
s_dat[1] = 0x08
readByteArry = spi.xfer2(s_dat)

BW_RATEレジスタ
s_dat[0] = 0x2C:レジスタ指定
s_dat[1] = 0x0B:レジスタの内容

DATA_FORMATレジスタ
s_dat[0] = 0x31:レジスタ指定
s_dat[1] = 0x09:レジスタの内容

POWER_CTLレジスタ
s_dat[0] = 0x2D:レジスタ指定
s_dat[1] = 0x08:レジスタの内容

BW_RATE、DATA_FORMAT、POWER_CTLレジスタは、I2C通信の2.センサーの設定に詳しい説明があります。

3.センサーから3軸加速度データを取得

#設定
x_dat[0] = 0x32
x_dat[0] |= 0x80
x_dat[0] |= 0x40

y_dat[0] = 0x34
y_dat[0] |= 0x80
y_dat[0] |= 0x40

z_dat[0] = 0x36
z_dat[0] |= 0x80
z_dat[0] |= 0x40

#データ読み込み
readByteArry = spi.xfer2(x_dat)
readByteArry = spi.xfer2(y_dat)
readByteArry = spi.xfer2(z_dat)

X軸:0x32
Y軸:0x34
Z軸:0x36
X軸、Y軸、Z軸の加速度データを読み込むためのアドレス設定です。

共通:0x80
[読み込み/書き込み] を [読み込み]に設定します。

共通:0x04
読み込みを自動インクリメントに設定します。

アドレス設定については、I2C通信の3.センサーから3軸加速度データを取得に詳しい解説があります。

4.データを物理量に変換し画面に表示

(I2C通信の4.データを物理量に変換し画面に表示で詳しい解説をしています。)

#データ変換
out_x = x_dat[2] << 8 | x_dat[1]
out_y = y_dat[2] << 8 | y_dat[1]
out_z = z_dat[2] << 8 | z_dat[1]

上位のデータを左に8bitシフトして、下位8ビットとorで16bitのデータにします。

#極性判断
if out_x >= 32768:
    out_x = out_x - 65536
    
if out_y >= 32768:
    out_y = out_y - 65536
    
if out_z >= 32768:
    out_z = out_z - 65536

2の補数表現を符号ありに変換します。

#物理量(加速度)に変換
out_x = out_x * 0.004
out_y = out_y * 0.004
out_z = out_z * 0.004

最大分解能は、4mg/LSBです。0.004を掛けて加速度に変換します。

#表示
print('X: ' + str(out_x))
print('Y: ' + str(out_y))
print('Z: ' + str(out_z))

X軸、Y軸、Z軸の加速度を画面に表示します。

5.3.~4.を繰り返します

#繰り返し
while True:

while True:
Stopボタンが押されるまで繰り返します。

※この『while True:』は、29行目のwhile文です。

プログラムの実行結果

プログラムの実行結果は、I2C通信時の実行結果と同じなので割愛します。

まとめ

ADXL345モジュールからRaspberry PiにI2C通信とSPI通信でデータを読み込んで表示するサンプルでした。如何でしたでしょうか。

初めのうちはなかなか動かないと思いますが、頑張っていきましょう。

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

コメント