2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberry Pi PicoでPicoMite(MMBasic)を使う〜3軸加速度センサー+3軸ジャイロセンサーのデータを取得する

Posted at

はじめに

I2C接続の3軸加速度センサー+3軸ジャイロセンサーをネットの検索結果やChatGPTとのやり取りでPicoMite(MMBasic)での利用できるようになったのでその方法をまとめた。

3軸加速度センサー+3軸ジャイロセンサー

加速度センサーは物体の直線的な動きである加速度を、ジャイロセンサーは物体の回転である角速度を検知できるセンサーです。

今回はAmazonで購入したREES52 MPU-6050 使用 3軸ジャイロスコープ・3軸加速度センサー モジュールを使用した。

このセンサの機能は次の通りです。

  • 3軸MEMSジャイロスコープ(MPU-60X0)
    • X・Y・Z 各軸独立の振動型コリオリ式ジャイロを搭載
    • 回転によるコリオリ力で振動→静電容量検出→増幅・復調・フィルタリング→角速度に比例した電圧を生成
    • 各軸ごとにオンチップ16ビットADCでデジタル化
    • フルスケール範囲:±250/±500/±1,000/±2,000 °/s(プログラム選択)
    • サンプリングレート:8,000 SPS~3.9 SPS(プログラム選択)
    • 選択可能なローパスフィルタで多様なカットオフ周波数を設定可能
  • 3軸MEMS加速度計(MPU-60X0)
    • 各軸に独立したプルーフマス+差動静電容量センサーを配置
    • 製造ばらつき・熱ドリフトに強いアーキテクチャ
    • 水平設置時:X/Y軸=0 g、Z軸=+1 g を測定
    • 工場校正済みのスケール係数(電源電圧に依存しない)
    • 各軸ごとに専用シグマデルタ16ビットADCでデジタル出力
    • フルスケール範囲:±2/±4/±8/±16 g(プログラム選択)

X、Y、Z軸の方向は次の写真のとおりです。

MPU6050軸の向.jpeg

配線

次のように配線しました。MPU6050はRaspberry Pi Picoとは別のブレッドボードに載せてセンサだけを動かせるようにした。

MPU6050_ブレッドボード.png

MPU6050のデータ読み取りと表示プログラム

MPU6050からの読み取ったデータをOLEDに表示するプログラムを次の手順で作成した。

処理手順

  1. 定数、変数の定義
  2. MPU6050のジャイロスコープ、加速度計、電力モード、クロックソースなどを設定
  3. 無限ループ内でMPU6050から加速度、角速度、温度データを読み取り、16ビット符号付きの数値への変換
  4. 加速度、角速度、温度をOLEDへ出力

プログラム

MPU6050-test.bas
Option EXPLICIT ' Forcing a variable to be defined
CLS
' Define constat values
Const MPUADDR         = &H68  ' MPU6050 I2C address
Const REG_CONFIG      = &H1A  ' Configuration register
Const REG_GYRO_CONFIG = &H1B  ' Gyroscope configuration register
Const REG_ACC_CONFIG  = &H1C  ' Accelerometer configuration
Const REG_PWR_MGMT1   = &H6B  ' Power management 1 configuration register
Const REG_ACC_XOUT_H  = &H3B  ' Accelerometer X output High bit register
Const REG_TEMP_OUT_H  = &H41  ' Temperature register
Const REG_GYR_XOUT_H  = &H43  ' Gyroscope X output High bit register
Const SENS_A          = 16384 ' Accelerometer LSB sensitive
Const SENS_G          = 131   ' Gyroscope LSB sensitive
' Define variables
Dim acc_x, acc_y, acc_z       ' store Accelemeter data
Dim gyr_x, gyr_y, gyr_z       ' store Gyrometer data
Dim temp                      ' store Temperature data
' Define I2C pins
SetPin GP17, GP16, I2C
' Open I2C channel 1 100kHz, timeout 100msec
I2C OPEN 100, 100
' Send configuration to MPU6050
I2C WRITE MPUADDR, 0, 2, REG_CONFIG,      &H00
I2C WRITE MPUADDR, 0, 2, REG_GYRO_CONFIG, &H00
I2C WRITE MPUADDR, 0, 2, REG_ACC_CONFIG,  &H00
I2C WRITE MPUADDR, 0, 2, REG_PWR_MGMT1,   &H00

