Как найти расстояние, пройденное с помощью гироскопа и акселерометра? - PullRequest
44 голосов
/ 11 июля 2011

Я хочу создать приложение, которое рассчитывает точное расстояние, пройденное iPhone (не большое расстояние), используя гироскоп + акселерометр. Здесь нет необходимости в GPS.

Как мне подойти к этой проблеме?

Ответы [ 6 ]

78 голосов
/ 11 июля 2011

Основное исчисление, стоящее за этой проблемой, находится в выражении

enter image description here

(и аналогичные выражения для смещений по y и z), а базовая геометрия - теорема Пифагора

enter image description here

Итак, после того, как ваши сигналы акселерометра пропущены через фильтр нижних частот и скомпонованы во времени с интервалом выборки dt, вы можете найти смещение в x как ( простите мой 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];

содержит значения x-ускорения от начала до конца измерения в моменты времени 0, dt, 2 * dt, 3 * dt, ... (n-1) * dt.

Чтобы найти полное смещение, вам просто нужно сделать

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

Гироскоп для этого не нужен, но если вы измеряете линейные расстояния, вы можете использовать показания гироскопа, чтобы контролировать, что вращение устройства не былослишком большой.Если вращение было слишком сильным, попросите пользователя повторить измерение.

43 голосов
/ 11 июля 2011

Вы получаете позицию, дважды интегрируя линейное ускорение, но ошибка ужасна. На практике это бесполезно.

Вот объяснение, почему (Google Tech Talk) в 23:20. Я очень рекомендую это видео.

Похожие вопросы:


Обновление (24 февраля 2013 г.): @Simon Да, если вы знаете больше о движении, например, о человеке, идущем и датчик на ноге, то вы можете сделать гораздо больше. Они называются

доменные специфические предположения .

Они печально ломаются, если предположения не выполняются и могут быть довольно громоздкими для реализации. Тем не менее, если они работают, вы можете делать забавные вещи. См. Ссылки в моем ответе Точность акселерометра Android (инерциальная навигация) при позиционировании в помещении.

5 голосов
/ 11 июля 2011

Вы должны использовать интерфейс Core Motion, как описано в Простое обнаружение движения iPhone .Особенно все повороты можно отслеживать очень точно.Если вы планируете делать что-то, связанное с линейными движениями, это очень сложная вещь.Посмотрите на Получение смещения из данных акселерометра с Core Motion .

1 голос
/ 19 мая 2015

Я взломал трещину и сдался (поздно ночью, казалось, никуда не денется).Это для проекта Unity3d.

Если кто-то захочет узнать, где я остановился, я был бы рад подробно рассказать о том, что делает весь этот материал.

В основном после того, что оказалось ложным срабатыванием, я подумалЯ попытался бы отфильтровать это, используя фильтр нижних частот, затем попытался удалить отскоки, найдя тренд, затем (acc_x [i-1] + acc_x [i]) / 2.

Похоже, что ложный положительный результат все еще исходит от наклона, который я пытался удалить ..

Если этот код полезен или ведет вас куда-то, пожалуйста, дайте мне знать!

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// rbi.noli@gmail.com
/// </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);

    }
}
0 голосов
/ 07 мая 2014

(acc_x [i-1] + acc_x [i]) / 2 - фильтр нижних частот, это среднее значение между двумя тактами во времени

также смотрите здесь: http://www.freescale.com/files/sensors/doc/app_note/AN3397.pdf pag: 3

0 голосов
/ 11 июля 2011

Вот ответ .Кто-то спрашивал раньше.

Есть приложение под названием RangeFinder , которое делает то же самое (доступно в App Store).

...