智能手表:MPU6050和水平仪,动态表情包
MPU6050
一,姿态解算
1.简介
2.计算
陀螺仪优点:响应快(能实时跟踪姿态变化)
陀螺仪缺点:长期漂移(积分误差会累积)
为什么漂移
陀螺仪在测量角速度时,存在细小的误差,yaw[k]=yaw[k-1]+gz*Delta_t ,每次 gz 的误差经积分积累,随时间推移,计算角度会大幅偏离真实值,产生漂移
加速度计优点:无长期漂移(靠重力参考,角度计算不累积误差)
加速度计缺点:高频噪声大(运动冲击、振动会让加速度计输出跳变)
加速度计,只能计算Roll、Pitch的值
Yaw是绕z轴旋转,ax,ay等于0,az总是等于9.8,无法计算Yaw
3.滤波器解决方法
陀螺仪数据(高频信号)通过低通滤波,保留其动态响应好的特性
陀螺仪擅长 短期动态(α 大负责 “跟得上运动”) 把噪声屏蔽掉
加速度计数据(低频信号)通过高通滤波,利用其无累积误差的特性
加速度计擅长 长期校准(α 小负责 “纠正漂移”)把漂移除去
融合公式:最终角度 = a×陀螺仪角度 + (1-a)×加速度计角度
当α等于0.9时,漂移基本消失,噪声不明显
4,程序
1.先计算欧拉角
int16_t ax,ay,az,gx,gy,gz;//MPU6050测得的三轴加速度,角速度
float roll_g,pitch_g,yaw_g;//陀螺仪解算的欧拉角
float roll_a,pitch_a;//加速度计解算的欧拉角
float Roll,Pitch,Yaw;//互补滤波后的欧拉角
float a=0.9;//互补滤波器系数
float Delta_t=0.005;//采样周期
double pi=3.1415927;
void MPU6050_Calculation(void)
{Delay_ms(5);MPU6050_GetData(&ax,&ay,&az,&gx,&gy,&gz);//陀螺仪解算的欧拉角roll_g= Roll+(float)gx*Delta_t;//用互补滤波后的欧拉角,这样误差就能及时修正pitch_g=Pitch+(float)gy*Delta_t;yaw_g=Yaw+(float)gz*Delta_t;//加速度计解算的欧拉角pitch_a=atan2((-1)*ax,az)*180/pi;roll_a=atan2(ay,az)*180/pi;//互补滤波后的欧拉角Roll=a*roll_g+(1-a)*roll_a;Pitch=a*pitch_g+(1-a)*pitch_a;Yaw=a*yaw_g;}
先读取三轴加速度和角速度,用陀螺仪积分计算角度(roll_g、pitch_g、yaw_g),用加速度计通过反正切函数解算角度(roll_a、pitch_a),最后按 0.9:0.1 的比例融合得到最终姿态角(Roll、Pitch、Yaw),采样周期 5ms。
2.欧拉角页面
void Show_MPU6050_UI(void)
{OLED_ShowImage(0,0,16,16,Return);OLED_Printf(0,16,OLED_8X16,"Roll:%.2f",Roll);OLED_Printf(0,32,OLED_8X16,"Pitch:%.2f",Pitch);OLED_Printf(0,48,OLED_8X16,"Yaw:%.2f",Yaw);
}
3.应用
int MPU6050(void)
{while(1){KeyNum=Key_GetNum();if(KeyNum==3){OLED_Clear();OLED_Update();return 0;}OLED_Clear();MPU6050_Calculation();Show_MPU6050_UI();OLED_ReverseArea(0,0,16,16);OLED_Update();}
}
二,水平仪
基于 MPU6050 的水平仪实现:让小球随姿态灵动 “滚动”
借助 MPU6050 传感器获取设备的欧拉角(反映姿态倾斜状态 ),结合 OLED 屏幕,在屏幕上呈现一个 “水平仪” 场景:小球初始坐标设为 (64, 32) ,会依据设备实际晃动产生的姿态变化(由 MPU6050 测得欧拉角体现 ),在屏幕上模拟出相应方向的移动,就像真实小球在倾斜平面滚动,直观呈现设备姿态。
程序
代码实现了一个基础的水平仪功能:Show_Gradienter_UI
函数通过 MPU6050 获取姿态数据,在 OLED 屏幕中心绘制半径 30 的圆形外框,并根据 Roll/Pitch 角度在 (64-Roll, 32+Pitch) 位置绘制半径 4 的小球,模拟水平仪效果;Gradienter
主循环实时刷新界面,检测到按键 3 按下则清屏退出,实现了姿态可视化与基本交互控制。
void Show_Gradienter_UI(void)
{MPU6050_Calculation();OLED_DrawCircle(64,32,30,0); //绘制外面的圆框OLED_DrawCircle(64-Roll,32+Pitch,4,1); //绘制小球
}int Gradienter(void)
{while(1){KeyNum=Key_GetNum();if(KeyNum==3){OLED_Clear();OLED_Update();return 0;}OLED_Clear();Show_Gradienter_UI();OLED_Update();}
}
三:动态表情包
通过调用绘制椭圆的函数,实现眼睛的图案
调用for循环实现眼睛的睁眼,闭眼