ESP32-WROOM-32 + MPU6050 获取设备姿态信息(Arduino-CLI 版)

📌 本文档适用于 树莓派 上通过 arduino-cli 构建 ESP32-WROOM-32 + MPU6050 项目。


📋 目录


1. 硬件连接

MPU6050 引脚 ESP32-WROOM-32 引脚
VCC 3.3V
GND GND
SCL GPIO22(I2C SCL)
SDA GPIO21(I2C SDA)
INT GPIO16(中断引脚)
AD0 GND(I2C地址0x68)

✅ 注意:ESP32 的 I2C 引脚可自定义,默认使用 GPIO21(SDA)和 GPIO22(SCL)。


2. 安装 arduino-cli 和 ESP32 开发环境

# 安装 arduino-cli
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh

# 添加到环境变量
echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc
source ~/.bashrc

# 初始化配置
arduino-cli config init
arduino-cli core update-index

# 安装 ESP32 开发板支持
arduino-cli core install esp32:esp32

3. 安装依赖库

# 安装库
arduino-cli lib install "I2Cdevlib-MPU6050"

⚠️ 若无法通过 arduino-cli lib install 安装,可手动下载:

bash cd ~/Arduino/libraries git clone https://github.com/jrowberg/i2cdevlib mv i2cdevlib/Arduino/I2Cdev . mv i2cdevlib/Arduino/MPU6050 .


4. 创建 Arduino Sketch 项目

创建项目目录:

mkdir -p ~/esp32_mpu6050_dmp
cd ~/esp32_mpu6050_dmp

创建主文件:esp32_mpu6050_dmp.ino

#include <Arduino.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"

#define INTERRUPT_PIN 16

MPU6050 mpu;
volatile bool mpuInterrupt = false;
bool dmpReady = false;
uint8_t mpuIntStatus;
uint8_t devStatus;
uint16_t packetSize;
uint8_t fifoBuffer[64];

Quaternion q;
VectorFloat gravity;
float ypr[3]; // [yaw, pitch, roll]

void IRAM_ATTR dmpDataReady() {
    mpuInterrupt = true;
}

void setup() {
    Serial.begin(115200);
    Wire.begin(21, 22);
    Wire.setClock(400000);

    mpu.initialize();
    if (!mpu.testConnection()) {
        Serial.println("MPU6050连接失败!");
        while (1);
    }

    devStatus = mpu.dmpInitialize();
    if (devStatus != 0) {
        Serial.printf("DMP初始化失败,状态码:%d\n", devStatus);
        while (1);
    }

    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1788);

    mpu.CalibrateAccel(6);
    mpu.CalibrateGyro(6);
    mpu.setDMPEnabled(true);

    pinMode(INTERRUPT_PIN, INPUT);
    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();
    dmpReady = true;
    packetSize = mpu.dmpGetFIFOPacketSize();

    Serial.println("ESP32 + MPU6050 DMP 初始化完成!");
}

void loop() {
    if (!dmpReady) return;

    if (!mpuInterrupt && fifoCount < packetSize) return;

    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    uint16_t fifoCount = mpu.getFIFOCount();

    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        mpu.resetFIFO();
        Serial.println("FIFO溢出!");
        return;
    }

    if (mpuIntStatus & 0x02) {
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;

        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);

        Serial.print("Yaw: "); Serial.print(ypr[0] * 180/M_PI);
        Serial.print(" Pitch: "); Serial.print(ypr[1] * 180/M_PI);
        Serial.print(" Roll: "); Serial.println(ypr[2] * 180/M_PI);
    }
}

5. 编译并上传代码

# 编译
arduino-cli compile --fqbn esp32:esp32:esp32 esp32_mpu6050_dmp

# 上传(替换为你的串口)
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32 esp32_mpu6050_dmp

6. 查看输出结果

打开串口监视器:

arduino-cli monitor -p /dev/ttyUSB0 -c baudrate=115200

示例输出

Yaw: -12.34 Pitch: 45.67 Roll: -3.21

7. 常见问题排查

问题 解决方案
上传失败 按住 BOOT 键再上电,进入下载模式
I2C 地址不对 AD0 接 GND 为 0x68,接 VCC 为 0x69
FIFO 溢出 检查中断引脚连接,确保中断服务函数已注册
数据不稳定 确保 MPU6050 固定牢靠,必要时重新校准

8. 进阶建议

  • 姿态融合优化:使用 MahonyMadgwick 滤波算法,提升动态精度。
  • 无线传输:利用 ESP32 的 WiFi 或蓝牙功能,将姿态数据发送到手机或服务器。
  • 三维可视化:使用 ProcessingUnity 接收串口数据,实时显示 3D 模型。