3軸ジャイロセンサーL3GD20Hの使い方(I2C通信/SPI通信)

L3GD20H ジャイロセンサー センサー

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に接続します。

L3GD20H 写真

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

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

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

モジュールとRaspberry Piの接続

接続図

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

接続写真

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)

プログラムの説明

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

  1. I2C通信の設定
  2. センサーの設定
  3. センサーから角速度データを取得
  4. データを物理量に変換し画面に表示
  5. 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 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
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)

各軸の角速度データを記憶しているレジスタは下図の通りです。

角速度16ビットデータのアドレス

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

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

out_x = xh << 8 | xl
読み込んだ8bitデータをシフトして、上位と下位の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.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°づつ軸を変えてブレッドボードを回転させると値が変化すると思います。

PythonのRunボタンとStopボタン
L3GD20Hのプログラムの実行結果
角速度 Z軸 回転

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

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

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

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

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

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

モジュールとRaspberry Piの接続

接続図

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

接続写真

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

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

プログラムの説明

  1. SPI通信の設定
  2. センサーの設定
  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.センサーの設定

#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は、ハイパスフィルタ設定、各種割り込み、温度測定など、今回使用していない機能がまだまだあります。興味があれば是非チャレンジしてください。

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

コメント