电子元器件论坛
登录
直播中
blAckGe
3年用户
44经验值
擅长:电源/新能源 控制/MCU
私信
关注
mpu6050数据处理
开启该帖子的消息推送
MPU6050
GY521
Arduino
matlab
mpu6050向arduino传输数据,
matlab
通过串口再读取传感器数据。由于每次启动传感器会重新校准,导致每次传感器测得同一姿态、同一位置x y两个方向角的初始值都不一样,这就造成很大的麻烦:比如说,我测小车的底盘倾角有无变化,每次测初始值都不一样,那就没办法测了。不知道各位高人有什么解决思路,办法。
这个是arduino的代码
//连线方法
//MPU-UNO
//VCC-VCC
//GND-GND
//SCL-A5
//SDA-A4
//INT-2 (Op
ti
onal)
#include
#include
#include
float fRad2Deg = 57.295779513f; //将弧度转为角度的乘数
const int MPU = 0x68; //MPU-6050的I2C地址
const int nValCnt = 7; //一次读取寄存器的数量
const int nCalibTimes = 1000; //校准时读数的次数
int calibData[nValCnt]; //校准数据
unsigned long nLastTime = 0; //上一次读数的时间
float fLastRoll = 0.0f; //上一次滤波得到的Roll角
float fLastPitch = 0.0f; //上一次滤波得到的Pitch角
Kalman kalmanRoll; //Roll角滤波器
Kalman kalmanPitch; //Pitch角滤波器
void setup() {
Serial.begin(9600); //初始化串口,指定波特率
Wire.begin(); //初始化Wire库
WriteMPUReg(0x6B, 0); //启动MPU6050设备
Calibration(); //执行校准
nLastTime = micros(); //记录当前时间
}
void loop() {
int readouts[nValCnt];
ReadAccGyr(readouts); //读出测量值
float realVals[7];
Rectify(readouts, realVals); //根据校准的偏移量进行纠正
//计算加速度向量的模长,均以g为单位
float fNorm = sqrt(realVals[0] * realVals[0] + realVals[1] * realVals[1] + realVals[2] * realVals[2]);
float fRoll = GetRoll(realVals, fNorm); //计算Roll角
if (realVals[1] > 0) {
fRoll = -fRoll;
}
float fPitch = GetPitch(realVals, fNorm); //计算Pitch角
if (realVals[0] < 0) {
fPitch = -fPitch;
}
//计算两次测量的时间间隔dt,以秒为单位
unsigned long nCurTime = micros();
float dt = (double)(nCurTime - nLastTime) / 1000000.0;
//对Roll角和Pitch角进行卡尔曼滤波
float fNewRoll = kalmanRoll.getAngle(fRoll, realVals[4], dt);
float fNewPitch = kalmanPitch.getAngle(fPitch, realVals[5], dt);
//跟据滤波值计算角度速
float fRollRate = (fNewRoll - fLastRoll) / dt;
float fPitchRate = (fNewPitch - fLastPitch) / dt;
//更新Roll角和Pitch角
fLastRoll = fNewRoll;
fLastPitch = fNewPitch;
//更新本次测的时间
nLastTime = nCurTime;
//向串口打印输出Roll角和Pitch角,运行时在Arduino的串口监视器中查看
//Serial.print("Roll:");
Serial.println(fNewRoll); //Serial.print('(');
//Serial.print(fRollRate); //Serial.print("),tPitch:");
Serial.println(fNewPitch); //Serial.print('(');
//Serial.print(fPitchRate); //Serial.print(")n");
delay(100);
}
//向MPU6050写入一个字节的数据
//指定寄存器地址与一个字节的值
void WriteMPUReg(int nReg, unsigned char nVal) {
Wire.beginTransmission(MPU);
Wire.write(nReg);
Wire.write(nVal);
Wire.endTransmission(true);
}
//从MPU6050读出一个字节的数据
//指定寄存器地址,返回读出的值
unsigned char ReadMPUReg(int nReg) {
Wire.beginTransmission(MPU);
Wire.write(nReg);
Wire.requestFrom(MPU, 1, true);
Wire.endTransmission(true);
return Wire.read();
}
//从MPU6050读出加速度计三个分量、温度和三个角速度计
//保存在指定的数组中
void ReadAccGyr(int *pVals) {
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.requestFrom(MPU, nValCnt * 2, true);
Wire.endTransmission(true);
for (long i = 0; i < nValCnt; ++i) {
pVals[i] = Wire.read() << 8 | Wire.read();
}
}
//对大量读数进行统计,校准平均偏移量
void Calibration()
{
float valSums[7] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0};
//先求和
for (int i = 0; i < nCalibTimes; ++i) {
int mpuVals[nValCnt];
ReadAccGyr(mpuVals);
for (int j = 0; j < nValCnt; ++j) {
valSums[j] += mpuVals[j];
}
}
//再求平均
for (int i = 0; i < nValCnt; ++i) {
calibData[i] = int(valSums[i] / nCalibTimes);
}
calibData[2] += 16384; //设芯片Z轴竖直向下,设定静态工作点。
}
//算得Roll角。算法见文档。
float GetRoll(float *pRealVals, float fNorm) {
float fNormXZ = sqrt(pRealVals[0] * pRealVals[0] + pRealVals[2] * pRealVals[2]);
float fCos = fNormXZ / fNorm;
return acos(fCos) * fRad2Deg;
}
//算得Pitch角。算法见文档。
float GetPitch(float *pRealVals, float fNorm) {
float fNormYZ = sqrt(pRealVals[1] * pRealVals[1] + pRealVals[2] * pRealVals[2]);
float fCos = fNormYZ / fNorm;
return acos(fCos) * fRad2Deg;
}
//对读数进行纠正,消除偏移,并转换为物理量。公式见文档。
void Rectify(int *pReadout, float *pRealVals) {
for (int i = 0; i < 3; ++i) {
pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 16384.0f;
}
pRealVals[3] = pReadout[3] / 340.0f + 36.53;
for (int i = 4; i < 7; ++i) {
pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 131.0f;
}
}
这个是matlab的代码
clc;clear;
if~isempty(instrfind)
fclose(instrfind);
delete(instrfind);
end
global s;
s= serial('COM5');
set(s,'BaudRate',9600);
fopen(s);
t=1;T=500;
A=1;
amount=0;
while(t
a=str2double(fgetl(s));
figure(1);
A=[A,a];
plot(A);
grid;
t=t+1;
drawnow limitrate;
end
X_Pitch=A(1:2:end);
Y_Roll=A(2:2:end);
figure(2);
plot(X_Pitch);
figure(3);
plot(Y_Roll);
已退回
7
积分
回帖
(3)
chenwei6991627
2021-8-5 11:47:47
那把初始值去掉呢
那把初始值去掉呢
1
举报
blAckGe:
能力实在有限,代码不知何从下手,望指教
blAckGe
2021-8-6 09:36:25
如果想实现始终以地面为基准,像手机水平仪那样,那改进思路应该是怎样的呢
如果想实现始终以地面为基准,像手机水平仪那样,那改进思路应该是怎样的呢
举报
mm2mm2
2021-8-12 14:00:38
有点难看懂啊,学习
有点难看懂啊,学习
举报
更多回帖
rotate(-90deg);
回复
相关问答
MPU6050
GY521
Arduino
matlab
MPU6050
的
数据处理
2014-06-29
4736
mpu6050
零飘值太大
2019-05-14
4195
MPU6050
数据
偏差有点大,怎么消除?
2023-11-09
260
怎样去获取STM32
MPU6050
模块的
数据
呢
2021-11-15
1770
请问
mpu6050
如何知道物体是否移动?
2019-06-14
1746
mpu6050
dmp输出
2017-07-28
3988
MPU6050
的原始
数据
怎么
处理
能得到向x,y,z方向移动的距离?
2023-11-08
274
MPU6050
芯片的特点有哪些
2021-10-14
2378
mpu6050
计算角度
2014-12-28
18909
加定时器影响
mpu6050
怎么
处理
2019-03-06
1851
发帖
登录/注册
20万+
工程师都在用,
免费
PCB检查工具
无需安装、支持浏览器和手机在线查看、实时共享
查看
点击登录
登录更多精彩功能!
首页
论坛版块
小组
免费开发板试用
ebook
直播
搜索
登录
×
20
完善资料,
赚取积分