0x6A Logbook

0x6A Logbook
Shi6a的筆記本
  1. 首頁
  2. 程式開發
  3. 正文

MPU6050 六軸陀螺儀加速度計完整教學:I2C 暫存器讀取、DMP 姿態解算與 FIFO 資料串流

2026 年 6 月 17 日 17點熱度 0人點贊 0條評論

MPU6050 六軸慣性感測器

MPU6050 是 InvenSense 推出的 MEMS 六軸慣性感測器,整合 3 軸陀螺儀與 3 軸加速度計於單一晶片,內建 DMP(Digital Motion Processor)硬體姿態融合引擎,廣泛用於無人機飛控、手機螢幕旋轉、機器人平衡、VR/AR 頭盔等需要即時姿態追蹤的應用。

規格一覽

參數 陀螺儀 加速度計
測量範圍 ±250 / 500 / 1000 / 2000 °/s ±2 / 4 / 8 / 16 g
解析度 (16-bit) 131 / 65.5 / 32.8 / 16.4 LSB/(°/s) 16384 / 8192 / 4096 / 2048 LSB/g
取樣率 最高 8 kHz 最高 1 kHz
雜訊密度 0.005 (°/s)/√Hz 400 μg/√Hz
非線性度 ±0.2% ±0.5%
介面 I2C (0x68/0x69) + SPI (MPU6000)
內建功能 DMP 姿態融合、FIFO、中斷、溫度感測

ESP32 + MPU6050 接線圖

硬體接線

MPU6050 ESP32 備註
VCC 3.3V 不可接 5V!MPU6050 最高 3.6V
GND GND 共地必要
SCL GPIO 22 I2C 時鐘(需 4.7kΩ 上拉)
SDA GPIO 21 I2C 資料(需 4.7kΩ 上拉)
AD0 GND I2C 位址 = 0x68;接 3.3V 則為 0x69
INT GPIO 4 (可選) 中斷輸出(資料就緒)

注意:大部分 MPU6050 模組(如 GY-521)已內建 I2C 上拉電阻,不需額外添加。

I2C 暫存器讀取

MPU6050 使用標準 I2C 協定,7-bit 位址 0x68(AD0=LOW)。設定暫存器和讀取感測資料都透過 I2C 進行:

I2C 讀取 MPU6050 加速度暫存器時序

關鍵暫存器速查

位址 名稱 預設值 說明
0x19 SMPLRT_DIV 0x07 取樣速率除頻器
0x1A CONFIG 0x00 數位低通濾波器 (DLPF) 設定
0x1B GYRO_CONFIG 0x00 陀螺儀滿量程範圍選擇
0x1C ACCEL_CONFIG 0x00 加速度計滿量程範圍選擇
0x3B ACCEL_XOUT_H - 加速度 X 軸高位元組(Burst 讀取起點)
0x41 TEMP_OUT_H - 溫度資料高位元組
0x43 GYRO_XOUT_H - 陀螺儀 X 軸高位元組
0x6B PWR_MGMT_1 0x40 電源管理(Bit 7 = Reset, Bit 6 = Sleep)
0x75 WHO_AM_I 0x68 元件辨識碼(唯讀)

Arduino 程式設計

基礎讀取:原始陀螺儀與加速度資料

// ESP32 MPU6050 基礎讀取
#include <Wire.h>

#define MPU6050_ADDR 0x68

void setup() {
    Serial.begin(115200);
    Wire.begin(21, 22);  // SDA, SCL

    // 初始化 MPU6050
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(0x6B);          // PWR_MGMT_1
    Wire.write(0x00);          // 喚醒(清除 Sleep 位元)
    Wire.endTransmission(true);

    // 設定陀螺儀量程 ±500°/s
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(0x1B);          // GYRO_CONFIG
    Wire.write(0x08);          // ±500°/s (65.5 LSB/(°/s))
    Wire.endTransmission(true);

    // 設定加速度計量程 ±4g
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(0x1C);          // ACCEL_CONFIG
    Wire.write(0x08);          // ±4g (8192 LSB/g)
    Wire.endTransmission(true);

    Serial.println("MPU6050 初始化完成");
    delay(100);
}

