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通信のどちらの通信方式でも使用可能です。今回はこのモジュールを使ってデータを読み込む方法を紹介します。
Raspberry Piの通信設定とPythonの操作方法
Raspberry PiのI2C通信とSPI通信設定を有効にします。
下の記事でRaspberry PiのSPI通信設定と、Pythonの基本操作を説明しています。
I2C通信でデータを取得する
モジュールとRaspberry Piの接続
接続図
接続写真
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)
プログラムの説明
プログラムの流れは以下の通りです。
- I2C通信の設定
- センサーの設定
- センサーから3軸加速度データを取得
- データを物理量に変換し画面に表示
- 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)
0x32~0x37は、データが格納されているレジスタアドレスです。
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のデータにします。
#極性判断
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なので、これを利用すれば加速度計で角度検出が可能です。
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
プログラムの説明
プログラムの流れは以下の通りです。
- SPI通信の設定
- センサーの設定
- センサーから3軸加速度データを取得
- データを物理量に変換し画面に表示
- 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通信でデータを読み込んで表示するサンプルでした。如何でしたでしょうか。
初めのうちはなかなか動かないと思いますが、頑張っていきましょう。
プログラミングやソフトウェアの記事です。
コメント