web-dev-qa-db-ja.com

ジャイロスコープと加速度計で移動距離を見つけるにはどうすればよいですか?

Gyro + Accelerometerを使用して、iPhoneの正確な移動距離(長距離ではない)を計算するアプリを作成したい。ここにはGPSは必要ありません。

この問題にどのように取り組むべきですか?

44
Ruchir Agile

この問題の背後にある基本的な計算は式にあります

enter image description here

(およびyおよびzの変位の同様の式)および基本的なジオメトリはピタゴラスの定理です。

enter image description here

したがって、加速度計の信号がローパスフィルターを通過し、サンプリング間隔dtに合わせてビニングされると、xの変位を(pardon my C ...)として見つけることができます

float dx=0.0f;
float vx=0.0f;
for (int i=1; i<n; i++)
 {
   vx+=(acceleration_x[i-1] + acceleration_x[i])/2.0f*dt;
   dx+=vx*dt;
 }

dyおよびdzについても同様です。ここに

float acceleration_x[n];

時間0、dt、2 * dt、3 * dt、...(n-1)* dtでの測定の開始から終了までのx加速度値が含まれます。

総変位を見つけるには、ただ

dl=sqrt(dx*dx + dy*dy + dz*dz);

これにはジャイロスコープは必要ありませんが、直線距離を測定する場合は、ジャイロスコープの読み取り値を使用して、デバイスの回転が大きすぎないことを制御できます。回転が強すぎる場合は、ユーザーに測定をやり直させます。

78
drlemon

直線加速度を2回積分することで位置を取得できますが、エラーは恐ろしいです。実際には役に立ちません。

理由(Google Tech Talk)の説明 23:20です。このビデオを強くお勧めします。

同様の質問:


Update(2013年2月24日):@Simonはい、動きについて詳しく知っている場合、たとえば人が歩いていてセンサーが足に付いている場合、その後、さらに多くのことができます。これらは呼ばれます

ドメイン固有の仮定

仮定が成り立たないとひどく壊れてしまい、実装するのが非常に面倒になります。それでも、それらが機能すれば、楽しいことができます。私の答えのリンクを参照してください Androidの加速度センサーの精度(慣性航法) 屋内での測位。

43
Ali

Simple iPhone motion detect で説明されているようなCore Motionインターフェイスを使用する必要があります。特に、すべての回転は非常に正確に追跡できます。直線運動に関連する何かをするつもりなら、これは非常に難しいことです。 Core Motionで加速度計データから変位を取得する をご覧ください。

5
Kay

私はこれにひびを取り、あきらめました(夜遅く、どこにも行かないようでした)。これはUnity3dプロジェクト用です。

誰かが私が中断したところを取り戻したいと思うなら、私はこのすべてが何をするかについて詳しく述べたいです。

基本的に誤検知であることが判明した後、ローパスフィルターを使用してこれをフィルター処理し、トレンドを見つけてバウンスを削除しようとした後、(acc_x [i-1] + acc_x [i] )/ 2。

誤検知はまだ傾きから生じているように見えますが、私はそれを削除しようとしました。

このコードが有用であるか、どこかにあなたを導くならば、私に知らせてください!

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// [email protected]
/// </summary>
public class AccelerometerInput : MonoBehaviour 
{

    Transform myTransform;
    Gyroscope gyro;
    GyroCam gyroCam;

    void Awake()
    {
        gyroCam= FindObjectOfType<GyroCam> ();
        myTransform = transform;
        if (SystemInfo.supportsGyroscope) {
            gyro = Input.gyro;
            gyro.enabled = true;
        }
    }

    bool shouldBeInitialized = false; 
    void Update () 
    {

        transform.Translate (GetAccelerometer ());// * Time.deltaTime * speed);

        //GetComponent<Rigidbody> ().AddForce (GetAccelerometer ());

    }

    public float speed = 10.0F;

    public Vector3 dir;
    public float f;
    Vector3 GetAccelerometer()
    {

        dir = Input.acceleration;

        dir.x *= gyro.attitude.x;
        dir.z *= gyro.attitude.z;

        if (Mathf.Abs (dir.x) < .001f)
            dir.x = 0;
        dir.y = 0;
        if (Mathf.Abs (dir.z) < .001f)
            dir.z = 0;

        RecordPointsForFilter (dir);

        //print ("Direction : " + dir.ToString("F7"));

        return TestPointsForVelocity();
    }

    Vector3[] points = new Vector3[20];
    int index;
    void RecordPointsForFilter(Vector3 recentPoint)
    {
        if (index >= 20)
            index = 0;
        points [index] = EvaluateTrend (recentPoint);;
        index++;
    }

    //try to remove bounces
    float xTrend = 0;
    float zTrend = 0;
    float lastTrendyX = 0;
    float lastTrendyZ = 0;
    Vector3 EvaluateTrend(Vector3 recentPoint)
    {

        //if the last few points were positive, and this point is negative, don't pass it along
        //accumulate points into a trend
        if (recentPoint.x > 0)
            xTrend += .01f;
        else
            xTrend -= .1f;

        if (recentPoint.z > 0)
            zTrend += .1f;
        else
            zTrend -= .1f;

        //if point matches trend, keep it
        if (xTrend > 0) {
            if (recentPoint.x > 0)
                lastTrendyX = recentPoint.x;
        } else  // xTrend < 0
            if (recentPoint.x < 0)
            lastTrendyX = recentPoint.x;

        if (zTrend > 0) {
            if (recentPoint.z > 0)
                lastTrendyZ = recentPoint.z;
        } else  // xTrend < 0
            if (recentPoint.z < 0)
                lastTrendyZ = recentPoint.z;

        return new Vector3( lastTrendyX, 0, lastTrendyZ);
    }

    Vector3 TestPointsForVelocity()
    {
        float x = 0;
        float z = 0;

        float xAcc = 0;
        float zAcc = 0;

        int successfulHits = 0;
        for(int i = 0; i < points.Length; i++)
        {
            if(points[i]!=null)
            {
                successfulHits ++;
                xAcc += points[i].x;
                zAcc += points[i].z;
            }
        }

        x = xAcc / successfulHits;
        z = zAcc / successfulHits;

        return new Vector3 (x, 0, z);

    }
}
1
user887973

これが answer です。誰かが前に尋ねました。

RangeFinder という同じことを行うアプリ(App Storeで入手可能)があります。

0
Raptor

(acc_x [i-1] + acc_x [i])/ 2はローパスフィルターであり、時間内の2つのメジャー間の平均値です。

こちらもご覧ください: http://www.freescale.com/files/sensors/doc/app_note/AN3397.pdf pag:3

0