Do
  ' Get accelerometer X, Y, Z value
  acc_x = ReadWordToSigned16(MPUADDR, REG_ACC_XOUT_H)     / SENS_A
  acc_y = ReadWordToSigned16(MPUADDR, REG_ACC_XOUT_H + 2) / SENS_A
  acc_z = ReadWordToSigned16(MPUADDR, REG_ACC_XOUT_H + 4) / SENS_A
  ' Get Temerature value
  temp  = ReadWordToSigned16(MPUADDR, REG_TEMP_OUT_H)     / 340 + 36.53
  ' Get Gyroscope X, Y, Z value
  gyr_x = ReadWordToSigned16(MPUADDR, REG_GYR_XOUT_H)     / SENS_G
  gyr_y = ReadWordToSigned16(MPUADDR, REG_GYR_XOUT_H + 2) / SENS_G
  gyr_z = ReadWordToSigned16(MPUADDR, REG_GYR_XOUT_H + 4) / SENS_G
  ' Draw values to OLED
  Text 0,  0, "acc x = " + Str$(acc_x, -3, 3) + "g ",,7
  Text 0,  8, "    y = " + Str$(acc_y, -3, 3) + "g ",,7
  Text 0, 16, "    z = " + Str$(acc_z, -3, 3) + "g ",,7
  Text 0, 24, "gyr x = " + Str$(gyr_x, -3, 3) + "/s",,7
  Text 0, 32, "    y = " + Str$(gyr_x, -3, 3) + "/s",,7
  Text 0, 40, "    z = " + Str$(gyr_z, -3, 3) + "/s",,7
  Text 0, 48, "temp  = " + Str$(temp,  -3, 2) + "C",,7
  Pause 500
Loop

' Define function, get data and calcurate 16 signed value
Function ReadWordToSigned16(ADDR As Integer, REG As Integer) As Integer
  Local data%(2), tmp                       ' Define local variables
  I2C WRITE MPUADDR, 0, 1, REG              ' Send register #
  I2C READ  MPUADDR, 0, 2, data%()          ' Read register value
  tmp = data%(0) << 8 Or data%(1)           ' make 16bit value
  If tmp >= &H8000 Then tmp = tmp - &H10000 ' Check negative value, make signed value
  ReadWordToSigned16 = tmp                  ' Return 16bit signed value
End Function

End

変数宣言の強制

OPTION EXPLICIT

MMBasicではプログラム冒頭でOPTION EXPLICITコマンドを記述することで変数宣言を強制できる。このコマンドにより宣言していない変数は使用できなくなる。

MPU6050のレジスタなどを定数として定義

Const MPUADDR         = &H68
Const REG_CONFIG      = &H1A
略

プログラム中で使用するI2Cアドレス、MPU6050の各種レジスタのアドレスなどの数値を定数として定義している。
定義した定数は次の表の通り。レジスタのアドレスは MPU6050レジスタマップに記されている。

定数 値(16進) 説明
MPUADD &H68 MPU6050のI2Cアドレス
REG_CONFIG &H1A 設定レジスタ
REG_GYRO_CONFIG &H1B ジャイロメータ設定レジスタ
REG_ACC_CONFIG &H1C 加速度計設定レジスタ
REG_PWM_MGMT1 &H6B 電力管理1設定レジスタ
REG_ACC_XOUT_H &H3B 加速時計X軸データ上位8ビットの値格納レジスタ
REG_TEMP_XOUT_H &H41 温度X軸データ上位8ビットの値格納レジスタ
REG_GYR_XOUT_H &H43 ジャイロスコープX軸データ上位8ビットの値格納レジスタ
SENS_A 16384 加速度計LSB感度値
SENS_G 131 ジャイロスコープLSB感度値

変数宣言

Dim acc_x, acc_y, acc_z
Dim gyr_x, gyr_y, gyr_z
Dim temp   

宣言した変数は下記の7つで型指定の後置子を省略しているのですべて浮動小数点数型になる。

