web-dev-qa-db-ja.com

加速度計とジャイロスコープ(MPU6050)を使用した変位の計算

私はコンピュータサイエンスの学生で、ヨー、ピッチ、ロール、X、Y、Z変位を計算する必要がある電子工学プロジェクトに取り組んでいます。 IMUを銃に取り付けて、その向きと変位を追跡したいと思います。ヨー、ピッチ、ロールを取得することはできますが、残念ながら、銃の変位や位置を計算する方法を理解できません。 MPU-6050を含む10-DOFGY-87センサーを使用しています。

Gおよびm/s2形式で値を取得しています。私がまだ研究した研究から、加速度/ time2を取得してから、すべての値を追加する必要があるということです。しかし、私がどの時差を使うべきか理解できません。参照: 電話の加速度に基づいて距離を計算する方法

#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

あなたの誰かがこの点で私を導くことができれば私はあなたに感謝します。ありがとうございました

追伸:私の悪い英語と非専門用語の使用について申し訳ありません。

5
svhr

答えはあなたが聞きたいと思うものではないのではないかと思います。 IMUユニットから位置を計算することは非常に困難です。これ Googleからのビデオ は理由の非常に良いリファレンスです(詳細な説明については24分に進んでください)。基本的に、位置に到達するには、加速度を2回積分する必要があります。また、IMUから見た加速度から重力を取り除く必要があります。これが完全に行われていない場合、エラーは非常に速く加算されます。

参照したビデオでは、ボールがテーブル上を転がっているという情報を使用して、モデルに通知しました。彼らはセンサーの向きを追跡して、ボールがどちらの方向に転がっていたかを知ることができました。彼らはボールの半径とangularボードからの変更を使用して、xとyでボールを追跡しました。テーブルからボールを​​拾った場合、まったく機能しません。

何かを追跡する必要がある場合は、オブジェクトの位置に関する情報(GPS、ビデオ分析)を提供できるセンサーを探す必要があります。次に、カルマンフィルターを使用して、それをIMUデータと組み合わせて、良好な位置精度を得ることができます。

あなたのプロジェクトで頑張ってください。

8
Scott Mahr

私はこれが古い投稿であることを知っていますが、MPU6050とarduinoで行った実験からいくつかの修正を投稿すると思いました。

まず、変位を見つけるために使用している方程式が正しくありません。運動学の方程式を使用する必要があります。ただし、方程式Xf = 1/2a t ^ 2 + Vo t + Xoも、一定の加速度のみを対象としているため、正しくありません。この場合、加速度は変化しているため、2つのデータセットポイント間の平均加速度を取得して前の式に代入するか、次の式を使用できます。

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

ここで、Xfはメートル単位の最終距離、Afはm/s ^ 2単位の最終現在の加速度、Aoはm/s ^ 2単位の最後のデータセットの以前の加速度、tはAfセットとAoセット間の時間の変化です。 SECONDSのデータの場合、Voは最後のデータセットの瞬間速度(m/s)、Xoは最後のデータセットの最終距離または以前のすべての距離の合計(メートル)です。 Voは、前の加速度と2つの前のデータセットからの加速度を使用して計算するか、次の運動方程式を使用してAo-1を計算する必要があります。

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

ここで、Voはm/sでの前の瞬間速度、Aoはm/s ^ 2での前の加速度、Ao-1はm/s ^ 2での2つのデータセットからの前の加速度、tはAoと間の時間の変化です。 SECONDSのAo-1データセット、およびVo-1は、Ao-1データセットまたは2データセット前のm/s単位の瞬間速度です。

次に、より信頼性の高い時計を使用する必要があります。 micros()関数を使用することをお勧めします。また、tはデータセット間の時間の変化であることを忘れないでください。信頼性はわかりませんが、私が考えることができる最高のものです。記載されている式を使用する場合は、マイクロ秒から秒に変換するようにしてください。

