Arduino和MPU6050加速计和陀螺仪教程

在本教程中,我们将学习如何使用Arduino的MPU6050加速度计和陀螺仪传感器。首先,我将解释MPU6050如何工作以及如何从它读取数据,然后我们将给出两个实际示例。

概述

在第一个示例中,使用处理开发环境,我们将制作传感器方向的3D可视化,并且在第二个例子中,我们将制作简单的自稳定平台或DIY万向节。基于MPU6050方向及其熔融加速度计和陀螺数据,我们控制了保持平台级别的三个伺服电源。

betway

MPU6050 IMU在单个芯片上具有3轴加速度计和3轴陀螺仪。

陀螺仪沿X,Y和Z轴测量随时间的旋转速度或角度位置的变化率。它使用MEMS技术和科里奥利效果来测量,但有关其的更多细节,您可以检查我的特定MEMS传感器如何工作教程。陀螺仪的输出处于每秒度数,因此为了获得角度位置,我们只需要整合角速度。

MPU6050 IMU 3轴加速度计和3轴陀螺仪

另一方面,MPU6050加速计测量加速度的方式与上一段视频中解释的相同ADXL345加速度计传感器。简而言之,它可以沿着3个轴测量引力加速度,并使用一些三角形数学,我们可以计算传感器定位的角度。因此,如果我们保险,或结合加速度计和陀螺数据,我们可以获得关于传感器方向的非常准确的信息。

MPU6050 IMU也称为六轴运动跟踪装置或6 DOF(六个自由度)器件,因为它的6个输出,或3个加速度计输出和3陀螺仪输出。

Arduino和MPU6050

让我们来看看我们如何使用Arduino从MPU6050传感器中连接和读取数据。我们正在使用I2C协议来与Arduino进行通信,因此我们只需要两根电线来连接它,加上两根电线供电。

Arduino和MPU6050电路图

你可以从下面的链接获得这个Arduino教程所需的组件:

必威外围提钱披露:这些是附属链接。作为一名亚马逊助理,我的收入来自符合条件的购买。

MPU6050 Arduino Code.

下面是Arduino代码,用于从MPU6050传感器读取数据。在代码下面,你可以找到它的详细描述。

/ * Arduino和MPU6050加速度计和陀螺仪传感器教程由Dejan,//www.mfxpo.com * / #include  const 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通信的线路库,并定义存储数据所需的一些变量。

在setup部分,我们需要初始化线库并通过电源管理寄存器重置传感器。为了做到这一点,我们需要看一下传感器的数据表从我们可以看到寄存器地址。

MPU6050电源管理寄存器X6B

此外,如果我们愿意,我们可以选择加速度计和陀螺仪的全尺寸范围,使用它们的配置寄存器。在本例中,我们将对加速度计使用默认的+- 2g范围,对陀螺仪使用250度/秒范围,所以我将保留这部分代码注释。

//配置加速度计灵敏度 - 全尺度范围(默认+/- 2g)Wire.BegintroAnsmission(MPU);Wire.write(0x1c);//与Accel_Config寄存器(1c hex)wire.write(0x10)交谈;//将寄存器位设置为00010000(+/- 8g全尺度范围)wire.endtransmission(true);//配置陀螺仪灵敏度 - 全尺度范围(默认+/- 250deg / s)Wire.BegintroAnsmission(MPU);Wire.write(0x1b);//与gyro_config寄存器(1b hex)wire.write(0x10)交谈;//将寄存器位设置为00010000(1000deg / s满量程)wire.endtransmission(true);* /

在循环部分中,我们首先读取加速度计数据。每个轴的数据存储在两个字节或寄存器中,我们可以从传感器的数据表中看到这些寄存器的地址。

MPU6050 IMU加速度计数据寄存器

为了阅读它们所有,我们从第一个寄存器开始,并使用RequiestFrom()函数我们请求读取X,Y和Z轴的所有6个寄存器。然后我们从每个寄存器读取数据,因为输出是TwoS补充,我们将它们适当地组合以获得正确的值。

// ===读取加速器数据=== // wire.begintroansmission(mpu);Wire.write(0x3b);//以寄存器0x3b(Accel_XOUT_H)Wire.endTransmission(false)开始。wire.requestfrom(mpu,6,true);//总计读取6寄存器,每个轴值存储在2个寄存器//范围内,对于+ -2g的范围,我们需要将原始值除以16384,根据数据表ACCX =(Wire.read()<< 8| Wire.read())/ 16384.0;// X轴值Accy =(Wire.read()<< 8 | Wire.read())/ 16384.0;// y轴值Accz =(Wire.read()<< 8 | Wire.read())/ 16384.0;// Z轴值

