3軸デジタル出力ジャイロセンサーL3GDHから角速度データを読み取る方法を紹介します。
使用するマイコンはRaspberry Pi、プログラム言語はPythonで、I2C通信とSPI通信の2種類の通信方式について解説していきます。
サンプルプログラムでは、センサーからデータを読み取るだけでなく測定条件設定も行っています。
また、ExcelのVBAを使って、Raspberry PiとWifi接続してリアルタイムにグラフ表示する動画も紹介しています。
L3GD20Hの主な仕様
測定範囲:±245dps、±500dps、±2000dps
感度:8.75mdps/digit、17.5mdps/digit、70.0mdps/digit
非直線性:±0.2%FS
感度の温度特性:±2%/℃
零の温度特性:±0.04dps/℃
L3GD20Hは温度測定もできます(温度は8bitデータ)。
準備
L3GD20Hの購入
L3GD20Hは16端子のLGAと呼ばれる形状です。
センサーを手ではんだ付けするのは不可能なのでモジュールの購入になると思います。
下の写真は秋月電子通商で購入したL3G20Hモジュールで、今回はこのモジュールを使います。
I2C通信とSPI通信のどちらの通信方式にも対応しており、通信方式の切り替えは指定端子を電源またはGNDに接続します。
Raspberry Piの通信設定とPythonの操作方法
Raspberry PiのI2C通信とSPI通信設定を有効にします。
下の記事でRaspberry PiのI2C通信設定とSPI通信設定、Pythonの基本操作を説明しています。
I2C通信でデータを取得する
モジュールとRaspberry Piの接続
接続図
接続写真
I2C通信プログラミング
プログラムコード
Pythonのプログラムコードです。
import smbus
import time
#I2C設定
i2c = smbus.SMBus(1)
address = 0x6a
#L3GD20H設定
ret = i2c.write_byte_data(address, 0x20, 0x0F)
ret = i2c.write_byte_data(address, 0x23, 0x20)
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
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.07
out_y = out_y * 0.07
out_z = out_z * 0.07
#表示
print('X: ' + str(out_x))
print('Y: ' + str(out_y))
print('Z: ' + str(out_z))
#一時停止
time.sleep(1)
プログラムの説明
プログラムの流れは以下の通りです。
- I2C通信の設定
- センサーの設定
- センサーから角速度データを取得
- データを物理量に変換し画面に表示
- 3.~4.を繰り返す
1.I2C通信の設定
#I2C設定
i2c = smbus.SMBus(1)
address = 0x6a
i2c = smbus.SMBus(1)
インスタンス生成です。使用するBus1を指定します。
address = 0x6a
アドレス指定です。モジュールの4番ピンをGNDに接続すると0x6a(16進数)で、電源に接続すると0x6bになります。通信時にこのアドレスを指定します。
Raspberry PiのLXTerminalから「i2cdetect -y 1」コマンドで、0x6aもしくは0x6bであることを確認出来ます。
2.センサーの設定
#L3GD20H設定
ret = i2c.write_byte_data(address, 0x20, 0x0F)
ret = i2c.write_byte_data(address, 0x23, 0x20)
設定は write_byte_data(adr, reg, dat)関数を使用します。
第1引数 adr:I2C通信のアドレス
第2引数 reg:レジスタ(設定したい項目の記憶場所)
第3引数 dat:データ(レジスタに設定する内容)
サンプルプログラムでは2つのレジスタを設定します。
・CTRL1レジスタ
・CTRL4レジスタ
レジスタの設定内容は以下の通りです。
i2c.write_byte_data(address, 0x20, 0x0F)
0x20(CTRL1レジスタ)
Xen(X軸の有効/無効)
Yen(Y軸の有効/無効)
Zen(Z軸の有効/無効)
PD(パワーモード)
BW1-BW0(帯域幅選択)
DR1-DR0(出力データレート)
0x0F
Xen(1:有効(デフォルト))
Yen(1:有効(デフォルト))
Zen(1:有効(デフォルト))
PD(1:通常モード)
BW1-BW0(00:12.5Hz(デフォルト))
DR1-DR0(00:100Hz(デフォルト))
データシートの『7.2 CTRL1(20h)』で詳細を確認できます。
DR1 | DR0 | BW1 | BW0 | PD | Zen | Xen | Yen |
0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
0 | F |
i2c.write_byte_data(address, 0x23, 0x20)
0x23(CTRL4レジスタ)
SIM(SPIモード 4wire/3wire)
ST2-ST1(セルフテスト 有効/無効)
IMPen(トリガラッチ(レベル)有効/無効)
FS1-FS0(フルスケール選択)
BLE( Big/Little endian data選択 )
BDU(Block data update)
0x20
SIM(0:SPIモード 4wire(デフォルト))
ST1-ST0(00:セルフテスト無効(デフォルト))
IMPen(0:トリガラッチ(レベル)無効(デフォルト))
FS1-FS0(10:2000dps)
BLE(0:Data LSB(デフォルト))
BDU(0:continuous update(デフォルト))
データシートの『7.5 CTRL4(23h)』で詳細を確認できます。
BDU | BLE | FS1 | FS0 | IMPen | ST1 | ST0 | SIM |
0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
2 | 0 |
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)
各軸の角速度データを記憶しているレジスタは下図の通りです。
4.データを物理量に変換し画面に表示
#データ変換
out_x = xh << 8 | xl
out_y = yh << 8 | yl
out_z = zh << 8 | zl
out_x = xh << 8 | xl
読み込んだ8bitデータをシフトして、上位と下位の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.07
out_y = out_y * 0.07
out_z = out_z * 0.07
out_x = out_x * 0.07
物理量(角速度)に変換します。
測定範囲が±2000dpsなので、1digitあたりの角速度は70.00mdps/digit(0.07dps/digit)です。
データに0.07をかけて物理量にします。
#表示
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:』は、12行目のwhile文です。
プログラムの実行結果
プログラムを実行します。
①Runボタンを押します。
②3軸角速度データを1秒間隔で画面に表示します。
③Stopボタンを押すとプログラムは終了します。
ブレッドボードを水平に回転させるとZ軸の数値が変化します。X軸とY軸についても90°づつ軸を変えてブレッドボードを回転させると値が変化すると思います。
L3GD20DHの動作確認動画(2分12秒)の紹介です。
ExcelのVBAを使ってRaspberry PiとWiFi通信しています。
VBAからのコマンドをPythonで受信して、測定データをVBAに返送します。VBAは受け取った測定データをExcelにグラフ表示します。
動画はこの記事のVBAプログラムを使っています。
Excelのグラフをアニメーションで動かす方法を紹介しています。
以上、I2C通信でL3GD20Hから角速度データを読み込んで表示するサンプルでした。
SPI通信でデータを取得する
モジュールとRaspberry Piの接続
接続図
接続写真
SPI通信プログラミング
プログラムコード
import spidev
import time
#SPI設定
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 100000
spi.mode = 3
s_dat = [0x00, 0x00]
gyr_x = [0x00, 0x00, 0x00]
gyr_y = [0x00, 0x00, 0x00]
gyr_z = [0x00, 0x00, 0x00]
#L3GD20H設定
s_dat[0] = 0x20
s_dat[1] = 0x0F
readByteArry = spi.xfer2(s_dat)
s_dat[0] = 0x23
s_dat[1] = 0x20
readByteArry = spi.xfer2(s_dat)
#繰り返し
while True:
#設定
gyr_x[0] = 0x28
gyr_x[0] |= 0x80
gyr_x[0] |= 0x40
gyr_y[0] = 0x2A
gyr_y[0] |= 0x80
gyr_y[0] |= 0x40
gyr_z[0] = 0x2C
gyr_z[0] |= 0x80
gyr_z[0] |= 0x40
#データ読み込み
readByteArry = spi.xfer2(gyr_x)
readByteArry = spi.xfer2(gyr_y)
readByteArry = spi.xfer2(gyr_z)
#データ変換
out_x = gyr_x[2] << 8 | gyr_x[1]
out_y = gyr_y[2] << 8 | gyr_y[1]
out_z = gyr_z[2] << 8 | gyr_z[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.07
out_y = out_y * 0.07
out_z = out_z * 0.07
#表示
print('X: ' + str(out_x))
print('Y: ' + str(out_y))
print('Z: ' + str(out_z))
#一時停止
time.sleep(1)
spi.close
プログラムの説明
- SPI通信の設定
- センサーの設定
- センサーから角速度データを取得
- データを物理量に変換し画面に表示
- 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.センサーの設定
#L3GD20H設定
s_dat[0] = 0x20
s_dat[1] = 0x0F
readByteArry = spi.xfer2(s_dat)
s_dat[0] = 0x23
s_dat[1] = 0x20
readByteArry = spi.xfer2(s_dat)
CTRL1レジスタ設定
s_dat[0] = 0x20
s_dat[1] = 0x0F
CTRL4レジスタ設定
s_dat[0] = 0x23
s_dat[1] = 0x20
CTRL1レジスタとCTRL4レジスタは、I2C通信の2.センサーの設定に詳しい説明があります。
#設定
gyr_x[0] = 0x28
gyr_x[0] |= 0x80
gyr_x[0] |= 0x40
gyr_y[0] = 0x2A
gyr_y[0] |= 0x80
gyr_y[0] |= 0x40
gyr_z[0] = 0x2C
gyr_z[0] |= 0x80
gyr_z[0] |= 0x40
X軸、Y軸、Z軸の角速度データを読み込むためのレジスタアドレス設定です。
X軸:0x28
Y軸:0x2A
Z軸:0x2C
共通:0x80
[読み込み/書き込み] を [読み込み]に設定します。
共通:0x04
読み込みを自動インクリメントに設定します。
3.センサーから角速度データを取得
#データ読み込み
readByteArry = spi.xfer2(gyr_x)
readByteArry = spi.xfer2(gyr_y)
readByteArry = spi.xfer2(gyr_z)
readByteArry = spi.xfer2(gyr_x)
角速度データを格納しているレジスタアドレスからデータを読み込みます。
gyr_x[0]、gyr_y[0]、gyr_z[0]がレジスタアドレスを指定しています。
レジスタアドレスは、I2C通信の3.センサーから角速度を取得に詳しい解説があります。
4. データを物理量に変換し画面に表示
(I2C通信の4.データを物理量に変換し画面に表示に詳しい解説があります。)
#データ変換
out_x = gyr_x[2] << 8 | gyr_x[1]
out_y = gyr_y[2] << 8 | gyr_y[1]
out_z = gyr_z[2] << 8 | gyr_z[1]
out_x = gyr_x[2] << 8 | gyr_x[1]
取得した[2]の方のデータを8bit左にシフトして、上位|下位で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の補数表現を符号あり表現に変換します。
#物理量(角速度)に変換
out_x = out_x * 0.07
out_y = out_y * 0.07
out_z = out_z * 0.07
out_x = out_x * 0.07
物理量(角速度)に変換します。
測定範囲が±2000dpsなので、1digitあたりの角速度は70.00mdps/digit(0.07dps/digit)です。
データに0.07をかけて物理量にします。
#表示
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:』は、25行目のwhile文です。
プログラムの実行結果
プログラムの実行結果は、I2C通信時の実行結果と同じなので割愛します。
まとめ
L3GD20HモジュールからRaspberry PiにI2C通信とSPI通信でデータを読み込んで表示するサンプルでした。如何でしたでしょうか。
L3GD20Hは、ハイパスフィルタ設定、各種割り込み、温度測定など、今回使用していない機能がまだまだあります。興味があれば是非チャレンジしてください。
プログラミングやソフトウェアの記事です。
コメント