使用加速度计和陀螺仪计算位移(MPU6050)

时间:2014-10-20 23:15:45

标签: position arduino accelerometer gyroscope dead-reckoning

我是一名计算机科学专业的学生,​​从事电子项目,需要计算偏航,俯仰,滚动和X,Y,Z位移。我想用一把枪连接IMU并跟踪它的方向和位移。我能够得到偏航,俯仰和俯仰,但遗憾的是无法理解如何计算我的枪的位移或位置。我使用的是包含MPU-6050的10-DOF GY-87传感器。

我得到的是g和m / s2格式的值。从我研究过的研究来看,我需要获得加速度/时间2,然后添加所有值。但是我不明白我应该使用什么时差。 参考:How to calculate distance based on phone acceleration

#include "I2Cdev.h"
#include "MPU6050.h"

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;
//MPU6050 accelgyro(0x69); // <-- use for AD0 high

int16_t ax, ay, az;
float dx, dy, dz = 0;
int16_t gx, gy, gz;





#define LED_PIN 13
bool blinkState = false;

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    Serial.begin(38400);

    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    Serial.println("Updating internal sensor offsets...");

    accelgyro.setXGyroOffset(85);
    accelgyro.setYGyroOffset(1);
    accelgyro.setZGyroOffset(-4);
    accelgyro.setXAccelOffset(-4269);
    accelgyro.setYAccelOffset(-4836);
    accelgyro.setZAccelOffset(1080);

    pinMode(LED_PIN, OUTPUT);
}

