web-dev-qa-db-fra.com

Comment trouver la distance parcourue avec un gyroscope et un accéléromètre?

Je veux construire une application qui calcule avec précision la distance parcourue par l'iPhone (pas de longue distance) à l'aide de Gyro + Accelerometer. Pas besoin de GPS ici.

Comment devrais-je aborder ce problème?

43
Ruchir Agile

Le calcul de base derrière ce problème est dans l'expression

enter image description here

(et expressions similaires pour les déplacements en y et z) et la géométrie de base est le théorème de Pythagore

enter image description here

Ainsi, une fois que les signaux de votre accéléromètre sont passés à travers un filtre passe-bas et regroupés dans le temps avec un intervalle d'échantillonnage dt, vous pouvez trouver le déplacement dans x comme ( 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;
 }

et de même pour dy et dz. Ici 

float acceleration_x[n];

contient les valeurs d'accélération x du début à la fin de la mesure aux moments 0, dt, 2 * dt, 3 * dt, ... (n-1) * dt.

Pour trouver le déplacement total, il suffit de faire

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

Le gyroscope n'est pas nécessaire pour cela, mais si vous mesurez des distances linéaires, vous pouvez utiliser la lecture du gyroscope pour contrôler que la rotation de l'appareil n'est pas trop importante. Si la rotation était trop forte, demandez à l'utilisateur de refaire la mesure.

77
drlemon

Vous obtenez la position en intégrant l'accélération linéaire deux fois mais l'erreur est horrible. C'est inutile en pratique.

Voici une explication pourquoi (Google Tech Talk) à 23h20. Je recommande fortement cette vidéo.

Questions similaires:


Mise à jour (24 février 2013): @Simon Oui, si vous en savez plus sur le mouvement, par exemple une personne qui marche et que le capteur est sur son pied, vous pouvez en faire beaucoup plus. Ceux-ci s'appellent 

hypothèses spécifiques au domaine

Ils se brisent lamentablement si les hypothèses ne sont pas vérifiées et peuvent être assez lourdes à mettre en œuvre. Néanmoins, s'ils fonctionnent, vous pouvez faire des choses amusantes. Voir les liens dans ma réponse Précision de l'accéléromètre Android (navigation par inertie) au positionnement à l'intérieur.

42
Ali

Vous devez utiliser l'interface Core Motion comme décrit dans Détection de mouvement d'un iPhone simple . Surtout toutes les rotations peuvent être suivies de manière très précise. Si vous envisagez de faire quelque chose lié aux mouvements linéaires, c'est très difficile. Jetez un coup d’œil à Obtenir un déplacement à partir des données de l’accéléromètre avec Core Motion .

5
Kay

J'ai pris un risque et abandonné (tard dans la nuit, ne semblait pas aller nulle part). Ceci est pour un projet Unity3d. 

Si quelqu'un veut reprendre là où je me suis arrêté, je me ferai un plaisir de vous expliquer ce que font toutes ces choses.

Fondamentalement, après une partie de ce qui s’est avéré être de faux positifs, je pensais essayer de filtrer cela à l’aide d’un filtre passe-bas, puis de supprimer les rebonds en trouvant une tendance, puis )/2. 

On dirait que le faux positif vient toujours de l'inclinaison que j'ai tenté de supprimer. 

Si ce code est utile ou vous mène quelque part, s'il vous plaît faites le moi savoir!

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

Voici la réponse . Quelqu'un a demandé avant.

Il existe une application appelée RangeFinder qui fait la même chose (disponible dans App Store).

0
Raptor

(acc_x [i-1] + acc_x [i])/2 est un filtre passe-bas, c'est la valeur moyenne entre deux mesures dans le temps

regardez aussi ici: http://www.freescale.com/files/sensors/doc/app_note/AN3397.pdf pag: 3

0