为了使输出值从-1g到+ 1g,适合计算角度,我们用先前选择的灵敏度将输出分开。

MPU6050加速度计灵敏度满量程范围

最后,使用这两个公式,我们根据加速度计的数据计算横摇和俯仰角度。

//从加速度计数据计算滚动和俯仰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; // accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2));/ / AccErrorY ~ (-1.58)

接下来,我们用同样的方法获得陀螺仪数据。

我们读取6个陀螺仪寄存器,适当地组合它们的数据,然后除以先前选定的灵敏度,以获得以每秒度为单位的输出。

// ===读取陀螺仪数据=== // previoustime = currenttime;//以前的时间存储在实际时间读Currentime = Millis()之前存储;//当前时间实际时间读取ELAPSEDTIME =(CULLERTIME  -  PREATIME)/ 1000;//划分1000以获得秒线.Begintroansmission(MPU);Wire.write(0x43);//陀螺数据第一寄存器地址0x43 wire.endtransmission(false);wire.requestfrom(mpu,6,true);//读取4寄存器总,每个轴值存储在2寄存器gyrox =(wire.read()<< 8 | wire.read())/ 131.0;//对于250deg / s范围,我们必须将首先将原始值分为131.0,根据数据表Gyroy =(Wire.read()<< 8 | Wire.read())/ 131.0;gyroz =(wire.read()<< 8 | Wire.read())/ 131.0;

在这里,您可以注意到,我用一些小的计算误差值修正了输出值,稍后我将解释我们是如何得到它们的。因为输出的单位是度/秒,现在我们需要将它们与时间相乘得到度。使用millis()函数在每次读取迭代之前捕获时间值。

//用计算出的误差值校正输出gyrox = gyrox + 0.56;// gyroerrorx〜(-0.56)gyroy = gyroy  -  2;// gyroerrany〜(2)gyroz = gyroz + 0.79;// gyroerrzz〜(-0.8)//目前原始值为每秒度数,DEG / s,所以我们需要乘以Sendonds(s)来获得Vyroanglex = Gyroanglex + Gyrox *闪光灯的角度;// deg / s * s = deg gyroangley = gyroangley + gyroy *闪光时间;yaw = yaw + gyroz *闪光;

最后,我们利用一个互补滤波器将加速度计和陀螺仪数据融合在一起。这里,我们取了陀螺仪96%的数据,因为它非常准确,而且不受外力的影响。陀螺仪的缺点是它会漂移,或者随着时间的推移它会在输出中引入误差。因此,从长期来看,我们使用来自加速度计的数据,在本例中为4%,足以消除陀螺仪漂移误差。

//互补滤波器-结合加速度计和陀螺的角度值pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;

但是,由于我们无法从加速度计数据计算偏航,因此我们无法在其上实现互补滤波器。

在我们查看结果之前,让我快速解释一下如何获得误差修正值。为了计算这些错误,我们可以在传感器处于静止位置时调用calculate_IMU_error()自定义函数。这里我们对所有输出做200个读数,我们把它们加起来除以200。当我们将传感器保持在静止的位置时,预期的输出值应该是0。通过这个计算,我们可以得到传感器的平均误差。

