こんにちは、ENGかぴです。
BMX055はBOSCH社製の9軸(加速度3軸、ジャイロ3軸、磁気3軸)を搭載したセンサーモジュールです。BMX055はI2Cに対応しているため、ArduinoのWireライブラリを使用することでセンサーの情報を取得することができます。
WireライブラリでBMX055から取得した加速度、ジャイロ、磁気のデータをOLED及びシリアルプロッタに表示して動作確認を行いました。
動作確認にはAE-BMX055(秋月電子)、OLEDは0.95インチ(HiLetgo製)を使用しています。Arduinoのライブラリを使用して動作確認したことをまとめています。
Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方
以下では、Arduino UNOをArduinoと表記します。
BMX055を使用する
AE-BMX055はBOSCH社のBMX055にレベル変換回路を追加してDIP6ピンで使用できるようにコンパクトに設計したモジュールです。AE-BMX055の詳細は下記リンクを参考にしてください。
BMX055使用9軸センサーモジュール: センサ一般 秋月電子通商-電子部品・ネット通販 (akizukidenshi.com)
6ピンの構成でINTピンがないためBMX055のINT設定に関するレジスタを操作しても使用することができません。各種センサーの測定条件に関するレジスタを初期化して使用します。レジスタ等の詳細はBMX055取扱説明書を参照してください。
レジスタの初期化
加速度センサー、ジャイロセンサー、磁気センサーのレジスタの初期化を行います。デフォルト値から変更する内容についてまとめました。
レジスタ | 内容 |
---|---|
0x0F(PMU_RANGE) | 加速度センサーのgレンジを指定する。 ±2g(デフォルト)、±4g、±8g、±16gから指定する。 |
0x10(PMU_BW) | フィルタのバンド幅(BW)を指定する。BW=ODR/2を目安にBWを指定する。Normal Modeは10Hzなので7.81Hzを選択。 |
レジスタ | 内容 |
---|---|
0x0F(RANGE) | ジャイロセンサーの角速度のレンジを指定する。 ±125°/s、±250°/s、±500°/s、±1000°/s、±2000°/sから指定する。 |
0x10(BW) | サンプリングのODRお及びフィルタのバンド幅(BW)を指定する。ODRに対してデシメーション係数(間引き)やBWを指定します。ODRを高くするほど測定周期が短くなります。 |
レジスタ | 内容 |
---|---|
0x4B | ソフトリセット(スリープ時)及びSPIモードを指定する。 2ビットのソフトリセットビットを同時に立てるとPORによりソフトリセットとなる。ソフトリセットはスリープモードで有効となるのでPower Control bitを1にしてソフトリセットする。 |
0x4C | 動作モードを指定します。ODRを10Hz、Normal Modeを選択。 |
基本的に測定のレンジと測定周期の設定を行うことで、測定データを取得できるため測定以外の機能を使用しない場合は他の設定は必要ありません。
データを換算する
加速度センサーの測定データは0x02~0x07レジスタを読み込むことで取得できます。2バイト分のデータから12ビットのデータを生成し換算すると加速度が取得できます。
//0x02~0x08までのデータを読み込む 0x08はtempデータ
Bmx055Read( ACCL_ADRS, 0x02, &accldata[0], sizeof(accldata));
accl_x= (accldata[1] << 4 ) + ( accldata[0] >> 4 );
if( accl_x > 0x7FF){ //12bitのMSBが符号ビット
accl_x -= 0x1000;
}
accl.x = accl_x * range; //2gの場合はrange=0.00098
X軸のデータを算出する例で説明します。0x02(ACCD_X_LSB)レジスタの値をaccladata[0]、0x03(ACCD_X_MSB)レジスタの値をaccladata[1]に格納したものとします。
0x02レジスタはMSBからacc_x_lsb<3:0>が配置されているためaccladata[0]を右に4回シフトします。
0x03レジスタはMSBからacc_X_msb<11:8>、acc_X_msb<7:4>が配置されているためaccldata[1]を左に4回シフトします。
シフトした2つのデータを加算すると12ビットのデータになります。12ビットのデータのうち最上位ビットは符号ビットとなるため、符号付の11ビットの最大値である0x7FFを超えた場合0x1000を引くことで符号変換しています。
12ビットのデータに各レンジの値を乗算すると加速度のデータに換算することができます。
ジャイロセンサーの測定データは0x02~0x07レジスタを読み込むことで取得できます。2バイト分のデータを換算するとジャイロ(角速度)が取得できます。
//0x02~0x07までのデータを読み込む
Bmx055Read( GYRO_ADRS, 0x02, &gyrdata[0], sizeof(gyrdata));
gyro_x= (gyrdata[1] << 8 ) + gyrdata[0];
gyro.x = gyro_x * range; //125 deg/sの場合はrange=0.0038
X軸のデータを算出する例で説明します。0x02(RATE_X_LSB)レジスタの値をgyrdata[0]、0x03(RATE_X_MSB)レジスタの値をgyrdata[1]に格納したものとします。
0x02レジスタはMSBからrate_x_lsb<7:4>及びrate_x_lsb<3:0>が配置されているためgyrdata[0]は下位の1バイトデータとしてそのまま使用できます。
0x03レジスタはMSBからrate_X_msb<15:12>、rate_X_msb<11:8>が配置されているためgyrdata[1]を左に8回シフトします。
2つのデータを加算すると16ビットのデータになります。16ビットのデータに各レンジの値を乗算すると角速度のデータに換算することができます。
磁気センサーの測定データは0x42~0x47レジスタを読み込むことで取得できます。2バイト分のデータから13ビットのデータを生成すると磁気が取得できます。
//0x42~0x47までのデータを読み込む
Bmx055Read( MAG_ADRS, 0x42, &magdata[0], sizeof(magdata));
mag_x = (magdata[1] << 5 ) + (magdata[0] >> 3);
if( mag_x > 0xFFF){ //13bitのMSBが符号ビット
mag_x -= 0x2000;
}
mag.x = mag_x;
X軸のデータを算出する例で説明します。0x42レジスタの値をmagdata[0]、0x03レジスタの値をmagdata[1]に格納したものとします。
0x42レジスタはMSBからDATAX_lsb<4:0>が配置されているためmagdata[0]を右に3回シフトします。
0x43レジスタはMSBからDATAX_msb<12:5>が配置されているためmagdata[1]を左に5回シフトします。
13ビットのデータのうち最上位ビットは符号ビットとなるため、符号付の13ビットの最大値である0xFFFを超えた場合0x2000を引くことで符号変換しています。
2つのデータを加算すると13ビットのデータになります。磁気のデータはレンジによる換算がないため、加算したデータが磁気のデータになります。
Wireライブラリを使用する
Arduinoの標準ライブラリであるWireライブラリの使い方を説明します。Wire(I2C)の送信と受信を中心に説明しています。
Wireライブラリの初期化
#include <Wire.h>
void setup() {
Wire.begin(); //begin()内にアドレスを入れるとスレーブになる
//Wire.setClock(100000); //クロック周波数を設定する場合にセット初期は100kHz
}
Wire(I2C)を使用する場合はWire.hをインクルードします。begin()関数の引数の有無によってマスタで動作するかスレーブで動作するかが決まります。引数に指定した値でスレーブ動作を開始します。マスタとして使用するため引数は無しとします。
クロックは設定しなければ初期条件の100kHzで動作します。setClock()関数でクロックを指定する場合は通信誤差が大きくならないように注意する必要があります。
I2Cによる信号はプルアップ抵抗にも影響するためクロックを早く設定しすぎると波形がなまってしまうこともあるので特に意識せず100kHzで十分だと思います。
PR:RUNTEQ(ランテック )- マイベスト3年連続1位を獲得した実績を持つWebエンジニア養成プログラミングスクール
Wire(I2C)の送信と実装例
Wireライブラリを使った送信の手順は以下の通りです。
- beginTransmission()関数で初期化とスレーブアドレスをセット
- write()関数で書き込み対象のアドレスをセット
- write()関数で書き込むデータをセット
- endTransmission()関数で送信
1~3まではデータの準備です。4のendTransmission()関数はスタート・コンディションの発行やコントロール・バイト(7ビットのスレーブアドレスを左詰めにして最下位ビットにWriteフラグ(0)をセット)の処理を行いデータを送信した(書き込んだ)後ストップ・コンディションの発行を行います。以下に実装例を示します。
/* Wireの書き込み */
void Bmx055Write(uint8_t adr, uint8_t reg, uint8_t data){
Wire.beginTransmission(adr); //スレーブが存在するか確認
int8_t error = Wire.endTransmission();
if( error == 0){ //スレーブが存在する場合は以下を処理
Wire.beginTransmission(adr);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission();
}
}
Bmx055Write()関数はBMX055にデータを書き込む自作の関数です。第1引数にデバイス番号、第2引数にレジスタ、第3引数に書き込むデータを指定します。
最初にWireのメンバー関数のbeginTransmission()関数で初期化とスレーブアドレスをセットします。endTransmission()関数でアドレスを送信しスレーブが存在するか確認を行います。スレーブが存在する場合は戻り値が0になるためデータの書き込み処理に移ります。
スレーブに送信するデータを準備します。最初にbeginTransmission()関数で初期化とスレーブアドレスをセットします。次にwrite()関数でレジスタのアドレス、書き込むデータをセットします。
最後にendTransmission()関数でスタート・コンディションからストップ・コンディションまでを含めたデータを送信します。
【クリエイターズファクトリー】卒業がない!挫折する心配なし!Webスクール説明会申し込み
Wire(I2C)の受信と実装例
Wireライブラリを使った受信の手順は以下の通りです。
- beginTransmission()関数で初期化とスレーブアドレスをセット
- write()関数で書き込み対象のアドレスをセット
- endTransmission()関数で送信
- requestFrom()関数で対象のアドレスのデータを取得する
- read()関数で取得したデータを読み込む
1~3まではスレーブアドレスに対して書き込み対象のアドレスを指定します。4のrequestFrom()関数はスタート・コンディションの発行やコントロール・バイト(7ビットのスレーブアドレスを左詰めにして最下位ビットにReadフラグ(1)をセット)の処理を行い指定した数のデータを取得し、ストップ・コンディションの発行を行います。
5は4で取得したデータを読み込みます。送信と異なる点はrequestFrom()でストップ・コンディションを発行するためendTransmission()の発行は必要ありません。以下に実装例を示します。
/* Wireの読み込み */
void Bmx055Read(uint8_t adr, uint8_t reg, uint8_t *data, uint8_t sz){
Wire.beginTransmission(adr); //スレーブが存在するか確認
int8_t error = Wire.endTransmission();
if( error == 0){
Wire.beginTransmission(adr);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(adr, sz);
for( uint8_t i=0; i < sz; i++ ){
*data = Wire.read();
++data;
}
}
}
Bmx055Read()関数はBMX055のデータを読み込む自作の関数です。第1引数にデバイス番号、第2引数にレジスタ、第3引数に読み込んでデータを格納するアドレス、第4引数に読み込むデータ数を指定します。
最初にWireのメンバー関数のbeginTransmission()関数で初期化とスレーブアドレスをセットします。endTransmission()関数でアドレスを送信しスレーブが存在するか確認を行います。スレーブが存在する場合は戻り値が0になるためデータの受信処理に移ります。
データの受信はレジスタを選択した状態にするため、beginTransmission()関数で初期化とスレーブアドレスを指定しwrite()関数でレジスタを指定します。endTransmission()関数でデータを送信しレジスタを選択した状態にします。
データの受信はrequestFrom()関数で指定した数のデータを取得します。read()関数で取得したデータを読み込みます。
OLEDライブラリを使用する
HiLetgo製の0.95インチ7ピン 65kカラー対応のOLEDディスプレイモジュールを使用しています。通信方式は3線のSPI通信を使用します。下記リンクにモジュールに関する情報が記載されています。
0.95″ Inch 7 Pin Colorful 65K SPI OLED Display Module
OLED用のドライバーICはSSD1331でありArduino環境に対応しているのでライブラリを追加して文字や記号を表示することができます。Arduino IDEでライブラリを追加して使用する方法を説明します。
Adafruit SSD1331 OLED Driverライブラリを追加する

Arduino IDEのライブラリマネージャの検索欄にssd1331を入力するとライブラリの候補が表示されます。候補の中から「Adafruit SSD1331 OLED Driver Library for Arduino」をインストールします。
インストールする際にライブラリの依存関係をインストールするかを尋ねられることがあります。ライブラリの依存関係が不足しているとうまく動作しないことがあるためすべてをインストールすることをお勧めします。
OLEDライブラリの使用例
#include <Adafruit_SSD1331.h>
#define cs 10 //チップセレクト
#define rst 9 //リセット
#define dc 8 //DATA COMMAND
#define BLACK 0x0000
Adafruit_SSD1331 oled = Adafruit_SSD1331(&SPI, cs, dc, rst);
void setup() {
oled.begin();
oled.fillScreen(BLACK);
}
Adafruit_SSD1331.hをインクルードします。Adafruit_SSD1331クラスの変数としてoled(任意でよい)をインスタンス化します。第1引数にSPIクラスの変数のアドレスを指定します。Arduino環境ではSPIが標準で定義されているのでSPIを指定します。
第2引数にチップセレクトで使用するピン番号を指定します。
第3引数にData/Commandピン番号を指定します。SPI通信を3線で行うためData/Commandピンでデータの方向を選択して送受信します。
第4引数にRESピン番号を指定します。RESピンはHIGHにするとモジュールのリセットを解除します。LOWにするとリセット状態になります。
setup()内でAdafruit_SSD1331クラスのメンバー関数であるbegin()関数でOLEDの初期化を行います。fillScreen()関数は画面全体のカラーを指定した色で塗りつぶします。例ではBLACK(0x0000)0指定しています。色の指定は16bitデータ(0~65535の範囲)で行います。
oled.setTextSize(1); //5×7フォント
oled.setCursor(0, 5);
oled.setTextColor(RED); //テキストの色を指定
oled.print("ACCL:");
oled.setCursor(40, 5);
oled.print(accl.x);
setTextSize()関数でフォントの大きさを指定します。1を指定すると5×7のフォントになります。2以上を指定すると1のフォント基準に倍数したフォントになります。0を指定すると1と同じフォントになります。
setCursor()関数で文字表示する座標を指定します。第1引数にX座標、第2引数にY座標を指定します。座標はピン側を上に見た時OLEDの左上の座標が(X,Y)=(0,0)になります。
setTextColor()関数はテキストの色を指定します。16ビットの値で色を指定します。
print()関数で文字を書き込んで表示します。例ではACCL:を表示後カーソルを移動して加速度を文字列で出力しています。
動作確認

AE-BMX055はJP6、JP4、JP5をジャンパーして使用しています。Wireを使用するためA4(SDA)、A5(SCL)に接続します。
OLEDはSPI通信を3線式で行うためArduinoのMISO(12ピン)は使用しません。MOSI(11ピン)で送信と受信をDCピンでデータとコマンドを切り替えながら通信を行います。RESピンはリセットを使用しない場合はHIGHに固定しても問題ありません。CSピンはLアクティブとなるのでモジュールを常に使用する場合はLOWに固定しても問題ありません。

電源を入れるとOLEDにBMX055から取得したデータを表示します。磁石のN極をX軸側に近づけているためMAG: 2094になっています。また重力加速度がZ軸方向にかかっているため0.98になっています。
次にBMX055を動かした測定値の様子をシリアルプロッタでグラフ表示して確認しました。

加速度はBMX055を各軸方向に向きを変えて測定しました。シリアルプロッタに表示すると向きによってY軸が-1.0、Z軸が1.0、X軸が1.0、X軸が-1.0など重力加速度に対応した値になっていることが確認できました。

ジャイロはBMX055の各軸を基準に回転させて測定しました。シリアルプロッタに表示すると回転軸に応じて測定値が変化していることが確認できました。また角速度が最大である125°(レンジの設定で125°/sにしている)で頭打ちになっていることも確認できました。

磁気はデータをX軸、Y軸、Z軸に対しては磁石のN極とS局の向きを変えたり磁石を近づけたり遠ざけたりして測定を行いました。シリアルプロッタに表示すると磁石の向きや距離によって値が増減することが確認できました。磁石の強度を確認する手段がないため値の変化のみの確認になりました。
ソースコード全体
ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。
リンクからZIPファイル形式のファイルをダウンロードし、任意の場所に展開していただくとテキストファイルが生成されます。
磁気センサーは加速度やジャイロセンサーの動作確認を行っている途中で動作停止することがありました。対策としてデータを読み込んだ後でソフトリセットしています。
関連リンク
Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。
Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方
Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方
ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方
PR:わからないを放置せず、あなたにあった最低限のスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
最後まで、読んでいただきありがとうございました。