在本教程中,我们将学习如何将MPU6050加速计和陀螺仪传感器与Arduino一起使用。首先,我将解释MPU6050如何工作以及如何从中读取数据,然后我们将制作两个实际示例。
概述
在第一个示例中,使用Processing开发环境,我们将制作一个传感器方向的三维可视化,在第二个示例中,我们将制作一个简单的自稳定平台或DIY的万向节。基于MPU6050定位系统及其融合的加速度计和陀螺仪数据,控制了三个保持平台水平的伺服系统。
betway
MPU6050 IMU集成了三轴加速度计和三轴陀螺仪。
陀螺仪测量旋转速度或角位置随时间的变化率,沿着X, Y和Z轴。它使用MEMS技术和科里奥利效应进行测量,但更多的细节,你可以查看我的特别MEMS传感器如何工作教程.陀螺仪的输出单位是度/秒,为了得到角位置,我们只需要对角速度积分。
另一方面,MPU6050加速度计测量加速度的方式与之前的视频中解释的相同ADXL345加速度计传感器.简单地说,它可以测量沿3轴的重力加速度,并使用一些三角数学,我们可以计算传感器的位置的角度。所以,如果我们融合,或者把加速度计和陀螺仪的数据结合起来,我们就可以得到关于传感器方向的非常精确的信息。
MPU6050 IMU也被称为六轴运动跟踪设备或六自由度(六自由度)设备,因为它有6个输出,或3个加速度计输出和3个陀螺仪输出。
Arduino和MPU6050
让我们看看如何使用Arduino连接和读取MPU6050传感器的数据。我们使用的是I2C协议与Arduino通信,所以连接Arduino只需要两根线,再加上供电的两根线。
你可以从下面的链接获得这个Arduino教程所需的组件:
- MPU6050 IMU…………………………。。…。亚马逊/Banggood/阿里巴巴全球速卖通
- Arduino电路板 ....................................亚马逊/Banggood/阿里巴巴全球速卖通
- 面包板和跳线............亚马逊/Banggood/阿里巴巴全球速卖通
必威外围提钱披露:这些是附属链接。作为一个亚马逊助理,我从合格的购买中赚取。
MPU6050 Arduino代码
这是读取MPU6050传感器数据的Arduino代码。在代码下面你可以找到它的详细描述。
/ * Arduino和MPU6050加速度计和陀螺仪传感器教程由Dejan,//www.mfxpo.com * / #includeconst int mpu = 0x68;// MPU6050 I2C地址浮动ACCX,ACCY,ACCZ;Float Gyrox,Gyroy,Gyroz;浮动装甲,加兰克利,Gyroanglex,Gyroangley,Gyroanglez;浮动卷,沥青,偏航;Float Accerrorx,Accerry,Gyroerrorx,Gyroerrany,Gyroerrorz;浮动闪光时间,本期,先发风仪;int c = 0;void setup(){serial.begin(19200);Wire.begin(); // Initialize comunication Wire.beginTransmission(MPU); // Start communication with MPU6050 // MPU=0x68 Wire.write(0x6B); // Talk to the register 6B Wire.write(0x00); // Make reset - place a 0 into the 6B register Wire.endTransmission(true); //end the transmission /* // Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g) Wire.beginTransmission(MPU); Wire.write(0x1C); //Talk to the ACCEL_CONFIG register (1C hex) Wire.write(0x10); //Set the register bits as 00010000 (+/- 8g full scale range) Wire.endTransmission(true); // Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s) Wire.beginTransmission(MPU); Wire.write(0x1B); // Talk to the GYRO_CONFIG register (1B hex) Wire.write(0x10); // Set the register bits as 00010000 (1000deg/s full scale) Wire.endTransmission(true); delay(20); */ // Call this function if you need to get the IMU error values for your module calculate_IMU_error(); delay(20); } void loop() { // === Read acceleromter data === // Wire.beginTransmission(MPU); Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission(false); Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers //For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis value // Calculating Roll and Pitch from the accelerometer data accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58) // === Read gyroscope data === // previousTime = currentTime; // Previous time is stored before the actual time read currentTime = millis(); // Current time actual time read elapsedTime = (currentTime - previousTime) / 1000; // Divide by 1000 to get seconds Wire.beginTransmission(MPU); Wire.write(0x43); // Gyro data first register address 0x43 Wire.endTransmission(false); Wire.requestFrom(MPU, 6, true); // Read 4 registers total, each axis value is stored in 2 registers GyroX = (Wire.read() << 8 | Wire.read()) / 131.0; // For a 250deg/s range we have to divide first the raw value by 131.0, according to the datasheet GyroY = (Wire.read() << 8 | Wire.read()) / 131.0; GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0; // Correct the outputs with the calculated error values GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56) GyroY = GyroY - 2; // GyroErrorY ~(2) GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8) // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg gyroAngleY = gyroAngleY + GyroY * elapsedTime; yaw = yaw + GyroZ * elapsedTime; // Complementary filter - combine acceleromter and gyro angle values roll = 0.96 * gyroAngleX + 0.04 * accAngleX; pitch = 0.96 * gyroAngleY + 0.04 * accAngleY; // Print the values on the serial monitor Serial.print(roll); Serial.print("/"); Serial.print(pitch); Serial.print("/"); Serial.println(yaw); } void calculate_IMU_error() { // We can call this funtion in the setup section to calculate the accelerometer and gyro data error. From here we will get the error values used in the above equations printed on the Serial Monitor. // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values // Read accelerometer values 200 times while (c < 200) { Wire.beginTransmission(MPU); Wire.write(0x3B); Wire.endTransmission(false); Wire.requestFrom(MPU, 6, true); AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ; AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ; AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ; // Sum all readings AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI)); AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI)); c++; } //Divide the sum by 200 to get the error value AccErrorX = AccErrorX / 200; AccErrorY = AccErrorY / 200; c = 0; // Read gyro values 200 times while (c < 200) { Wire.beginTransmission(MPU); Wire.write(0x43); Wire.endTransmission(false); Wire.requestFrom(MPU, 6, true); GyroX = Wire.read() << 8 | Wire.read(); GyroY = Wire.read() << 8 | Wire.read(); GyroZ = Wire.read() << 8 | Wire.read(); // Sum all readings GyroErrorX = GyroErrorX + (GyroX / 131.0); GyroErrorY = GyroErrorY + (GyroY / 131.0); GyroErrorZ = GyroErrorZ + (GyroZ / 131.0); c++; } //Divide the sum by 200 to get the error value GyroErrorX = GyroErrorX / 200; GyroErrorY = GyroErrorY / 200; GyroErrorZ = GyroErrorZ / 200; // Print the error values on the Serial Monitor Serial.print("AccErrorX: "); Serial.println(AccErrorX); Serial.print("AccErrorY: "); Serial.println(AccErrorY); Serial.print("GyroErrorX: "); Serial.println(GyroErrorX); Serial.print("GyroErrorY: "); Serial.println(GyroErrorY); Serial.print("GyroErrorZ: "); Serial.println(GyroErrorZ); }
代码说明:因此,首先我们需要包含用于I2C通信的Wire.h库,并定义存储数据所需的一些变量。
在设置部分,我们需要初始化电线库并通过电源管理寄存器复位传感器。为了做到这一点,我们需要看一下传感器数据表从那里我们可以看到注册地址。
此外,如果需要,我们可以使用加速计和陀螺仪的配置寄存器选择其满标度范围。对于这个例子,我们将使用默认的+-2g范围作为加速计,250度/秒范围作为陀螺仪,因此我将对代码的这一部分进行注释。
//配置加速度计灵敏度-全量程(默认+/- 2g)Wire.write (0 x1c);//与ACCEL_CONFIG寄存器对话(1C十六进制)//设置寄存器位为00010000 (+/- 8g满量程)Wire.endTransmission(true);//配置陀螺仪灵敏度-全量程范围(默认+/- 250deg/s)Wire.write (0 x1b);//与GYRO_CONFIG寄存器对话(1B十六进制)//设置寄存器位为00010000 (1000deg/s满量程)*/
在循环部分,我们从读取加速度计数据开始。每个轴的数据存储在两个字节或寄存器中,我们可以从传感器的数据表中看到这些寄存器的地址。
为了读取所有寄存器,我们从第一个寄存器开始,并使用requiestFrom()函数请求读取X、Y和Z轴的所有6个寄存器。然后我们从每个寄存器读取数据,由于输出是2的补码,我们将它们适当组合以获得正确的值。
// === Read acceleromter data === // Wire.beginTransmission(MPU);Wire.write (0 x3b);//从寄存器0x3B (ACCEL_XOUT_H) Wire.endTransmission(false)开始;wire.requestfrom(mpu,6,true);//对于+-2g范围,我们需要根据数据表AccX = (Wire.read() << 8 | Wire.read()) / 16384.0,将原始值除以16384;// x轴值AccY = (Wire.read() << 8 | Wire.read()) / 16384.0;// y轴值AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0;/ / z轴的值
为了得到从-1g到+1g的输出值,适合于计算角度,我们将输出与之前选择的灵敏度进行分割。
最后,使用这两个公式,我们根据加速度计的数据计算横摇和俯仰角度。
//从加速度计数据计算滚转和俯仰accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58;accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58;/ / AccErrorY ~ (-1.58)
接下来,使用相同的方法,我们得到陀螺仪数据。
我们读取6个陀螺仪寄存器,适当地组合它们的数据,并将其除以之前选择的灵敏度,以获得每秒的度输出。
//读取陀螺仪数据=== // previousTime = currentTime;//之前的时间存储在实际读取时间之前currentTime = millis();//当前时间实际时间读取elapsedTime = (currentTime - previousTime) / 1000;//除以1000得到秒Wire.write (0 x43);//陀螺数据第一个寄存器地址0x43 Wire.endTransmission(false);wire.requestfrom(mpu,6,true);//总共读取4个寄存器,每个轴值存储在2个寄存器中//对于250deg/s范围,我们必须首先将原始值除以131.0,根据数据表GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;
在这里,您可以注意到我用一些小的计算误差值来修正输出值,我将在一分钟内解释如何得到它们。由于输出是以每秒度数为单位的,现在我们需要将它们与时间相乘,以获得度数。使用millis()函数在每次读取迭代之前捕获时间值。
//用计算的误差值修正输出// GyroErrorX ~(-0.56) GyroY = GyroY - 2;// gyroerror ~(2) GyroZ = GyroZ + 0.79;// GyroErrorZ ~(-0.8) //当前的原始值是度每秒,deg/s,所以我们需要乘以sendseconds (s)得到角度的角度gyroAngleX = gyroAngleX + GyroX * elapsedTime;// deg/s * s = deg gyroAngleY = gyroAngleY + GyroY * elapsedTime;偏航=偏航+陀螺仪*经过时间;
最后,我们用一个互补滤波器融合加速度计和陀螺仪的数据。这里,我们取96%的陀螺仪数据,因为它非常精确,不受外力的影响。陀螺仪的缺点是它会漂移,或者随着时间的推移在输出中引入误差。因此,从长期来看,我们使用加速度计的数据,在这种情况下,4%,足以消除陀螺仪漂移误差。
//互补滤波器-组合加速度计和陀螺仪角度值roll=0.96*陀螺仪角度X+0.04*加速度计角度X;螺距=0.96*回旋角度+0.04*角度;
然而,由于我们不能从加速度计数据计算偏航,我们不能在它上实现互补滤波器。
在我们看结果之前,让我快速解释一下如何得到错误校正值。为了计算这些错误,我们可以在传感器处于平面静止位置时调用calculate_IMU_error()自定义函数。这里我们对所有输出做200个读数,把它们加起来除以200。当我们将传感器保持在静止位置时,期望的输出值应该是0。通过这个计算,我们可以得到传感器产生的平均误差。
void calculate_IMU_error(){//我们可以在设置部分调用这个函数来计算加速度计和陀螺数据误差。从这里,我们将得到在串行监视器上打印的上述方程中使用的错误值。//读取加速度计值200次,while (c < 200) {line . begintransmission (MPU);Wire.write (0 x3b);Wire.endTransmission(假);wire.requestfrom(mpu,6,true);AccX = (Wire.read() << 8 | Wire.read()) / 16384.0;AccY = (Wire.read() << 8 | Wire.read()) / 16384.0;AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0;//所有读数之和AccErrorX = AccErrorX + (((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2)) * 180 / PI)); AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI)); c++; } //Divide the sum by 200 to get the error value AccErrorX = AccErrorX / 200; AccErrorY = AccErrorY / 200; c = 0; // Read gyro values 200 times while (c < 200) { Wire.beginTransmission(MPU); Wire.write(0x43); Wire.endTransmission(false); Wire.requestFrom(MPU, 6, true); GyroX = Wire.read() << 8 | Wire.read(); GyroY = Wire.read() << 8 | Wire.read(); GyroZ = Wire.read() << 8 | Wire.read(); // Sum all readings GyroErrorX = GyroErrorX + (GyroX / 131.0); GyroErrorY = GyroErrorY + (GyroY / 131.0); GyroErrorZ = GyroErrorZ + (GyroZ / 131.0); c++; } //Divide the sum by 200 to get the error value GyroErrorX = GyroErrorX / 200; GyroErrorY = GyroErrorY / 200; GyroErrorZ = GyroErrorZ / 200; // Print the error values on the Serial Monitor Serial.print("AccErrorX: "); Serial.println(AccErrorX); Serial.print("AccErrorY: "); Serial.println(AccErrorY); Serial.print("GyroErrorX: "); Serial.println(GyroErrorX); Serial.print("GyroErrorY: "); Serial.println(GyroErrorY); Serial.print("GyroErrorZ: "); Serial.println(GyroErrorZ); }
我们只需在串行监视器上打印这些值,一旦知道它们,我们就可以在代码中实现它们,如前所示,用于横摇和俯仰计算,以及3个陀螺仪输出。
最后,使用Serial。我们可以在串行监视器上打印Roll, Pitch和Yaw的值,看看传感器是否工作正常。
MPU6050方向跟踪-三维可视化
接下来,为了制作3D可视化示例,我们只需要接受Arduino通过串口发送的数据处理开发环境.以下是完整的Processing代码:
/*Arduino和MPU6050 IMU-Dejan的3D可视化示例,//www.mfxpo.com */输入处理bet188官方网站。串行。*;导入java.awt.event.KeyEvent;导入java.io.IOException;串行端口;字符串数据=”;浮动滚转、俯仰、偏航;void setup(){size(25601440,P3D);myPort=new Serial(这是“COM7”,19200);//启动串行通信myPort.bufferUntil('\n');}void draw(){translate(width/2,height/2,0);background(233);textSize(22);text(“Roll:+int(Roll)+“Pitch:+int(Pitch),-100265);//旋转对象rotateX(弧度(-Pitch));rotateZ(弧度(滚动);旋转(弧度(偏航));//3D对象文本大小(30);填充(0,76,153);框(386,40,200);//绘制框文本大小(25);填充(255,255,255);文本(“www.HowToMechatronics.com”,-183,10,101);//延迟(10);//打印LN(“ypr:\t”+angleX+“\t”+angleY);//打印值以检查是否得到正确的值}//从串行端口读取数据void serialEvent(Serial myPort){//从串行端口读取数据,直到字符'.'为止,并将其放入字符串变量“data”.data=myPort.readStringUtil('\n');//如果有换行符以外的字节:if(data!=null){data=trim(data);//在“/”字符串项处拆分字符串[]=拆分(数据“/”);如果(items.length>1){/--Roll,俯仰度数Roll=float(items[0]);俯仰=float(items[1]);偏航=float(items[2]);}}
在这里,我们从Arduino读取传入数据,并将其放入适当的Roll、Pitch和Yaw变量中。在主绘制循环中,我们使用这些值来旋转3D对象,在本例中,这是一个带有特定颜色和文本的简单框。
如果我们运行草图,我们可以看到MPU6050传感器是多么好的跟踪方向。3D物体非常精确地跟踪传感器的方向,而且反应也非常灵敏。
正如我提到的,唯一的缺点是偏航会随时间漂移因为我们不能使用互补滤波器。为了改善这一点,我们需要使用一个额外的传感器。那通常是一个磁强计,可以用来长期校正陀螺仪的偏航漂移。然而,MPU6050实际上有一个功能叫做数字运动处理器用于机载数据的计算它能够消除偏航漂移。
下面是使用数字运动处理器的相同3D示例。我们可以看到,在没有偏航漂移的情况下,定向跟踪是多么精确。板载处理器也可进行计算和输出四元数用于表示三维对象的方向和旋转。在本例中,我们实际上使用四元数来表示方向,该方向也不会受到使用时发生的万向节锁定的影响欧拉角.
然而,从传感器获取数据比我们之前解释的要复杂一些。首先,我们需要连接和额外的电线到Arduino数字pin。这是一个中断引脚,用于从MPU6050读取数据类型。
代码也有点复杂这就是为什么我们要用i2cdevlib库由Jeff Rowberg编写.这个图书馆可以从github我会在网站文章中加入一个链接。
一旦安装了库,就可以从库中打开MPU6050_DMP6示例。这个例子的每一行都有注释。
在这里,我们可以选择我们想要的输出类型,四元数,欧拉角,偏航,俯仰和滚转,加速度值或3D可视化的四元数。这个库还包括3D可视化示例的处理草图。我只是像前面的例子一样修改它以获得盒子形状。下面是使用MPU6050_DPM6示例的3D可视化处理代码,用于选定的“OUTPUT_TEAPOT”输出:
/*Arduino和MPU6050 IMU-Dejan的3D可视化示例,//www.mfxpo.com */输入处理bet188官方网站。串行。*;导入java.awt.event.KeyEvent;导入java.io.IOException;串行端口;字符串数据=”;浮动滚转、俯仰、偏航;void setup(){size(25601440,P3D);myPort=new Serial(这是“COM7”,19200);//启动串行通信myPort.bufferUntil('\n');}void draw(){translate(width/2,height/2,0);background(233);textSize(22);text(“Roll:+int(Roll)+“Pitch:+int(Pitch),-100265);//旋转对象rotateX(弧度(-Pitch));rotateZ(弧度(滚动);旋转(弧度(偏航));//3D对象文本大小(30);填充(0,76,153);框(386,40,200);//绘制框文本大小(25);填充(255,255,255);文本(“www.HowToMechatronics.com”,-183,10,101);//延迟(10);//打印LN(“ypr:\t”+angleX+“\t”+angleY);//打印值以检查是否得到正确的值}//从串行端口读取数据void serialEvent(Serial myPort){//从串行端口读取数据,直到字符'.'为止,并将其放入字符串变量“data”.data=myPort.readStringUtil('\n');//如果有换行符以外的字节:if(data!=null){data=trim(data);//在“/”字符串项处拆分字符串[]=拆分(数据“/”);如果(items.length>1){/--Roll,俯仰度数Roll=float(items[0]);俯仰=float(items[1]);偏航=float(items[2]);}}
在这里,我们使用serialEvent()函数接收来自Arduino的四元数,在主绘制循环中,我们使用它们来旋转3D对象。如果我们运行这个草图,我们可以看到四元数在三维旋转物体上有多好。
为了不使本教程超载,我放置了第二个例子DIY Arduino框架或自稳定平台在另一篇文章中。
请在下面的评论部分提出任何与本教程相关的问题,也不要忘记检查我的Arduino项目集合bet188me.
嗨,德扬,
加速度计的LSB乘法器值表是不正确的,将提供俯仰和横摇值为实际值的1/2。修正后的表格如下:
* AFS_SEL |全量程| LSB灵敏度
* ——–+——————+—————-
* 0 | +/- 2g | 8192 LSB/mg
* 1 | +/- 4g | 4096 LSB/mg
*2 |+/-8g | 2048 LSB/mg
* 3| +/- 16g | 1024 LSB/mg
如新发布的MPU6050库(2019年2月)所示。
谢谢你提供了一个非常好的关于如何使用这个板的教程。
预计起飞时间
嘿,谢谢你的意见!
嗨,德扬
多么伟大的项目啊
请问你用的是什么三维建模软件?
非常感谢。我使用Solidworks制作3D模型。
嗨,德扬,
谢谢你在这个项目上令人印象深刻的工作,它看起来真的很棒!
我试图实现你的代码,但我遇到了一个我不理解的问题。
我按照你的描述做了接线,我在我的Arduino Nano和Mega上试过。我甚至为MPU-6050、GY-521和GY-87使用了两种不同的转接板。
在所有情况下,当我看我的串行监视器时,这三个值只是继续计数,它们根本不代表我的传感器角度。下面是一个简短的例子:
5.83 / -24.94/10.72
5.84/-24.96/10.73
5.84 / -24.97/10.74
5.85/-24.99/10.74
5.85/-25.01/10.75
5.86 / -25.03/10.76
5.86 / -25.05/10.77
5.87 / -25.07/10.77
你知道可能是什么问题吗?
非常感谢!
嘿,谢谢!试着改变调整计算误差值,也许会有帮助。漂移的发生是因为陀螺仪,所以你也可以试着只用加速度计来看看它是否正常工作。
我也有同样的问题。我运行calculate_IMU_error函数,并将新的错误值替换到代码中,这些值保持稳定。
供参考——运行calculate_IMU_error函数时得到的错误值如下:
AccErrorX ~ (-1.80)
AccErrorY(4.40)
GyroErrorX ~ (-2.18)
陀螺误差(1.11)
GyroErrorZ ~ (0.75)
你执行:
gyroangle = gyroangle + GyroX * elapsedTime;
所以每个循环都用陀螺仪的旧值来计算新值。这也许可以解释为什么即使你不移动传感器,XY和Z也会发生变化。
如果你只是表演
gyroAngleX=GyroX*延迟时间;
你会看到移动然后是稳定。也许这样会更好?
我使用MPU6050 DMP6的例子和最后的处理代码,但它总是产生偏航将漂移的时间。
是的,因此,为了克服偏航漂移,您需要在代码中包含一个磁强计,或者一个新的IMU模块,或者实施一个卡尔曼滤波器以减少总体漂移。
老兄! !我只是想说声谢谢。你在这里做了一些令人印象深刻的工作。我对你感激不尽。在我的项目中我需要这些内容,并且能够详细地解释陀螺仪,它是如何工作的以及数据是如何使用的。betway我已经订阅了你的youtube频道,你肯定有粉丝了。再次感谢你的出色工作,并坚持下去。
嘿,很高兴听到这个。谢谢!干杯!
你好,感谢这个很棒的教程!它真的帮助我摆脱了很多mpu库,我不理解-我总是喜欢代码,我理解
但是,我认为你的第一个草图有一个错误:
//互补滤波器-组合加速度计和陀螺仪角度值
横摇=0.96*回旋角X+0.04*转角X;
间距= 0.96 * gyroangley + 0.04 * accangley;
这基本上是正确的-然而,在我看来,你没有“关闭循环”..翻滚和俯仰将继续计数向上(或向下),取决于漂移。我们必须以某种方式“重置”每个循环的角度“一点”。因此,我的建议是:
gyroAngleX = 0.96 * gyroAngleX + 0.04 * accAngleX;
gyroAngleY = 0.96 * gyroAngleY + 0.04 * accAngleY;
滚= gyroAngleX;
距= gyroAngleY;
通过此更改,accAngle可以随时间将矢量“拉回到”其正确位置。短期变化主要由回转角支撑。
你觉得这个怎么样?
你是正确的。