查看: 181|回复: 0
打印 上一主题 下一主题

[经验] 零知开源——ESP8266+MPU6050 实现运动姿态检测

[复制链接]

该用户从未签到

跳转到指定楼层
楼主
发表于 2025-2-21 11:24:20 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
分享到:
零知ESP8266学习教程
   在运动姿态检测、机器人平衡控制、VR头戴设备等应用中,MPU6050(三轴加速度计+三轴陀螺仪)是一个常见的姿态传感器。而ESP8266作为一款低功耗Wi-Fi模块,可以实现数据无线传输,将姿态数据上传至服务器或云端,便于实时监测。

   然而,MPU6050 没有磁力计,直接使用陀螺仪的角速度积分计算yaw角(航向角)会导致累积漂移。本次实验采用优化后的互补滤波,减少漂移,提高yaw角的计算精度。



一、硬件连接
   MPU6050模块采用I2C通信连接到零知ESP8266开发板

1.所需材料:
零知ESP8266
MPU6050姿态检测传感器
跳线

2.硬件连接示意图:
零知ESP8266
MPU6050
3.3V
VCC
GND
GND
SCL
SCL
SDA
SDA

二、代码实现 1.头文件及变量定义
通过MPU6050库与传感器交互
使用yaw_integral变量累积航向角
previousTime变量用于计算时间间隔dt

  1. #include "MPU6050.h"

  2. MPU6050 accelgyro;

  3. int16_t ax, ay, az;
  4. int16_t gx, gy, gz;

  5. float nax, nay, naz;
  6. float ngx, ngy, ngz;

  7. float roll, pitch, yaw;
  8. float yaw_integral = 0.0f;  // 累积 yaw 角
  9. unsigned long previousTime = 0;  // 记录上一帧的时间

  10. // 校准值
  11. int16_t ax_offset = 0, ay_offset = 0, az_offset = 0;
  12. int16_t gx_offset = 0, gy_offset = 0, gz_offset = 0;

  13. #define LED_PIN LED_BUILTIN
复制代码

2.初始化MPU6050
设置ESP8266 I2C端口SDA、SCL
初始化MPU6050并进行连接测试
校准传感器,减少偏差
设置50Hz采样率和±2000°/s陀螺仪量程

  1. void setup() {
  2.     Serial.begin(9600);

  3.     // MPU6050 初始化
  4.     Serial.println("Initializing I2C devices...");
  5.     accelgyro.initialize();

  6.     // 检测 MPU6050 是否连接成功
  7.     Serial.println("Testing device connections...");
  8.     if (accelgyro.testConnection()) {
  9.         Serial.println("MPU6050 connection successful");
  10.     } else {
  11.         Serial.println("MPU6050 connection failed");
  12.     }

  13.     // 传感器校准
  14.     calibrateSensors();

  15.     // 设置 MPU6050 的采样率和陀螺仪的量程
  16.     accelgyro.setRate(50);  // 采样率 50Hz
  17.     accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_2000);  // 陀螺仪量程 ±2000°/s

  18.     // LED 指示灯
  19.     pinMode(LED_PIN, OUTPUT);

  20.     // 记录起始时间
  21.     previousTime = millis();
  22. }
复制代码

3.获取MPU6050数据
获取加速度计&陀螺仪原始数据
减去偏移量,提高数据精度
归一化数据,提高计算稳定性
调用complementaryFilter()计算姿态角
串口打印姿态角数据

  1. void loop() {
  2.     // 获取原始数据
  3.     accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  4.     // 减去偏移量
  5.     ax -= ax_offset;
  6.     ay -= ay_offset;
  7.     az -= az_offset;
  8.     gx -= gx_offset;
  9.     gy -= gy_offset;
  10.     gz -= gz_offset;

  11.     // 读取归一化数据
  12.     accelgyro.readNormalizeAccel(&nax, &nay, &naz);
  13.     accelgyro.readNormalizeGyro(&ngx, &ngy, &ngz);

  14.     // 计算姿态角
  15.     complementaryFilter();

  16.     // 打印姿态角
  17.     Serial.print("Roll: ");
  18.     Serial.print(roll);
  19.     Serial.print(" Pitch: ");
  20.     Serial.print(pitch);
  21.     Serial.print(" Yaw: ");
  22.     Serial.println(yaw);

  23.     delay(10);
  24. }
