🪐

【連載④】宇宙を目指す小さなIMU試作の記録:MPU6050+TMP102を統合してIMUモジュールにする

に公開

はじめに

これまでの記事では、MPU6050による加速度・ジャイロデータの取得、TMP102による温度データの取得をそれぞれ個別に行ってきました。

この回では、いよいよ両センサーをI²Cバス上に同時に接続し、Arduinoを使って同時に読み取る統合モジュールを構築します。

2つのセンサーはどちらもI²C対応であり、異なるI²Cアドレス(MPU6050: 0x68 / TMP102: 0x48)を持つため、1本のSDA/SCLラインで並列接続が可能です。これにより、Arduinoの1つのI²Cポートで複数センサーを制御する基本的な仕組みを学ぶことができます。


この回で行うこと

  • MPU6050とTMP102を同じI²Cラインに接続
  • Arduinoで両方のデータを同時に取得
  • それらの値をCSV形式でシリアルモニターに出力
  • Pythonなどでの後処理(グラフ化、補正)に備える

なぜCSV形式で出力するのか?

センサーの出力をシリアルモニターで“見るだけ”では、データの変化傾向や相関を分析するのが難しいです。
CSV(カンマ区切りテキスト)形式で出力すれば、ExcelやPythonのpandasなどでそのまま読み込み・可視化・解析することができ、次のステップである温度ドリフト補正やセンサーフュージョンにスムーズに進むことができます。


次回は、このCSVデータを使って、Pythonでリアルタイムに可視化しながら**「温度変化とセンサー出力の関係性」を視覚的に分析する**環境を構築していきます。

回路図

実際のモジュール(汚いけど、配線を作ってみた)

Arduinoコード(統合)

このスケッチでは、MPU6050から加速度・角速度の6軸データを、TMP102から温度データをそれぞれI²C経由で取得し、それらを1行のCSV形式でシリアルモニターに出力します。

sketch_accel_gyro_temp.ino

#include <Wire.h>

#define MPU_ADDR    0x68
#define TMP102_ADDR 0x48

const float ACCEL_SCALE = 16384.0; // ±2g
const float GYRO_SCALE  = 131.0;   // ±250°/s

void setup() {
  Serial.begin(9600);
  Wire.begin();

  // MPU6050 スリープ解除
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6B); // PWR_MGMT_1
  Wire.write(0x00); // スリープ解除
  Wire.endTransmission();

  delay(100);

  // CSVヘッダー出力
  Serial.println("Temp_C,Accel_X[g],Accel_Y[g],Accel_Z[g],Gyro_X[dps],Gyro_Y[dps],Gyro_Z[dps]");
}

void loop() {
  // TMP102から温度を取得
  float tempC = readTMP102();

  // MPU6050から加速度・ジャイロを取得
  int16_t ax_raw, ay_raw, az_raw, gx_raw, gy_raw, gz_raw;
  readMPU6050(ax_raw, ay_raw, az_raw, gx_raw, gy_raw, gz_raw);

  // スケーリング
  float ax = ax_raw / ACCEL_SCALE;
  float ay = ay_raw / ACCEL_SCALE;
  float az = az_raw / ACCEL_SCALE;
  float gx = gx_raw / GYRO_SCALE;
  float gy = gy_raw / GYRO_SCALE;
  float gz = gz_raw / GYRO_SCALE;

  // CSV出力
  Serial.print(tempC, 2); Serial.print(",");
  Serial.print(ax, 2); Serial.print(",");
  Serial.print(ay, 2); Serial.print(",");
  Serial.print(az, 2); Serial.print(",");
  Serial.print(gx, 2); Serial.print(",");
  Serial.print(gy, 2); Serial.print(",");
  Serial.println(gz, 2);

  delay(500);
}

float readTMP102() {
  Wire.beginTransmission(TMP102_ADDR);
  Wire.write(0x00); // 温度レジスタ
  Wire.endTransmission();
  Wire.requestFrom(TMP102_ADDR, 2);

  if (Wire.available() == 2) {
    uint8_t msb = Wire.read();
    uint8_t lsb = Wire.read();
    int16_t rawTemp = ((msb << 8) | lsb) >> 4;
    if (rawTemp & 0x800) rawTemp |= 0xF000; // 負数補正
    return rawTemp * 0.0625;
  }

  return -999.0; // エラー時
}

void readMPU6050(int16_t &ax, int16_t &ay, int16_t &az, int16_t &gx, int16_t &gy, int16_t &gz) {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B); // Accel_X_H
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14);

  if (Wire.available() >= 14) {
    ax = Wire.read() << 8 | Wire.read();
    ay = Wire.read() << 8 | Wire.read();
    az = Wire.read() << 8 | Wire.read();
    Wire.read(); Wire.read(); // Temp(未使用)
    gx = Wire.read() << 8 | Wire.read();
    gy = Wire.read() << 8 | Wire.read();
    gz = Wire.read() << 8 | Wire.read();
  } else {
    ax = ay = az = gx = gy = gz = 0;
  }
}

結果

シリアルモニターにセンサーのデータが出力されていることを確認。

Discussion