変数 格納する値  
acc_x X軸方向の加速度
acc_y Y軸方向の加速度
acc_z Z軸方向の加速度
gyr_x X軸方向の角速度
gyr_y Y軸方向の角速度
gyr_z Z軸方向の角速度
temp 温度

I2CのオープンとMPU6050の設定

Raspberry Pi PicoとMPU6050との間のI2Cチャンネル1で接続するピンを配線図に従って指定し、クロック周波数100kHz、タイムアウト100ミリ秒で開いている。

SetPin GP17, GP16, I2C
OPEN 100, 100

MPU6050の設定

I2C WRITE MPUADDR, 0, 2, REG_CONFIG,      &H00
I2C WRITE MPUADDR, 0, 2, REG_GYRO_CONFIG, &H00
I2C WRITE MPUADDR, 0, 2, REG_ACC_CONFIG,  &H00
I2C WRITE MPUADDR, 0, 2, REG_PWR_MGMT1,   &H00

I2C WRITEコマンドでMPU6050の複数の設定用レジスタへ設定を設定値&H00を書き込んでいる。設定値&H00はそれぞれの設定で次に示すの意味をもつ。

設定レジスタ(REG_CONFIG)

ジャイロスコープと加速度センサーの両方について、外部フレーム同期(FSYNC)ピンのサンプリングとデジタルローパスフィルタ(DLPF)の設定を行います。レジスタの構成は下記のとおり。

レジスタ Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
1A - - EXT_SYNC_SET[2:0] DLPF_CFG[2:0]
0 0 0 0 0 0 0 0

ジャイロスコープと加速度計は外部のフレーム同期(EXT_SYNC_SETを0)を使用せず、ディジタルローバスフィルタの設定で加速度計は帯域幅260Hz、遅延0msで、ジャイロスコープは帯域幅256Hz、遅延0.98ms、サンプリング周波数8kHzにする(DLPF_CFGを0)。3ビットのDLPF_CFGは下の表の8とおりの値の組み合わせを示す。

DLPF_CFG 加速時計 ジャイロスコープ
(Fs=1kHz)
帯域幅(Hz) 遅延(ms) 帯域幅(Hz) 遅延(ms) Fs(kHz)
0 260 0 256 0.98 8
1 184 2.0 188 1.9 1
2 94 3.0 98 2.8 1
3 44 4.9 42 4.8 1
4 21 8.5 20 8.3 1
5 10 13.8 10 13.4 1
6 5 19.0 5 18.6 1
7 予約済み 予約済み 8

ジャイロスコープ設定(REG_GYRO_CONFIG)

ジャイロスコープのセルフテストの有無とフルスケールレンジを設定するレジスタ。レジスタの構成は下記のとおり。

レジスタ Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
1B XG_ST YG_ST ZG_ST FS_SEL[1:0] - - -
0 0 0 0 0 0 0 0

ジャイロスコープのX、Y、Z軸のセルフテストは実行せず(Bit7〜Bit5を0)、フルスケールレンジを±250°/sにする(FS_SEL[1:0]を0)。LSB感度は下表から131LSB/°/sになる。

FS_SEL フルスケールレンジ LSB感度(SENS_G)
0 ±250°/s 131 LSB/°/s
1 ±500°/s 65.5 LSB/°/s
2 ±1000°/s 32.8 LSB/°/s
3 ±2000°/s 16.4 LSB/°/s

加速度計設定(REG_ACC_CONFIG)

加速度計のセルフテストの有無、フルスケール範囲を設定する。また、このレジスタはデジタルハイパスフィルタ(DHPF)も設定します。レジスタの構成は下記のとおり。

レジスタ Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
1C XA_ST YA_ST ZA_ST AFS_SEL[1:0] -
0 0 0 0 0 0 0 0

加速度計のX、Y、Z軸のセルフテストは実行せず(Bit7〜Bit5を0)、フルスケールレンジを±2gにする(AFS_SEL[1:0]を0)LSB感度は下表から16384 LSB/gになる。

AFS_SEL フルスケールレンジ LSB感度(SENS_A)
0 ±2g 16384 LSB/g
1 ±4g 8192 LSB/g
2 ±8g 4096 LSB/g
3 ±16g 2048 LSB/g

電力管理1の設定(REG_PWM_MGMT1)