复制代码

4.传感器校准
采集100组数据,计算平均值作为偏移量
过滤MPU6050启动时的零偏误差
减少环境噪声对传感器的影响

  1. // 传感器校准
  2. void calibrateSensors() {
  3.     int num_readings = 100;
  4.     for (int i = 0; i < num_readings; i++) {
  5.         accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  6.         ax_offset += ax;
  7.         ay_offset += ay;
  8.         az_offset += az;
  9.         gx_offset += gx;
  10.         gy_offset += gy;
  11.         gz_offset += gz;
  12.         delay(50);
  13.     }
  14.     ax_offset /= num_readings;
  15.     ay_offset /= num_readings;
  16.     az_offset /= num_readings;
  17.     gx_offset /= num_readings;
  18.     gy_offset /= num_readings;
  19.     gz_offset /= num_readings;
  20. }
复制代码

5.互补滤波计算姿态角
计算dt(时间间隔),用于陀螺仪积分计算 yaw

roll和 pitch 采用加速度计计算:
yaw采用 陀螺仪积分计算并限制范围 [-180, 180]
yaw=0.98*yaw_integral+0.02*yaw进行互补滤波,减少漂移

  1. // 互补滤波计算姿态角
  2. void complementaryFilter() {
  3.     // 计算时间间隔 dt(单位:秒)
  4.     unsigned long currentTime = millis();
  5.     float dt = (currentTime - previousTime) / 1000.0;  // ms 转换为 s
  6.     previousTime = currentTime;

  7.     // 计算 Roll 和 Pitch
  8.     roll = atan2(nay, naz) * 180 / M_PI;
  9.     pitch = atan2(-nax, sqrt(nay * nay + naz * naz)) * 180 / M_PI;

  10.     // 陀螺仪角速度转换
  11.     float gyroYawRate = ngz;  // 直接使用归一化后的 ngz(角速度 deg/s)

  12.     // 计算 Yaw (积分计算)
  13.     yaw_integral += gyroYawRate * dt;  // 积分计算 yaw
  14.     yaw_integral = fmod(yaw_integral + 180, 360) - 180;  // 限制 yaw 在 [-180, 180] 之间

  15.     // 互补滤波减少漂移影响
  16.     yaw = 0.98 * yaw_integral + 0.02 * yaw;  // 0.98 和 0.02 为滤波系数
  17. }
