😍

6軸IMUを自作した!

2024/12/01に公開

はじめに

お久しぶりです!ネギです。大学に進学して予想以上に忙しくて有意義な日々を過ごしている今日このごろです。前回に引き続き今回の記事もJLCPCB関連の記事となっております。今回もJLCPCBさんのスポンサーで基板製造と部品実装をお願いしました。前回がモータードライバーに関しての記事だったので今回は別のもの、IMU(加速度センサ・ジャイロセンサ)を紹介します!モータードライバーに関しては個人的に納得行くものができたら再度紹介します。乞うご期待。

IMUって何?

この記事を読む多くの皆さんはご存知だと思いますが一応IMUについて解説します。IMUを開発しているTDKから引用すると「IMU (イナーシャル・メジャーメント・ユニット)とは加速度センサとジャイロスコープからなるユニットを基本とし、ある物体の加速度と角速度を検出するための装置です。」らしいです。私達が生きている世界は3次元なので、x,y,z軸の加速度とx, y, z軸周りの角速度\dot{\theta_x}, \dot{\theta_y}, \dot{\theta_z}をそれぞれ計測することができます。これらの値を用いることで物体の運動の特徴を知ることができます。例えば、Nintedo SwitchのJoyConにもIMUが搭載されています。ゲームによってはJoyConの傾きでキャラクターを操作できると思います。この技術はIMUから得た数値をもとにJoyConの傾きなどを計算して操作に応用しているわけです。他にもスマートフォンなどにも必ず入っています。

なぜIMUを開発したのか

IMUの紹介からわかるようにIMUは非常に有用なセンサユニットです。自立して動作するデバイスではデバイス自身で運動の特徴を把握してフィードバックする必要があります。その一つとしてデバイスの傾きを把握する必要があります。例えば、ドローンとかでは水平を保つよう各モーターの出力をリアルタイムで微調整しています。その微調整の大元がIMUから得られる機体の傾きなわけです。ここまでくればわかるとお思いますが自立型ロボットを制作する必要のあるロボカップで、IMUは必須となります。また、手動型のオムニホイールでも機体の向きが勝手にズレていしまうのでIMUを使ってフィードバックする必要があります。(人間の手でも修正できますがコンピューターに処理させたほうがスマートですよね。)高い精度のIMUがあればあるほどよいわけです。そこで、自分で開発してみることにしました。

自作IMU紹介

使用部品

品名 個数
IMU TDK ICM-42688-P 1
3端子レギュレータ PJ73HM33SC 1
セラミックコンデンサ 10nF (1005) 1
セミラックコンデンサ 100nF (1005) 1
セミラックコンデンサ 2.2μF (1608) 1
セミラックコンデンサ 10μF (1608) 2

IMUユニットに必要なセンサなどはすべて内蔵されているので、他に用意するものはかなり少なっています。入力電源を適切な電圧まで降圧するレギュレータとパスコン類があれば動きます。

回路図

IMC-42688-Pのデータシートを参考に作成した回路図です。特に特徴とかはありません。

  • 電源入力は5Vとなっている点に注意です。
    • なぜ5V入力にしたか忘れました。すみません。
    • 3端子レギュレータで3.3Vに降圧しています。
  • 通信方式はSPIになっています。
    • 過去のロボットでI2Cに苦しめられたのでSPIを選択しました。

届いた基板

JLCPCBさんから届いた基板です。まだコネクタ類は取り付けていない状態です。

  • 表面
  • 裏面
  • はんだ付けの品質は非常に綺麗だと思います。
  • IMUユニットが曲がって取り付けられたりすると精度に影響してくるので、委託してきれいにはんだ付けしてもらったほうが良いと思います。
  • 表面の右下に軸の向きがわかるようになっています。
    • 写真の水平方向がx軸(右向き正)、垂直方向がy軸(上向き正)、基板を垂直に貫くよう方向がz軸(裏面から表面の方向が正)となっています。
  • 裏面に配線用のシルクがあります。

以下がコネクタをつけてブレッドボード上で配線した様子です。マイコンにはSeeeduino XIAOを使用しています。

動作確認

インターネット上にあるICM-42688用のライブラリを利用して簡単な動作確認を行いました。本当はライブラリも自分で書きたいのですが、この記事を早く書くためにとりあえず既製ライブラリを利用させていただきました。