ユーザーが電力モードとクロックソースを設定する。デバイス全体のリセット、温度センサーを無効にするためのビットも備えています。

レジスタ Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
6B DEVICE_RESET SLEEP CYCLE - TEMP_DIS CLKSEL[2:0]
0 0 0 0 0 0 0 0

クロックに内蔵8MHz発振器(CLKSELを0)を使い、スリープをせず(SLEEPを0)、温度センターを有効にする(TEMP_DISを0)。

CLKSEL クロックソース
0 内蔵8MHz発振器
1 X軸ジャイロスコープリファレンス付きPLL
2 Y軸ジャイロスコープリファレンス付きPLL
3 Z軸ジャイロスコープリファレンス付きPLL
4 外部32.768MHzリファレンス付きPLL
5 外部19.2MHzリファレンス付きPLL
6 予約済み
7 クロックを停止し、タイミングジェネレータをリセット状態に保つ

MPU6050から読み取ったデータから加速度、角速度、温度を算出

acc_x = ReadWordToSigned16(MPUADDR, REG_ACC_XOUT_H)     / SENS_A
acc_y = ReadWordToSigned16(MPUADDR, REG_ACC_XOUT_H + 2) / SENS_A
acc_z = ReadWordToSigned16(MPUADDR, REG_ACC_XOUT_H + 4) / SENS_A
temp  = ReadWordToSigned16(MPUADDR, REG_TEMP_OUT_H)     / 340 + 36.53
gyr_x = ReadWordToSigned16(MPUADDR, REG_GYR_XOUT_H)     / SENS_G
gyr_y = ReadWordToSigned16(MPUADDR, REG_GYR_XOUT_H + 2) / SENS_G
gyr_z = ReadWordToSigned16(MPUADDR, REG_GYR_XOUT_H + 4) / SENS_G

後述するMPU6050から加速度、角速度、温度のデータを読み取る関数ReadWordToSigned16を使用して取得したそれぞれのセンサーの16ビット符号付きの値を、それぞれの感度等の値で除して加速度、角速度、温度の値を算出しています。

MPU6050の加速度とジャイロスコープのX、Y、Z軸のデータを保持するレジスタは次の表(レジスタマップより)に示すように連続しているのでX軸の上位8ビットのレジスタの値に2および4を加算すればY軸、Z軸のレジスタにアクセスできる。

アドレス 名前 Bit7〜Bit0 格納されている値
3B ACCEL_XOUT_H ACCEL_XOUT[15:8] 加速度のX軸データの上位8ビット
3C ACCEL_XOUT_L ACCEL_XOUT[7:0] 加速度のX軸データの下位8ビット
3D ACCEL_YOUT_H ACCEL_YOUT[15:8] 加速度のY軸データの上位8ビット
3E ACCEL_YOUT_L ACCEL_YOUT[7:0] 加速度のY軸データの下位8ビット
3F ACCEL_ZOUT_H ACCEL_ZOUT[15:8] 加速度のZ軸データの上位8ビット
40 ACCEL_ZOUT_L ACCEL_ZOUT[7:0] 加速度のZ軸データの下位8ビット
41 TEMP_OUT_H TEMP_OUT[15:8] 温度データの上位8ビット
42 TEMP_OUT_L TEMP_OUT[7:0] 温度データの下位位8ビット
43 GYRO_XOUT_H GYRO_XOUT[15:8] ジャイロスコープのX軸データの上位8ビット
44 GYRO_XOUT_L GYRO_XOUT[7:0] ジャイロスコープのX軸データの下位8ビット
45 GYRO_YOUT_H GYRO_YOUT[15:8] ジャイロスコープのY軸データの上位8ビット
46 GYRO_YOUT_L GYRO_YOUT[7:0] ジャイロスコープのY軸データの下位8ビット
47 GYRO_ZOUT_H GYRO_ZOUT[15:8] ジャイロスコープのZ軸データの上位8ビット
48 GYRO_ZOUT_L GYRO_ZOUT[7:0] ジャイロスコープのZ軸データの下位8ビット

OLEDへの出力