void calculate_imu_error(){//我们可以在设置部分中调用此功能以计算加速度计和Gyro数据错误。从这里,我们将获得在串行监视器上打印的上述等式中使用的错误值。//注意,我们应该将IMU平放放置以获得适当的值,以便我们可以正确的值//读取加速度计值200次(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;//求和所有读数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个陀螺仪输出。

MPU6050螺距辊和偏航输出

最后,使用Serial.print功能我们可以在串行监视器上打印卷,俯仰和偏航值,并查看传感器是否正常工作。

MPU6050定向跟踪 - 3D可视化

接下来,为了使3D可视化示例我们只需接受此数据Arduino正在通过串行端口发送处理开发环境。以下是完整的处理代码:

/* Arduino和MPU6050 IMU - 3D可视化示例,Dejan, //www.mfxpo.com */bet188官方网站 import processing.serial.*;进口java.awt.event.KeyEvent;进口java.io.IOException;串行myPort;字符串数据= " ";浮动辊、俯仰、偏航;void setup() {size (2560, 1440, P3D);myPort = new串行(this, "COM7", 19200);//启动串行通信myPort.bufferUntil('\n');} void draw() {translate(width/2, height/ 2,0); background(233); textSize(22); text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265); // Rotate the object rotateX(radians(-pitch)); rotateZ(radians(roll)); rotateY(radians(yaw)); // 3D 0bject textSize(30); fill(0, 76, 153); box (386, 40, 200); // Draw box textSize(25); fill(255, 255, 255); text("www.HowToMechatronics.com", -183, 10, 101); //delay(10); //println("ypr:\t" + angleX + "\t" + angleY); // Print the values to check whether we are getting proper values } // Read data from the Serial Port void serialEvent (Serial myPort) { // reads the data from the Serial Port up to the character '.' and puts it into the String variable "data". data = myPort.readStringUntil('\n'); // if you got any bytes other than the linefeed: if (data != null) { data = trim(data); // split the string at "/" String items[] = split(data, '/'); if (items.length > 1) { //--- Roll,Pitch in degrees roll = float(items[0]); pitch = float(items[1]); yaw = float(items[2]); } } }

在这里,我们从Arduino读取了传入的数据,并将其放入适当的滚动,间距和偏航变量。在主绘制循环中,我们使用这些值旋转3D对象,在这种情况下,这是一个具有特定颜色和文本的简单框。

如果我们运行草图,我们可以看到MPU6050传感器的跟踪方向有多好。3D对象追踪传感器的方向非常准确,它也非常响应。

MPU6050定向跟踪 -  3D可视化示例

正如我所提到的,唯一的侧面是,随着时间的推移,偏航会漂移,因为我们不能使用互补过滤器。为了改善这一点,我们需要使用额外的传感器。这通常是磁力计,可用作陀螺仪偏航漂移的长期校正。然而,MPU6050实际上具有称为数字运动处理器的特征,该功能用于数据的板载计算,它能够消除横摆漂移。

绝对方位传感器- MPU6050 BNO055

以下是使用数字运动处理器的相同的3D示例。我们可以看到朝向追踪的准确性,没有偏航漂移。板载处理器还可以计算和输出四十二烷它们用于表示物体在三维中的方向和旋转。在这个例子中,我们实际上使用四元数来表示方向,这也不会受到使用时发生的万向节锁定的影响欧拉角

具有MPU6050 DMP特征的三维对象定向

然而,从传感器中获取此数据比我们之前解释的更复杂。首先,我们需要将额外的电线连接到Arduino数字引脚。这是一个中断引脚,用于从MPU6050读取此数据类型。

代码也有点复杂,所以这就是我们将使用的原因jeff rowberg的i2cdevlib库。这个库可以从以下网站下载GitHub我将包括网站文章中的链接。

安装库之后,就可以从库中打开MPU6050_DMP6示例。这个例子很好地解释了每一行的注释。

在这里,我们可以选择什么样的输出我们想要的,四元数,欧拉角,偏航,俯仰和滚动,加速度值或四元数的3D可视化。这个库还包括一个三维可视化示例的处理草图。我只是修改了它,以获得像前面例子中那样的盒子形状。下面是与MPU6050_DPM6示例一起工作的3D可视化处理代码,用于选定的“OUTPUT_TEAPOT”输出:

/* Arduino和MPU6050 IMU - 3D可视化示例,Dejan, //www.mfxpo.com */bet188官方网站 import processing.serial.*;进口java.awt.event.KeyEvent;进口java.io.IOException;串行myPort;字符串数据= " ";浮动辊、俯仰、偏航;void setup() {size (2560, 1440, P3D);myPort = new串行(this, "COM7", 19200);//启动串行通信myPort.bufferUntil('\n');} void draw() {translate(width/2, height/ 2,0); background(233); textSize(22); text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265); // Rotate the object rotateX(radians(-pitch)); rotateZ(radians(roll)); rotateY(radians(yaw)); // 3D 0bject textSize(30); fill(0, 76, 153); box (386, 40, 200); // Draw box textSize(25); fill(255, 255, 255); text("www.HowToMechatronics.com", -183, 10, 101); //delay(10); //println("ypr:\t" + angleX + "\t" + angleY); // Print the values to check whether we are getting proper values } // Read data from the Serial Port void serialEvent (Serial myPort) { // reads the data from the Serial Port up to the character '.' and puts it into the String variable "data". data = myPort.readStringUntil('\n'); // if you got any bytes other than the linefeed: if (data != null) { data = trim(data); // split the string at "/" String items[] = split(data, '/'); if (items.length > 1) { //--- Roll,Pitch in degrees roll = float(items[0]); pitch = float(items[1]); yaw = float(items[2]); } } }

因此,使用SeriaLevent()函数我们接收来自Arduino的四元数,并且在主绘制循环中,我们使用它们来旋转3D对象。如果我们运行草图,我们可以看到良好的四元数是如何在三个维度中旋转对象。

为了不要过载本教程,我下了第二个例子,DIY Arduino Gimbal或自稳定平台,在一个单独的文章中。

DIY Arduino框架-自我稳定平台

随意向下面的评论部分提出与本教程相关的任何问题,也别忘了检查我的Arduino项目的收集bet188me

14的反应

  1. 爱德华国际象棋

    嗨Dejan,
    具有LSB乘数加速度计的乘数值的表是不正确的,并且将提供音高和滚动值1/2实际值。更正的表如下所示:
    * AFS_SEL |全量程| LSB灵敏度
    * --- + ------ + ------
    * 0 |+/- 2g |8192 LSB / mg
    * 1 | +/- 4g | 4096 LSB/mg
    * 2| +/- 8g | 2048 LSB/mg
    * 3| +/- 16g | 1024lsb /mg
    如MPU6050库的新版本(2019年2月)所示。
    感谢您提供有关如何使用此突破板的真正良好的教程。
    艾德

    回复
  2. 奥马尔

    嗨德国
    什么是一个伟大的项目
    请问你用的是什么3d建模软件?

    回复
  3. 曼努埃尔

    嗨Dejan,
    谢谢你对这个项目的令人印象深刻的工作,看起来真的很棒!

    我试着实现你的代码,但我遇到了一个我不理解的问题。
    我按照你的描述做了接线,我在我的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函数,并将新的错误值替换到代码中,这些值保持稳定。

        FYI - 运行Compulate_imu_Error函数时获得的错误值如下:
        Accerrorx〜(-1.80)
        AccErrorY ~ (4.40)
        gyroerrorx〜(-2.18)
        GyroErrorY ~ (1.11)
        gyroerrorz〜(0.75)

      • Feroce-Lapin

        你表演:
        gyroanglex = gyroanglex + gyrox *闪光时间;
        所以每个循环都使用gyroanglex的旧值来计算新的价值。这可以解释为什么XY和Z即使您不移动传感器也会发生变化。
        如果你只是表演
        gyroAngleX = GyroX * elapsedTime;
        你会看到动作然后是稳定化。也许会更好?

    • 亚伦理查兹

      是的,因此为了克服偏航漂移将需要在你的代码中包括一个磁强计,或一个新的IMU模块或实现一个卡尔曼滤波器来减少总体漂移。

      回复
  4. Lolu Akindele

    老兄!!!我只是想说谢谢你。你在这里做了一些非常令人印象深刻的工作。我不知道该怎么感谢你才足够。我需要这个项目,并只是对陀螺仪提供如此详细的解释,如何工作以及数据如何完全相同超出令人印象深刻。betway我现在订阅了你的YouTube频道,你肯定获得了一个粉丝。再次感谢这真的很好的工作,并保持了。

    回复
  5. 克里斯

    嗨,谢谢你这个伟大的教程!它真的帮助我摆脱了mpu libs,我不明白 - 我总是喜欢代码,我理解

    然而,我认为你的第一个草图有一个错误:
    //互补滤波器-结合加速度计和陀螺角度值
    roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
    pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;

    这是碱性的正确 - 但是,它在我看来,你不会“关闭循环”..滚动和音调将继续计算和上升(或向下),具体取决于漂移。我们以某种方式必须“重置”每个循环的角度“有点”。因此,我的建议是写入:

    Gyroanglex = 0.96 * Gyroanglex + 0.04 * Accanglex;
    Gyroangley = 0.96 * Gyroangley + 0.04 * Accangley;

    roll = gyroanglex;
    间距= gyroangley;

    通过这种更改,accAngle可以随着时间的推移“将矢量拉回”到正确的位置。短期的变化主要由gyroAngle支持。

    你觉得这个怎么样?

    回复

发表评论

您的电子邮件地址将不会被公布。

推荐的

2019年初学者和爱好者的最佳进入级示波器

为初学者和爱好者最好的示波器

推荐的

2019年初学者的8个最佳Arduino Starter Kits

初学者的8个最佳Arduino Starter Kits

推荐的

最好的3D打印机为初学者和爱好者- 3D打印

初学者和爱好者的最佳3D打印机