#include "Arduino.h"
#include "ICM42688.h"

// an ICM42688 object with the ICM42688 sensor on SPI bus 0 and chip select pin 10
ICM42688 IMU(SPI, D7);

void setup() {
    // serial to display data
    Serial.begin(115200);
    while (!Serial) {
    }

    // start communication with IMU
    int status = IMU.begin();
    if (status < 0) {
        Serial.println("IMU initialization unsuccessful");
        Serial.println("Check IMU wiring or try cycling power");
        Serial.print("Status: ");
        Serial.println(status);
        while (1) {
        }
    }

    Serial.println("ax,ay,az,gx,gy,gz,temp_C");
}

void loop() {
    // read the sensor
    IMU.getAGT();
    // display the data
    Serial.print(IMU.accX(), 6);
    Serial.print("\t");
    Serial.print(IMU.accY(), 6);
    Serial.print("\t");
    Serial.print(IMU.accZ(), 6);
    Serial.print("\t");
    Serial.print(IMU.gyrX(), 6);
    Serial.print("\t");
    Serial.print(IMU.gyrY(), 6);
    Serial.print("\t");
    Serial.print(IMU.gyrZ(), 6);
    Serial.print("\t");
    Serial.println(IMU.temp(), 6);
    delay(100);
}

上記のプログラムに加え、"ICM42688.h", "ICM42688.cpp"を用意する必要があります。実際にこのコードを書き込むと以下のように各加速度と角速度、またIMUに内蔵されている温度センサからの温度が出力されます。

また、少しコードをいじっってz軸周りの角度、ヨー角を計算するプログラムも試してみました。細かい計算のやり方などについてはわかりやすい記事がインターネット上にあるので調べてみてください。使用したコードだけ掲載しておきます。

#include "Arduino.h"
#include "ICM42688.h"

// an ICM42688 object with the ICM42688 sensor on SPI bus 0 and chip select pin 10
ICM42688 IMU(SPI, D7);

void setup() {
    // serial to display data
    Serial.begin(115200);
    while (!Serial) {
    }

    // start communication with IMU
    int status = IMU.begin();
    if (status < 0) {
        Serial.println("IMU initialization unsuccessful");
        Serial.println("Check IMU wiring or try cycling power");
        Serial.print("Status: ");
        Serial.println(status);
        while (1) {
        }
    }

    float gZ_sum = 0.0f;
    for (int i = 0; i < 500; i++) {
        IMU.getAGT();
        gZ_sum += IMU.gyrZ();
        delay(10);
    }
    IMU.setGyroBiasZ(gZ_sum / 500.0f);
    Serial.print("Calibration complete\n");
}

void loop() {
    // read the sensor
    IMU.getAGT();
    
    static float deg = 0.0f;
    static float prev_gz = 0.0f;
    static unsigned long prev_time = micros();
    unsigned long curr_time = micros();
    deg += (IMU.gyrZ() + prev_gz) / 2.0f * (curr_time - prev_time) / 1000000.0f;
    if (deg > 180.0f) {
        deg -= 360.0f;
    } else if (deg <= -180.0f) {
        deg += 360.0f;
    }
    prev_gz = IMU.gyrZ();
    prev_time = curr_time;
    Serial.print(deg, 6);
    Serial.print(" deg\n");
}

実際に書き込んでみるとちゃんと角度が計算できています。

最後に

自作IMUの開発が無事にできました。やった〜。ロボコニストとしてやっぱり使うモジュールは1つ1つ自作指定ですよね。そんなみなさんに朗報です。JLCPCBを利用すれば自作基板が安く速くできてしまいます。初回利用ではお得なクーポンもゲットできちゃいます。まだ使ったことが無いという人は是非一度利用してみてください。過去の記事で発注の仕方などは解説しているのでぜひ読んでみてください。ちょっとでも興味があれば一度以下のリンクからJLCPCBのサイトにアクセスしてみてください。

JLCPCB 日本語サイト (JLCPCB 英語サイト

また、分かりづらい点などがあればぜひ教えていただけると幸いです。最後に、私のX @negi_roboをフォローしていただけると嬉しいです。

Discussion