Text 0,  0, "acc x = " + Str$(acc_x, -3, 3) + "g ",,7
Text 0,  8, "    y = " + Str$(acc_y, -3, 3) + "g ",,7
Text 0, 16, "    z = " + Str$(acc_z, -3, 3) + "g ",,7
Text 0, 24, "gyr x = " + Str$(gyr_x, -3, 3) + "/s",,7
Text 0, 32, "    y = " + Str$(gyr_x, -3, 3) + "/s",,7
Text 0, 40, "    z = " + Str$(gyr_z, -3, 3) + "/s",,7
Text 0, 48, "temp  = " + Str$(temp,  -3, 2) + "C",,7

直前までに得られた加速度、角速度、温度をStr\$関数で文字列に変換し、TextコマンドでOLEDへ出力する。Str\$関数の2番目の引数は整数部の桁数を指定するが-をつけることで正負の符号を常に不可することになる。

測定される温度はチップの温度です。

関数ReadWordToSigned16

Function ReadWordToSigned16(ADDR As Integer, REG As Integer) As Integer
  Local data%(2), tmp
  I2C WRITE MPUADDR, 0, 1, REG
  I2C READ  MPUADDR, 0, 2, data%()
  tmp = data%(0) << 8 Or data%(1)
  If tmp >= &H8000 Then tmp = tmp - &H10000
  ReadWordToSigned16 = tmp
End Function

関数ReadWordToSigned16は次の処理をしています。

  • 引数に与えられたデバイスのI2Cアドレス(ADDR)のレジスタ(REG)に格納されている2バイトのデータを配列data%()に格納します
  • 配列に格納した2つの8ビットデータのうち、上位8ビットを左へ8ビットシフト下値と下位8ビットの値の論理和で結合して16ビットの値にする。temp = data%(0) << 8 Or data%(1)
  • 得られた16ビットデータは2の補数表現なので正数の&H0000〜&H7000(10進で0〜32767)の場合はその値を,負数の&H8000〜&HFFFF(10進の32768〜65535)の場合には&H10000(10進の65536)から値を減じて符号付きにした値を返している

MMBasicでは変数や関数の戻り値の型指定は後置子を使う以外に変数 As 型という書式でも指定できます。戻り値は関数名への代入で指定します(ReadWordToSigned16 = tmp)。

MPU6050からのデータ読み出しの別な方法

ChatGPTにコードを問い合わせて得られた別のデータ読み出し方法としてはMPU6050のレジスタACCEL_XOUT_H(&H3B)からGYRO_ZOUT_L(&H48)まで14このレジスタが連続しているので14バイト分を一気に読み込む方法がある。読み込みを始めるレジスタを書き込むときにストップコンディションを送信しないように指定すればよい。

Dim buf%(14)
I2C WRITE MPUADDR, 1, 1, REG_ACCEL_XOUT_H
I2C READ  MPUADDR, 0, 14, buf%(0)

動作確認

プログラムを実行させ、MPU6050の向きを変えて加速度(重力加速度)を取得した結果を以下に示す。

センサ基盤を水平に置いたとき(Z軸方向への重力加速度)

基盤のシルク印刷面を上にしたとき。Z軸+方向で、+1になるはずだがわずかにずれている。

MPU6050+Z.jpeg

基盤のシルク印刷面を下向きにしたとき。Z軸ー方向で、–1になるはずだがわずかにずれている。

MPU6050-Z.jpeg

センサ基盤の短辺を上にしたとき(Y軸方向への重力加速度)

VCCなどのピンを左側にした状態で基盤の短辺を上にしたとき。Y軸+方向で、+1になるはずだがこれもわずかにずれている。

MPU6050+Y.jpeg

VCCなどのピンを右側にした状態で基盤の短辺を上にしたとき。Y軸ー方向で、–1になるはずだがこれもわずかにずれている。

MPU6050-Y.jpeg

センサ基盤の長辺を上にしたとき

基盤の長辺のピンを上にしたとき。X軸+方向で、+1になるはずだがこれもわずかにずれている。

MPU6050+X.jpeg

基盤の長辺のピンを下にしたとき。X軸ー方向で、–1になるはずだがこれもわずかにずれている。

MPU6050-X.jpeg

以上のようにRaspberry Pi PicoのMMBasicでもI2C接続の3軸加速度センサー+3軸ジャイロセンサーからデータを取得できることが確認できた。

参考サイトなど

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?