void loop() {
    int16_t ax, ay, az, gx, gy, gz, temp;

    // Burst 讀取:從 0x3B 開始連續讀取 14 個位元組
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(0x3B);          // 起始暫存器
    Wire.endTransmission(false);
    Wire.requestFrom(MPU6050_ADDR, 14, true);

    ax = (Wire.read() << 8) | Wire.read();  // ACCEL_XOUT_H/L
    ay = (Wire.read() << 8) | Wire.read();
    az = (Wire.read() << 8) | Wire.read();
    temp = (Wire.read() << 8) | Wire.read();  // TEMP_OUT_H/L
    gx = (Wire.read() << 8) | Wire.read();    // GYRO_XOUT_H/L
    gy = (Wire.read() << 8) | Wire.read();
    gz = (Wire.read() << 8) | Wire.read();

    // 轉換為物理單位
    float a_scale = 8192.0;  // ±4g
    float g_scale = 65.5;    // ±500°/s
    float tempC = temp / 340.0 + 36.53;

    Serial.printf("Accel: %.2f %.2f %.2f g | Gyro: %.1f %.1f %.1f °/s | Temp: %.1f&C
",
        ax/a_scale, ay/a_scale, az/a_scale,
        gx/g_scale, gy/g_scale, gz/g_scale, tempC);

    delay(50);  // 20 Hz
}

DMP 姿態解算

MPU6050 內建的 DMP(Digital Motion Processor)是專用的硬體運動處理器,可將陀螺儀與加速度計資料融合,輸出四元數或尤拉角,大幅減輕主控晶片的運算負擔。

MPU6050 DMP 感測器融合管線

使用 MPU6050_tockn 函式庫

// ESP32 MPU6050 DMP 姿態解算(含 filter)
// 下載並安裝 MPU6050_tockn 函式庫
#include <MPU6050_tockn.h>
#include <Wire.h>

MPU6050 mpu6050(Wire);

void setup() {
    Serial.begin(115200);
    Wire.begin(21, 22);
    mpu6050.begin();
    mpu6050.calcGyroOffsets(true);  // 自動校正陀螺儀零偏
    Serial.println("DMP 初始化完成,請保持靜止 5 秒...");
}

void loop() {
    mpu6050.update();  // 更新感測器資料 + 互補濾波

    Serial.printf("Roll: %.2f° | Pitch: %.2f° | Yaw: %.2f° ",
        mpu6050.getAngleX(),  // Roll (繞 X 軸)
        mpu6050.getAngleY(),  // Pitch (繞 Y 軸)
        mpu6050.getAngleZ()); // Yaw (繞 Z 軸)

    Serial.printf("| Accel: %.2f %.2f %.2f g ",
        mpu6050.getAccX(), mpu6050.getAccY(), mpu6050.getAccZ());

    Serial.printf("| Gyro: %.2f %.2f %.2f °/s
",
        mpu6050.getGyroX(), mpu6050.getGyroY(), mpu6050.getGyroZ());

    delay(10);  // 100 Hz
}

使用 MPU6050 DMP 原生韌體庫(精確版)

DMP FIFO 封包結構

// ESP32 MPU6050 DMP 原生 FIFO 讀取
// 安裝 MPU6050 by Electronic Cats 函式庫
#include <MPU6050_6Axis_MotionApps20.h>

MPU6050 mpu;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;         // 四元數
VectorInt16 aa;       // 加速度計 raw
VectorFloat gravity;  // 重力向量
float ypr[3];         // Yaw/Pitch/Roll (弧度)

void setup() {
    Serial.begin(115200);
    Wire.begin(21, 22);
    mpu.initialize();

    if (!mpu.testConnection()) {
        Serial.println("MPU6050 連接失敗!");
        while (1);
    }

    // 初始化 DMP
    uint8_t devStatus = mpu.dmpInitialize();
    if (devStatus != 0) {
        Serial.printf("DMP 初始化失敗:%d
", devStatus);
        while (1);
    }

    // 設定感測器偏移值(需事先校準)
    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1788);

    // 啟用 DMP
    mpu.setDMPEnabled(true);
    mpu.resetFIFO();
    Serial.println("DMP 已啟用,請等待資料...");
}

void loop() {
    fifoCount = mpu.getFIFOCount();
    if (fifoCount < 42) return;  // DMP 封包大小

    mpu.getFIFOBytes(fifoBuffer, 42);

    // 從 FIFO 解出四元數
    mpu.dmpGetQuaternion(&q, fifoBuffer);

    // 轉換為尤拉角
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);

    // 轉換為度數並輸出
    float yaw   = ypr[0] * 180.0 / M_PI;
    float pitch = ypr[1] * 180.0 / M_PI;
    float roll  = ypr[2] * 180.0 / M_PI;

    Serial.printf("Yaw: %7.2f° | Pitch: %7.2f° | Roll: %7.2f°
",
        yaw, pitch, roll);
}