第3に、コードをLuisRódenasのようなキャリブレーションスケッチと組み合わせて、コードの最初でオフセットを頻繁に、または毎回キャリブレーションすることをお勧めします。これをsetup()ルーチンに配置し、小さなバッファサイズ値または200や300などのデータセットを使用して、実験の合間に長く待たないようにすることができます。

第4に、2つのデータセット加速度の平均を使用して操作するか(上記で行っていることです)、さらに一歩進んで、fifoバッファー配列を使用してさまざまな加速度値を格納し、取得するなど、さまざまなデータセットの平均を使用できます。バッファ内のすべての値の平均。 Fifoバッファーでは、常に設定された数の値が残っている必要がありますが、新しい値が入ると、古い値が残ります。 fifoが大きいほど、距離の計算は不正確になりますが、fifoバッファーを使用すると、外れ値の加速度値がデータに過度に影響を与えることがなくなります。バッファのサイズでは、加速度値の精度と唯一の外れ値の間のスイートスポットを見つける必要があります。加速度値にFIFOバッファーを使用する場合は、次の式を使用してください。

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

Vo = Aold * t + Vo-1

ここで、Aは仮想のFIFOバッファーから導出された新しい平均加速度、Aoldは最後のFIFO平均からの古い平均加速度、tは2つの個別のデータセットポイント間の時間。もちろん、すべて標準単位、m/ssなど。

16384で割り、9.8m/s ^ 2を掛けることで、生の加速度値をm/s ^ 2に変換するのに良い仕事をしました。 16384の値は、+-2gの標準感度設定に依存します。これは+ -4gなどの別の設定を選択した場合に変更される可能性があります。

最後に、上記のすべての変更を行っても、温度などのさまざまな要因により、正確な読み取り値を取得することは非常に困難です。ジャイロ/加速度計を室温または25℃に保つためにファンなどを使用して、加速度計の制御された環境を維持することが重要です。 Jeff Rowberg MPU6050ライブラリには、現在の温度を取得する関数があります。mpu.getTemperature()私は信じています。

これらすべての変更を行っても、数学的な理由と小さな不正確さのために、正確な読み取り値を取得することは非常に困難です。 mpu6050がデフォルトの+ -2g設定に設定されていることがわかっているので、ジャイロを感度の低い設定に設定してみてください。設定を高くすると、多くの問題が読み取り値に影響を与えるのを防ぐことができますが、小さな変位に対する感度は低くなります。

ジャイロ/加速度計の値を最適化する方法は常にたくさんあります。1つの方法は、一定期間により多くのデータを受信するためにMPUデータストリームの頻度を増やすと、より正確な測定値を受信できるようになる可能性があります。 。これを可能にする関数がJeffRowbergライブラリにあると思います。

3
Nick G

はい..loop()にはdelay(1000)があります。

つまり、デルタ時間は50ミリ秒ではなく、1秒です。

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(); 
3
user2425343

遅いですが、多分役に立つでしょう。慣性航法装置のINSスタンドで検索して詳細を確認できます。ただし、簡単に言うと、IMUはそれに接続されたフレームの加速度とangular速度を測定します。たとえば、x方向のaccは、IMUのx方向であり、必要な参照フレームのx方向ではありません。位置を計算するには、加速度を参照フレームに変換する必要があります。これは、オイラー角度で実行できます。私が理解したように、MPU 6050は、オイラー角度と変換マトリックスを提供します。その場合は、を使用する必要があります。

Acc_inert = T * Acc_body 

センサーによって測定されたaccベクトルを参照フレームのaccベクトルに転送します。次に、2回積分すると、参照フレーム内の位置がわかります。オイラー角と変換行列の計算に関する詳細は、インターネットで入手できます。

2
Yaser

最後に、あなたの質問は「しかし、どの時差を使うべきか理解できません」ということだと理解しています。

コードで使用するデルタ時間は0.05です。意味;加速度データレートが20HZであると想定します。 20HZでない場合は、それに応じて変更します。計算は次の式に基づいています。

dis = 1/2 a t^2 + vt

v = v0 + at

ここで、tは2つの連続する加速度サンプル間の時間です。

幸運を

0