复制代码
6.完整代码

  1. #include "MPU6050.h"

  2. MPU6050 accelgyro;

  3. int16_t ax, ay, az;
  4. int16_t gx, gy, gz;

  5. float nax, nay, naz;
  6. float ngx, ngy, ngz;

  7. float roll, pitch, yaw;
  8. float yaw_integral = 0.0f;  // 累积 yaw 角
  9. unsigned long previousTime = 0;  // 记录上一帧的时间

  10. // 校准值
  11. int16_t ax_offset = 0, ay_offset = 0, az_offset = 0;
  12. int16_t gx_offset = 0, gy_offset = 0, gz_offset = 0;

  13. #define LED_PIN LED_BUILTIN

  14. void setup() {
  15.     Serial.begin(9600);

  16.     // MPU6050 初始化
  17.     Serial.println("Initializing I2C devices...");
  18.     accelgyro.initialize();

  19.     // 检测 MPU6050 是否连接成功
  20.     Serial.println("Testing device connections...");
  21.     if (accelgyro.testConnection()) {
  22.         Serial.println("MPU6050 connection successful");
  23.     } else {
  24.         Serial.println("MPU6050 connection failed");
  25.     }

  26.     // 传感器校准
  27.     calibrateSensors();

  28.     // 设置 MPU6050 的采样率和陀螺仪的量程
  29.     accelgyro.setRate(50);  // 采样率 50Hz
  30.     accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_2000);  // 陀螺仪量程 ±2000°/s

  31.     // LED 指示灯
  32.     pinMode(LED_PIN, OUTPUT);

  33.     // 记录起始时间
  34.     previousTime = millis();
  35. }

  36. void loop() {
  37.     // 获取原始数据
  38.     accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

  39.     // 减去偏移量
  40.     ax -= ax_offset;
  41.     ay -= ay_offset;
  42.     az -= az_offset;
  43.     gx -= gx_offset;
  44.     gy -= gy_offset;
  45.     gz -= gz_offset;

  46.     // 读取归一化数据
  47.     accelgyro.readNormalizeAccel(&nax, &nay, &naz);
  48.     accelgyro.readNormalizeGyro(&ngx, &ngy, &ngz);

  49.     // 计算姿态角
  50.     complementaryFilter();

  51.     // 打印姿态角
  52.     Serial.print("Roll: ");
  53.     Serial.print(roll);
  54.     Serial.print(" Pitch: ");
  55.     Serial.print(pitch);
  56.     Serial.print(" Yaw: ");
  57.     Serial.println(yaw);

  58.     delay(10);
  59. }

  60. // 传感器校准
  61. void calibrateSensors() {
  62.     int num_readings = 100;
  63.     for (int i = 0; i < num_readings; i++) {
  64.         accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  65.         ax_offset += ax;
  66.         ay_offset += ay;
  67.         az_offset += az;
  68.         gx_offset += gx;
  69.         gy_offset += gy;
  70.         gz_offset += gz;
  71.         delay(50);
  72.     }
  73.     ax_offset /= num_readings;
  74.     ay_offset /= num_readings;
  75.     az_offset /= num_readings;
  76.     gx_offset /= num_readings;
  77.     gy_offset /= num_readings;
  78.     gz_offset /= num_readings;
  79. }

  80. // 互补滤波计算姿态角
  81. void complementaryFilter() {
  82.     // 计算时间间隔 dt(单位:秒)
  83.     unsigned long currentTime = millis();
  84.     float dt = (currentTime - previousTime) / 1000.0;  // ms 转换为 s
  85.     previousTime = currentTime;

  86.     // 计算 Roll 和 Pitch
  87.     roll = atan2(nay, naz) * 180 / M_PI;
  88.     pitch = atan2(-nax, sqrt(nay * nay + naz * naz)) * 180 / M_PI;

  89.     // 陀螺仪角速度转换
  90.     float gyroYawRate = ngz;  // 直接使用归一化后的 ngz(角速度 deg/s)

  91.     // 计算 Yaw (积分计算)
  92.     yaw_integral += gyroYawRate * dt;  // 积分计算 yaw
  93.     yaw_integral = fmod(yaw_integral + 180, 360) - 180;  // 限制 yaw 在 [-180, 180] 之间

  94.     // 互补滤波减少漂移影响
  95.     yaw = 0.98 * yaw_integral + 0.02 * yaw;  // 0.98 和 0.02 为滤波系数
  96. }
复制代码

   将上述代码移植到零知开源平台,选择连接的端口编译并上传到零知ESP8266。

三、实验结果
   点击零知开源平台调试按钮,打开零知开源平台的串口监视器,设置波特率为9600,观察串口打印测量到的MPU6050姿态角。

使用vofa+上位机效果:

VOFA+上位机获取MPU6050运动姿态


本人才疏学浅,有错误或遗漏的部分欢迎大家探讨学习!

回复

举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 2/4 下一条

【预约|参会享"豪"礼】2025慕尼黑上海设备展
“2025慕尼黑上海电子生产设备展”将于2025年03月26-28日上海新国际博览中心开幕诚邀您的光临!

查看 »



手机版|小黑屋|与非网

GMT+8, 2025-4-15 13:51 , Processed in 0.118503 second(s), 19 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.5

Copyright © 2001-2024, Tencent Cloud.