MPU6050 是一个集成了三轴陀螺仪和三轴加速度计的惯性测量单元(IMU),常用来测量角度和角速度。
计算 MPU6050 的姿态角度(如俯仰角 Pitch、横滚角 Roll)主要有两种常用方法:


1. 利用加速度计计算角度(静态)

加速度计测量的是重力分量,根据加速度在各轴上的分量计算俯仰角和横滚角:

  • 俯仰角 Pitch:

Pitch=arctan⁡(axay2+az2)×180π

  • 横滚角 Roll:

Roll=arctan⁡(ayax2+az2)×180π

其中 ax,ay,az 是加速度计在三个轴上的读数(单位一般是 g)。


2. 利用陀螺仪积分角度(动态)

陀螺仪给出角速度 ωx,ωy,ωz,通过积分角速度计算角度:θ(t)=θ(t−1)+ω×Δt

但是陀螺仪有漂移,积分误差会累积。


3. 结合加速度计和陀螺仪 — 卡尔曼滤波或互补滤波

为克服加速度计受加速度影响大,陀螺仪漂移问题,通常采用滤波算法:

  • 互补滤波(简单实现):

Angle=α×(Angle+ω×Δt)+(1−α)×AccAngle

α 一般取 0.95 左右。


4. 示例代码(Arduino 风格 C++)

#include <Wire.h>
#include <MPU6050.h>

MPU6050 mpu;

float gyroAngleX, gyroAngleY, gyroAngleZ;
float accAngleX, accAngleY;
float pitch, roll;

unsigned long timer;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  mpu.initialize();
  timer = millis();
}

void loop() {
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  // 加速度计角度
  accAngleX = atan2(ay, az) * 180 / PI;
  accAngleY = atan2(-ax, sqrt(ay * ay + az * az)) * 180 / PI;

  // 计算陀螺仪角度增量
  float dt = (millis() - timer) / 1000.0;
  timer = millis();
  
  gyroAngleX += gx * dt / 131.0; // 陀螺仪灵敏度调整(假设±250度/秒)
  gyroAngleY += gy * dt / 131.0;

  // 互补滤波
  pitch = 0.98 * (pitch + gyroAngleX * dt) + 0.02 * accAngleX;
  roll = 0.98 * (roll + gyroAngleY * dt) + 0.02 * accAngleY;

  Serial.print("Pitch: "); Serial.print(pitch);
  Serial.print(" Roll: "); Serial.println(roll);

  delay(10);
}

5. 总结

  • 加速度计角度适合静态测量,噪声较大;
  • 陀螺仪积分角度适合短时间动态,但会漂移;
  • 互补滤波结合两者优点,实用性好;
  • 如果要求更高精度,考虑卡尔曼滤波或使用 MPU6050 内部 DMP(数字运动处理器);

下面给你一个 Python 版的 MPU6050 角度计算示例,包含加速度计、陀螺仪读数解析,结合互补滤波计算俯仰角 Pitch 和横滚角 Roll。


Python 示例(使用 smbus2 读取 MPU6050)

import smbus2
import time
import math

# MPU6050寄存器地址
MPU6050_ADDR = 0x68
PWR_MGMT_1 = 0x6B
ACCEL_XOUT_H = 0x3B
GYRO_XOUT_H = 0x43

bus = smbus2.SMBus(1)  # 树莓派I2C bus编号通常是1

# 初始化MPU6050
bus.write_byte_data(MPU6050_ADDR, PWR_MGMT_1, 0)

def read_word(reg):
    high = bus.read_byte_data(MPU6050_ADDR, reg)
    low = bus.read_byte_data(MPU6050_ADDR, reg + 1)
    val = (high << 8) + low
    if val >= 0x8000:
        val = -((65535 - val) + 1)
    return val

def get_accel_data():
    ax = read_word(ACCEL_XOUT_H)
    ay = read_word(ACCEL_XOUT_H + 2)
    az = read_word(ACCEL_XOUT_H + 4)
    return ax, ay, az

def get_gyro_data():
    gx = read_word(GYRO_XOUT_H)
    gy = read_word(GYRO_XOUT_H + 2)
    gz = read_word(GYRO_XOUT_H + 4)
    return gx, gy, gz

# 互补滤波参数
alpha = 0.98
dt = 0.01  # 10ms采样间隔
pitch = 0.0
roll = 0.0

try:
    while True:
        ax, ay, az = get_accel_data()
        gx, gy, gz = get_gyro_data()

        # 加速度计转为g值
        ax /= 16384.0
        ay /= 16384.0
        az /= 16384.0

        # 陀螺仪转为角速度 (deg/s),灵敏度为±250度/s,16.4 LSB/deg/s
        gx /= 131.0
        gy /= 131.0
        gz /= 131.0

        # 计算加速度计角度 (单位:度)
        acc_pitch = math.degrees(math.atan2(ay, math.sqrt(ax*ax + az*az)))
        acc_roll = math.degrees(math.atan2(-ax, az))

        # 互补滤波计算角度
        pitch = alpha * (pitch + gx * dt) + (1 - alpha) * acc_pitch
        roll = alpha * (roll + gy * dt) + (1 - alpha) * acc_roll

        print(f"Pitch: {pitch:.2f}  Roll: {roll:.2f}")

        time.sleep(dt)
except KeyboardInterrupt:
    print("结束")

说明:

  • 读取加速度计和陀螺仪原始数据,并换算成实际单位;
  • 采用简单互补滤波公式融合两种传感器数据;
  • 采样间隔 dt 根据实际硬件设定(这里是10毫秒);
  • 运行环境需要有 I2C 接口和 MPU6050 硬件支持,如树莓派。

如果你想要:

  • C++ / Arduino 版本代码;
  • Java 版本算法实现;
  • 或更复杂的卡尔曼滤波方案;

告诉我,我可以帮你继续提供。