1. MPU6050原始数据读取与校准

MPU6050原始数据读取与校准 学习卡片

任务与环境

目标:通过 I2C 读取 MPU6050 的加速度计、陀螺仪原始值,并完成零偏校准与温度补偿。硬件:MPU6050(地址 0x68)、MCU 或 Linux 主机 I2C 总线。依赖:C 语言 + linux/i2c-dev.h(Linux 用户态 I2C),无需额外库。

关键寄存器:0x6B PWR_MGMT_1(唤醒)、0x1C ACCEL_CONFIG、0x1B GYRO_CONFIG、0x3B 起 14 字节数据(加速度 6 + 温度 2 + 陀螺仪 6)、0x41/0x43 温度与陀螺仪零偏寄存器。

数据流与校准关系

I2C 读 0x3B 14 字节 加速度 raw ax ay az 温度 raw T = raw/340+36.53 陀螺仪 raw gx gy gz 零偏校准 g - bias 温度补偿 输出

完整实现

#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <math.h>

#define ADDR 0x68
static int fd;

static int wr(uint8_t reg, uint8_t val){
    uint8_t b[2] = {reg, val};
    return write(fd, b, 2) == 2 ? 0 : -1;
}
static int rd(uint8_t reg, uint8_t *buf, int n){
    if (write(fd, &reg, 1) != 1) return -1;
    return read(fd, buf, n) == n ? 0 : -1;
}
static int16_t be16(uint8_t *p){ return (int16_t)((p[0] << 8) | p[1]); }

/* 读取原始数据:ax,ay,az,gx,gy,gz,temp_raw */
static int read_raw(int16_t *ax,int16_t *ay,int16_t *az,
                    int16_t *gx,int16_t *gy,int16_t *gz,int16_t *tr){
    uint8_t b[14];
    if (rd(0x3B, b, 14)) return -1;
    *ax = be16(b+0); *ay = be16(b+2); *az = be16(b+4);
    *tr = be16(b+6);
    *gx = be16(b+8); *gy = be16(b+10); *gz = be16(b+12);
    return 0;
}

/* 零偏校准:静止采样 N 次求均值 */
static void calibrate(int n, double *bx,double *by,double *bz){
    double sx=0, sy=0, sz=0;
    int16_t ax,ay,az,gx,gy,gz,tr;
    for (int i=0;i<n;i++){
        read_raw(&ax,&ay,&az,&gx,&gy,&gz,&tr);
        sx+=gx; sy+=gy; sz+=gz;
        usleep(2000);
    }
    *bx=sx/n; *by=sy/n; *bz=sz/n;
}

int main(int argc, char **argv){
    const char *dev = argc>1 ? argv[1] : "/dev/i2c-1";
    fd = open(dev, O_RDWR);
    if (fd < 0 || ioctl(fd, I2C_SLAVE, ADDR) < 0){ perror("i2c"); return 1; }

    wr(0x6B, 0x00);          /* 唤醒 */
    wr(0x1C, 0x00);          /* ±2g */
    wr(0x1B, 0x00);          /* ±250 dps */
    usleep(50000);

    double bx,by,bz;
    calibrate(200, &bx,&by,&bz);   /* 保持静止 */
    printf("gyro bias: %.2f %.2f %.2f\n", bx,by,bz);

    int16_t ax,ay,az,gx,gy,gz,tr;
    for (int i=0;i<5;i++){
        if (read_raw(&ax,&ay,&az,&gx,&gy,&gz,&tr)) break;
        double T = tr/340.0 + 36.53;                 /* 温度补偿 */
        double gxs = (gx-bx)/131.0;                  /* 去零偏 + 转 dps */
        double gys = (gy-by)/131.0;
        double gzs = (gz-bz)/131.0;
        printf("T=%.2fC ax=%.3fg ay=%.3fg az=%.3fg gx=%.3f gy=%.3f gz=%.3f dps\n",
               T, ax/16384.0, ay/16384.0, az/16384.0, gxs, gys, gzs);
        usleep(200000);
    }
    close(fd);
    return 0;
}

编译与运行

gcc mpu6050.c -o mpu6050 -lm
./mpu6050 /dev/i2c-1

若使用树莓派需先启用 I2C:sudo raspi-config → Interface → I2C,并用 i2cdetect -y 1 确认 0x68 出现。

验证与判定

  • 程序启动后先打印 gyro bias 三个值,校准期间传感器必须静止。
  • 随后 5 行输出中,静止时 az≈1.000g、ax/ay≈0,三轴角速度接近 0 dps,即判定校准与温度补偿生效。
  • 温度 T 应接近室温(约 20~30℃),若明显偏离说明温度寄存器解析或量程配置有误。
  • 若 i2c 报错,检查设备节点、接线(SDA/SCL/GND/VCC)与地址。