void loop() {

        accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

        dx=dx+(float)(((float)ax/(float)16384)*9.8*0.05*0.05);
        dy=dy+(float)(((float)ay/(float)16384)*9.8*0.05*0.05);
        dz=dz+(float)(((float)az/(float)16384)*9.8*0.05*0.05);
        Serial.print(dx); Serial.print("\t");
        Serial.print(dy); Serial.print("\t");
        Serial.print(dz); Serial.print("\t\n");


delay(1000);
    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

我想跟踪对象,如以下YouTube视频中所示。

http://www.youtube.com/watch?v=ZYyyaJgKsDg

如果你们中的任何人能够在这方面指导我,我将不胜感激。 谢谢

P.S:对不起我的英语不好以及使用非技术性术语。

5 个答案:

答案 0 :(得分:7)

我担心答案不是你想听的答案。从IMU单元计算位置是非常非常困难的。这个video from Google是一个非常好的参考原因(详见第24分钟)。基本上,您需要将加速度两次集成才能定位。您还需要从IMU看到的加速度中移除重力。如果这不能完美地完成,那么错误就会非常快。

您引用的视频使用了球在桌面上滚动的信息来通知他们的模型。他们可以跟踪传感器的方向,以了解球的滚动方向。他们使用球的半径以及球板的角度变化来跟踪x和y球。如果你从桌子上拿起他们的球,那根本就不会起作用。

如果您需要跟踪某些内容,您应该寻找一些可以为您提供有关物体位置信息的传感器(GPS,视频分析)。然后,您可以使用卡尔曼滤波器将其与IMU数据相结合,以获得良好的定位精度。

祝你的项目好运。

答案 1 :(得分:3)

是..在你的循环中()你有延迟(1000);

这意味着你的增量时间是1秒,而不是50毫秒。

在loop()中尝试这个:

accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    double t2 = millis() - pms;
    t2 /= 1000;  // convert ms to s
    t2 *=t2;


    // your Math and Serial here... 


    pms = millis(); 

答案 2 :(得分:2)

虽然很晚但可能很有用。您可以在惯性导航系统上搜索INS支架以查找详细信息。然而,简而言之:IMU测量附着在其上的框架中的加速度和角速度。例如,x方向上的acc是IMU的x方向,而不是您想要计算位置的参考系的x方向。 因此,您需要将加速度转换为参考帧。这可以通过欧拉角来完成。据我所知,MPU 6050为您提供欧拉角甚至转换矩阵。如果是这样,你应该使用

<subflow-state id="customer" subflow="checkout/customer">
      <input name="order" value="order"/>
      <transition on="customerReady" to="updateCustomerAddress" />
    </subflow-state>

    <action-state id="updateCustomerAddress">
        <evaluate expression="customerServiceImpl.updateAddressDetails(order.customer)" />
        <transition to="customer"
            on-exception="javax.validation.ConstraintViolationException" />
        <transition to="orderConfirmation" />   
    </action-state>

将传感器测量的acc矢量传输到参考系中的acc矢量。然后积分两次为您提供参考框架中的位置。有关欧拉角和转换矩阵计算的更多细节可在互联网上找到。

答案 3 :(得分:2)

我知道这是一个过时的帖子,但是我想我会发布一些我对MPU 6050和arduino所做的实验的更正。

首先,您用来查找位移的方程不正确,您需要使用运动学方程。但是,方程Xf = 1 / 2a t ^ 2 + Vo t + Xo也是不正确的,因为它仅对于恒定加速度有效。在这种情况下,加速度是CHANGING,因此您可以获取两个数据集点之间的平均加速度,并将其插入上一个方程式,或者使用以下方程式:

Xf = 1/4(Af + Ao) t ^ 2 + Vo t + Xo

其中Xf是以米为单位的最终距离,Af是以m / s ^ 2为单位的最终CURRENT加速度,Ao是以m / s ^ 2为单位的最后一个数据集的先前加速度,t是Af之间的时间变化以及SECONDS中的Ao数据集,Vo是最后一个数据集的瞬时速度(以m / s为单位),Xo是最后一个数据集的最终距离或以米为单位的所有先前距离的总和。 需要使用先前的加速度和来自两个之前的数据集的加速度来计算Vo,或者 使用以下运动学方程计算Ao-1:

Vo = 1/2(Ao + Ao-1)* t + Vo-1

其中Vo是先前的瞬时速度,单位为m / s,Ao是先前的加速度,单位是m / s ^ 2,Ao-1是来自两个数据集的加速度,单位是m / s ^ 2,t是时间的变化SECONDS中Ao和Ao-1数据集之间的距离,而Vo-1是Ao-1数据集或两个数据集之前的瞬时速度,单位为m / s。

第二,您需要使用更可靠的时钟。我建议使用micros()函数,并记住t是数据集之间的时间变化。我不确定它的可靠性,但这是我能想到的最好的。使用所述方程式时,请确保从微秒转换为秒。

第三,我建议您将代码与LuisRódenas之类的校准草图结合起来,在代码开始时就如此频繁地校准校准偏移量。您可以将其放在setup()例程中,并可以使用较小的缓冲区大小值或200或300之类的数据集来确保实验之间的等待时间不会太长。

第四,您可以使用两个数据集加速度之间的平均值进行运算(这就是我们在上面所做的),或者进一步进行运算,并使用各种数据集的平均值,例如使用fifo缓冲区数组存储各种加速度值,并取缓冲区中所有值的平均值。 Fifo缓冲区要求始终保留一定数量的值,但随着新值的输入,较旧的值将消失。 fifo越大,距离计算将越不准确,但fifo缓冲区将使异常加速度值对数据的影响太大。缓冲区的大小要求您在精度和加速度值中的孤立值之间找到一个最佳平衡点。如果确实将fifo缓冲区用作加速度值,则使用以下方程式:

Xf = 1 / 2A t ^ 2 + Vo t + Xo

Vo = Aold * t + Vo-1

其中,A是从假设的FIFO缓冲区得出的新平均加速度,Aold是从最后的FIFO平均值得出的旧平均加速度,t是两个单独的数据集点之间的时间变化。 一切当然都以标准单位为单位,例如m / s s。

通过将原始加速度值除以16384再乘以9.8m / s ^ 2,您可以很好地将原始加速度值转换为m / s ^ 2。 16384值取决于+ -2g的标准灵敏度设置,如果您选择+ -4g之类的其他设置,该设置可能会更改。

最后,即使有上述所有更改,由于许多不同的因素(例如温度),也很难获得准确的读数。使用风扇或其他任何东西将陀螺仪/加速度计保持在室温或25°C,保持加速度计的受控环境非常重要。 Jeff Rowberg MPU6050库中有一个函数可以获取当前温度,mpu.getTemperature(),我相信。

即使进行了所有这些更改,由于数学原因和不准确的原因,仍然很难获得良好的准确读数。您可以尝试将陀螺仪设置为较不敏感的设置,因为我知道mpu 6050的默认设置为+ -2g,较高的设置可以防止许多问题影响读数,但对小位移的敏感度就会降低。

总有很多方法可以优化陀螺仪/加速度计的值,一种方法是,如果为了在一段时间内接收更多数据而增加了MPU数据流的频率,则可以让您接收更准确的读数。我相信Jeff Rowberg库中有一个函数可以允许这样做。

答案 4 :(得分:0)

我知道最后你的问题是:“但我无法理解我应该使用的时差。”

您在代码中使用的增量时间为0.05。含义;你假设你的加速度数据率是20HZ。如果不是20HZ,请相应更改。 您的计算基于以下公式:

dis = 1/2 a t^2 + vt

v = v0 + at

其中t是两个连续加速度样本之间的时间。

祝你好运