11

我是一名计算机科学专业的学生,​​正在从事一个需要计算偏航、俯仰、滚动和 X、Y、Z 位移的电子项目。我想在枪中安装一个 IMU 并跟踪它的方向和位移。我能够得到 Yaw、Pitch 和 Roll 但不幸的是无法理解如何计算我的枪的位移或位置。我正在使用包含 MPU-6050 的 10 自由度 GY-87 传感器。

我得到 g 和 m/s2 格式的值。从我研究过的研究来看,我需要获得加速度/时间2,然后添加所有值。但无法理解我应该使用什么时差。参考:如何根据手机加速度计算距离

#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

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

PS:对不起我的英语不好和使用非技术术语。

4

5 回答 5

13

恐怕答案不是你想听到的。从 IMU 单元计算位置非常非常困难。这段来自 Google 的视频是一个很好的参考资料(详细解释请看第 24 分钟)。基本上,您需要对加速度进行两次积分才能到达位置。您还需要从 IMU 看到的加速度中消除重力。如果这没有完美地完成,错误加起来真的很快。

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

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

祝你的项目好运。

于 2015-01-23T20:21:59.377 回答
5

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

首先,你用来求位移的方程不正确,你需要使用运动学方程。然而,方程 Xf = 1/2a t^2 + Vo t + Xo 也是不正确的,因为它仅适用于恒定加速度。在这种情况下,加速度是变化的,因此您可以取两个数据集点之间的平均加速度并将其代入上一个等式或使用以下等式:

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

其中 Xf 是以米为单位的最终距离,Af 是以 m/s^2 为单位的最终当前加速度,Ao 是以 m/s^2 为单位的最后一个数据集的先前加速度,t 是 Af 和 A​​o 集之间的时间变化以 SECONDS 为单位的数据,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 是 Ao 和Ao-1 数据集以 SECONDS 为单位,Vo-1 是 Ao-1 数据集或两个数据集之前的瞬时速度,以 m/s 为单位。

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

第三,我建议您通过将您的代码与 Luis Ró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/ss 等等。

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

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

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

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

于 2018-08-05T01:32:03.237 回答
4

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

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

在循环()中试试这个:

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(); 
于 2015-04-20T11:55:12.570 回答
3

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

Acc_inert = T * Acc_body 

将传感器测量的 acc 向量传输到参考框架中的 acc 向量。然后积分两次为您提供参考框架中的位置。有关欧拉角和变换矩阵计算的更多详细信息,请访问 Internet。

于 2016-09-09T10:41:25.830 回答
1

我知道最后你的问题是:“但我不明白我应该使用什么时差。”

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

dis = 1/2 a t^2 + vt

v = v0 + at

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

祝你好运

于 2014-11-24T14:19:21.387 回答