Roll/Pitch/Yaw 即時軌跡

互補濾波器 vs Kalman 濾波器 vs DMP

演算法 運算量 精度 延遲 實作難度 適用場景
互補濾波器 極低 中等 低 簡單 入門、玩具
Mahony/Madgwick 低 高 中 中等 一般姿態解算
Kalman 濾波器 高 非常高 高 困難 精密導航
DMP(硬體) 無 高 低 簡單 MPU6050 最佳解

互補濾波器自實作

// 簡潔互補濾波器(搭配 MPU6050 原始資料)
typedef struct {
    float roll;   // °
    float pitch;  // °
} Attitude;

Attitude complementaryFilter(float ax, float ay, float az,
                              float gx, float gy, float gz,
                              Attitude prev, float dt, float alpha) {
    // alpha = 0.98, dt = 時間間隔 (秒)

    // 從加速度計計算傾角(參考重力向量)
    float accRoll  = atan2(ay, az) * 180.0 / M_PI;
    float accPitch = atan2(-ax, sqrt(ay*ay + az*az)) * 180.0 / M_PI;

    // 從陀螺儀積分角度
    float gyroRoll  = prev.roll  + gx * dt;
    float gyroPitch = prev.pitch + gy * dt;

    // 互補融合
    Attitude out;
    out.roll  = alpha * gyroRoll  + (1 - alpha) * accRoll;
    out.pitch = alpha * gyroPitch + (1 - alpha) * accPitch;

    return out;
}

FIFO 與中斷應用

// MPU6050 FIFO 中斷讀取(不阻塞主迴圈)
// INT 腳位接 ESP32 GPIO 4
volatile bool dataReady = false;

void IRAM_ATTR onDataReady() {
    dataReady = true;
}

void setup() {
    pinMode(4, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(4), onDataReady, RISING);

    // ... MPU6050 + DMP 初始化(同上)...

    // 啟用中斷輸出
    mpu.setIntEnabled(true);
    mpu.setIntDMPEnabled(true);
}

void loop() {
    if (!dataReady) {
        // 主程式可以執行其他工作(如 Wi-Fi、顯示)
        return;
    }
    dataReady = false;

    // 讀取 FIFO 並解算(同上)
    fifoCount = mpu.getFIFOCount();
    if (fifoCount >= 42) {
        mpu.getFIFOBytes(fifoBuffer, 42);
        // 解算並輸出姿態
    }
}

實務注意事項

  • 電壓:MPU6050 僅支援 3.3V,接 5V 會燒毀!ESP32 的 3.3V 可直接供電
  • 冷啟動:第一次上電時 MPU6050 處於睡眠模式(PWR_MGMT_1 = 0x40),需寫入 0x00 喚醒
  • 陀螺儀零偏:開機後前幾秒的靜止資料平均可作為零偏補償,DMP 初始化時會自動校正
  • Yaw 飄移:陀螺儀有累積誤差,Yaw 會隨時間緩慢飄移。MPU6050 沒有磁力計,無法絕對校準 Yaw。如需要精確 Yaw,請選用 MPU9250(含磁力計)
  • 加速度計衝擊:加速度計對震動敏感,安裝時建議使用避震墊
  • 取樣率 vs DLPF:內部取樣率 1 kHz(加速度)/ 8 kHz(陀螺儀),透過 DLPF 可設定低通截止頻率(5~260 Hz)
  • FIFO 溢位:如果主控讀取太慢,FIFO 會溢位(overflow),需 reset FIFO 並重新開始

總結

MPU6050 是 CP 值最高的六軸 IMU 感測器,搭配 ESP32 的 I2C 介面和內建 DMP 硬體融合引擎,可在不佔用 CPU 資源的情況下即時輸出精確的 Roll/Pitch/Yaw 姿態資料。

選型參考:

  • 基礎傾角偵測:MPU6050 + 互補濾波器(程式簡單、適合入門)
  • 姿態即時追蹤:MPU6050 + DMP(硬體融合、不佔 CPU)
  • 精確 Yaw 與方向:MPU9250(含 AK8963 磁力計)或 ICM-20948
  • 機器人平衡車:MPU6050 + DMP + PID 控制(100 Hz 更新率已足夠)
  • 無人機飛控:MPU6000(SPI 介面、更低延遲)或 ICM-20602
標籤: 教學
最後更新:2026 年 6 月 17 日

shi6a

這個人很懶,什麼都沒留下

點贊
< 上一篇
下一篇 >

文章評論

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回覆

COPYRIGHT © 2026 0x6A Logbook. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang