秋月から9軸センサーモジュール(BMX055)を入手しようとしたら、現在在庫切れとなっていました。販売ページにデータシートとサンプルソースがアップされていたため、物は無いけどとりあえず予習ということで中身を確認してみました。覚書ついでにサンプルソースコードの中身を解説です。
▼この製品です。ここからサンプルソースコードとかダウンロードできます(2022年/2月)▼
このモジュールはI2Cでマイコンなどと通信しますが、ここではI2C通信方法の詳細は割愛します。。
▼I2C通信方法はこちら▼
セットアップ部分
まずはセットアップ部分からです。ソースを抜粋しながら見ていきます。
加速度センサーの初期設定
最初に加速度センサーの初期設定です。ここでは測定レンジ、帯域幅、スリープモード(パワーモード)の設定を行っています。
Wire.beginTransmission(Addr_Accl); Wire.write(0x0F); // Select PMU_Range register Wire.write(0x03); // Range = +/- 2g Wire.endTransmission();
▲加速度の測定レンジを設定してます。加速度センサーのアドレス[Addr_Accl]は「0x19」。レンジ設定するレジスタアドレスは「0x0F」。続けて設定値は「0x03」(±2G)となってます。スケールレンジは以下の値から設定可能。
2進数 | 16進数 | 加速度測定レンジ |
---|---|---|
0011b | 0x03 | ±2G |
0101b | 0x05 | ±4G |
1000b | 0x08 | ±8G |
1100b | 0x0C | ±16G |
▼次に帯域幅(Bandwidth)の設定部分▼
Wire.beginTransmission(Addr_Accl); Wire.write(0x10); // Select PMU_BW register Wire.write(0x08); // Bandwidth = 7.81 Hz Wire.endTransmission();
ここで帯域幅の設定してます。レジスタアドレスは「0x10」。設定値「0x08」(7.81Hz)となってます。帯域幅は以下値から設定可能。
2進数 | 16進数 | 帯域幅 |
---|---|---|
01000b | 0x08 | 7.81Hz |
01001b | 0x09 | 15.63Hz |
01010b | 0x0A | 31.25Hz |
01011b | 0x0B | 62.5Hz |
01100b | 0x0C | 125Hz |
01101b | 0x0D | 250Hz |
01110b | 0x0E | 500Hz |
01111b | 0x0F | 1000Hz |
▼最後にパワーモードの設定▼
Wire.beginTransmission(Addr_Accl); Wire.write(0x11); // Select PMU_LPW register Wire.write(0x00); // Normal mode, Sleep duration = 0.5ms Wire.endTransmission(); delay(100);
加速度センサーのパワーモードを設定してます。「0x11」レジスタアドレスで、スリープやサスペンドの設定ができます。がデータシート見たのですが細かいところはよくわからなかったです。
加速度センサーの設定は以上。続いてジャイロセンサーの設定です。
ジャイロセンサーの初期設定
ジャイロセンサーのデバイスアドレスは「0x69」となってます。基本、加速センサーと同様な項目(レンジ、帯域幅、スリープモード)を設定している箇所です。
▼まずは測定レンジの設定部分▼
Wire.beginTransmission(Addr_Gyro); Wire.write(0x0F); // Select Range register Wire.write(0x04); // Full scale = +/- 125 degree/s Wire.endTransmission();
ここでジャイロのレンジ設定。アドレスは「0x0F」。設定値は「0x04」(±125deg/s)となってます。ジャイロのスケールレンジは以下から設定可能。
2進数 | 16進数 | 測定レンジ |
---|---|---|
000b | 0x00 | ±2000deg/s |
001b | 0x01 | ±1000deg/s |
010b | 0x02 | ±500deg/s |
011b | 0x03 | ±250deg/s |
100b | 0x04 | ±125deg/s |
▼続いて出力レートの設定部分▼
Wire.beginTransmission(Addr_Gyro); Wire.write(0x10); // Select Bandwidth register Wire.write(0x07); // ODR = 100 Hz Wire.endTransmission();
レジスタアドレスは「0x10」で設定値は「0x07」(100Hz)です。ここもいくつかの値(以下)から選択することが可能です。
2進数 | 16進数 | 出力レート | 帯域幅 |
---|---|---|---|
0111b | 0x07 | 100Hz | 32Hz |
0110b | 0x06 | 200Hz | 64Hz |
0101b | 0x05 | 100Hz | 12Hz |
0100b | 0x04 | 200Hz | 23Hz |
0011b | 0x03 | 400Hz | 47Hz |
0010b | 0x02 | 1000Hz | 116Hz |
0001b | 0x01 | 2000Hz | 230Hz |
0000b | 0x00 | 2000Hz | 無し |
▼最後にパワーモードの設定▼
Wire.beginTransmission(Addr_Gyro); Wire.write(0x11); // Select LPM1 register Wire.write(0x00); // Normal mode, Sleep duration = 2ms Wire.endTransmission();
加速度センサーと同様(NormalMode)の設定がされてます。
最後に地磁気センサーの設定です。
地磁気センサーの初期設定
地磁気センサーのアドレスは「0x13」となります。基本は加速度やジャイロと同じような初期設定項目ですが若干違うところがあります。
//------------------------------------------------------------// Wire.beginTransmission(Addr_Mag); Wire.write(0x4B); // Select Mag register Wire.write(0x83); // Soft reset Wire.endTransmission(); delay(100); //------------------------------------------------------------// Wire.beginTransmission(Addr_Mag); Wire.write(0x4B); // Select Mag register Wire.write(0x01); // Soft reset Wire.endTransmission();
まず最初にソフトリセットを掛けてそのあと、パワーコントロールbitを「1」にしてます。ここはおまじないと思ってこう記述するもんだと覚えましょう。
▼出力レート設定▼
Wire.beginTransmission(Addr_Mag); Wire.write(0x4C); // Select Mag register Wire.write(0x00); // Normal Mode, ODR = 10 Hz
地磁気センサーの出力レート設定は「0X4C」アドレスとなります。ここでは「0x00」(10Hz)で設定されてます。出力レートは以下の値から選択可能。
2進数 | 16進数 | レート |
---|---|---|
000b | 0x00 | 10Hz(デフォルト) |
001b | 0x01 | 2Hz |
010b | 0x02 | 6Hz |
011b | 0x03 | 8Hz |
100b | 0x04 | 15Hz |
101b | 0x05 | 20Hz |
110b | 0x06 | 25Hz |
111b | 0x07 | 30Hz |
あと地磁気センサーにレピティションの設定とかの記述があるのですが中身の細かいところはよくわからないです。。。
次にセンサー値を読み出す部分です。
センサー値の取得
ここからは加速度、ジャイロ、地磁気のセンサー値の取得部分になります。読み込んだ値をbit値から物理量に変換している部分です。
加速度センサー値の取得&変換
for (int i = 0; i < 6; i++) { Wire.beginTransmission(Addr_Accl); Wire.write((2 + i));// Select data register Wire.endTransmission(); Wire.requestFrom(Addr_Accl, 1);// Request 1 byte of data // Read 6 bytes of data // xAccl lsb, xAccl msb, yAccl lsb, yAccl msb, zAccl lsb, zAccl msb if (Wire.available() == 1) data[i] = Wire.read(); }
ここで加速度をビット値で読みだしてます。加速度値はアドレス「0x02」から6byte分で格納されてます。各軸、2byteずつ、計6byte分です。読みだした値をdata[]
に順に格納してます。
xAccl = ((data[1] * 256) + (data[0] & 0xF0)) / 16; if (xAccl > 2047) xAccl -= 4096; yAccl = ((data[3] * 256) + (data[2] & 0xF0)) / 16; if (yAccl > 2047) yAccl -= 4096; zAccl = ((data[5] * 256) + (data[4] & 0xF0)) / 16; if (zAccl > 2047) zAccl -= 4096;
ここで読み出した値を各軸ごとに振り分けてます。最初に各軸値の2byte分を結合して、16bit ⇒ 12bitデータへマスク。で次に正負の符号付き値にしてます。これを3軸分(3回)繰り返してます。個人的にはあまり好きな記述ではないです。
xAccl = xAccl * 0.0098; // range = +/-2g yAccl = yAccl * 0.0098; // range = +/-2g zAccl = zAccl * 0.0098; // range = +/-2g
加速度値をbit値 ⇒ 物理量(G)に変換してます。正確には設定レンジが±2Gなので2/4096でLSBは0.00097656…となります。次にジャイロセンサーの読み取り部分です。
ジャイロセンサー値の取得&変換
読み取り部分は加速度センサーと同じなので割愛。結合するところから微妙に違います。
xGyro = (data[1] * 256) + data[0]; if (xGyro > 32767) xGyro -= 65536; yGyro = (data[3] * 256) + data[2]; if (yGyro > 32767) yGyro -= 65536; zGyro = (data[5] * 256) + data[4]; if (zGyro > 32767) zGyro -= 65536;
ジャイロ値を各軸ごとに振り分けてるところです。ジャイロは加速度センサーと違い16bit値なので、結合して、正負値に変えてるだけです。
xGyro = xGyro * 0.0038; // Full scale = +/- 125 degree/s yGyro = yGyro * 0.0038; // Full scale = +/- 125 degree/s zGyro = zGyro * 0.0038; // Full scale = +/- 125 degree/s
ここでbit値から物理量(deg/s)へ変換してます。250/65536でLSBは0.00381469…。。最後に地磁気センサーの値読み取りです。
地磁気センサー値の取得
最後に地磁気センサー値の取得です。
xMag = ((data[1] <<5) | (data[0]>>3)); if (xMag > 4095) xMag -= 8192; yMag = ((data[3] <<5) | (data[2]>>3)); if (yMag > 4095) yMag -= 8192; zMag = ((data[5] <<7) | (data[4]>>1)); if (zMag > 16383) zMag -= 32768;
ここで読み取った値を各軸値に結合してます。地磁気は13bit値のようです。物理量には変換してなくbit値のまま。
ソース内容はだいたいこんなところです。サンプルソースは単純に取得した値を物理量に変換してそれをシリアル出力しているだけ。取得した値(ジャイロ、加速度、地磁気)をつかって姿勢角度算出したり、ドリフト補正したりするのは自分でやる必要がありそうです。
コメント