【问题标题】:How can I find distance traveled with a gyroscope and accelerometer?如何使用陀螺仪和加速度计找到行进的距离?
【发布时间】:2011-10-02 14:28:29
【问题描述】:

我想构建一个应用程序,使用 Gyro+Accelerometer 计算 iPhone 行进的准确距离(不是长距离)。这里不需要 GPS。

我应该如何解决这个问题?

【问题讨论】:

    标签: iphone accelerometer distance gyroscope


    【解决方案1】:

    这个问题背后的基本微积分在表达式中

    (以及y和z位移的类似表达式)和基本几何是勾股定理

    因此,一旦您的加速度计信号通过低通滤波器并以采样间隔 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];
    

    包含从测量开始到结束时间 0、dt、2*dt、3*dt、... (n-1)*dt 的 x 加速度值。

    要找到总位移,您只需这样做

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

    陀螺仪不是必需的,但如果您正在测量线性距离,您可以使用陀螺仪读数来控制设备的旋转不会太大。如果旋转太强,让用户重新测量。

    【讨论】:

    • 不错。我刚刚看到提问者既没有投票也没有接受答案,所以我+1 :-) 实际上,即使使用辛普森规则进行集成,由于错误传播,我在几秒钟后遇到了麻烦。
    • 谢谢Kay,我怀疑魔鬼在细节中,我相信这不是不可能解决的。在我的脑海中,加速度计的响应在高频处可能是非线性的,或者它们可能没有足够准确地减去重力。在这两种情况下,滤除问题频率(可能必须抑制高于 30 Hz 的所有频率)和运行时校准(保持静止 1 秒并测量漂移以补偿它)应该会有所帮助。我想我现在必须在我的 Android 上试用它。
    • 获得准确的结果仍然是一个未解决的问题,即您可以真正用于游戏或其他什么的东西。就像阿里所说的那样,大卫萨克斯对 Android 做了一些非常研究(s. Ali 的 Google Tech Talk 链接)。您可能会在我在下面的答案中提供的链接中找到有用的想法。准备做一些繁重的数学运算(卡尔曼滤波器和导数)。
    • @drlemon:你为什么要这样做 - (acc_x[i-1]+acc_x[i])/2?
    • @drlemon :这不应该更准确吗? stackoverflow.com/questions/12926459/…
    【解决方案2】:

    您可以通过两次积分线性加速度来获得位置,但 错误非常可怕。在实践中是没有用的。

    这里是 an explanation why (Google Tech Talk) 23:20。我强烈推荐这个视频。

    类似问题:


    更新(2013 年 2 月 24 日):@Simon 是的,如果您对运动有更多了解,例如一个人走路并且传感器在他的脚上,那么您可以做更多的事情。这些被称为

         特定领域的假设

    如果假设不成立并且实施起来可能非常麻烦,它们就会惨遭破坏。不过,如果它们有效,您可以做一些有趣的事情。室内定位见我的回答Android accelerometer accuracy (Inertial navigation)中的链接。

    【讨论】:

    • 你知道是否有人试图找到可怕的系统错误的根源吗?抑制高频或预先测量校准有帮助吗?
    • 观看 23:20 的视频,我在回答中链接了 Google 技术讲座。它解释了为什么你会得到那个可怕的错误。过滤和校准都无济于事。
    • 我不认为他们解释了什么。他说:“有一些方法可以改善线性运动估计……但是任何类型的方向误差都非常重要,各种误差都会耦合进来,包括加速度计和陀螺仪之间的交叉轴误差”。对我来说,看起来他们只是不知道发生了什么,因为如果他们知道,他们可以提出一些建议来使结果更好。感谢您的视频,非常有用!有空的时候,我现在必须玩一下那个加速度计。
    • 有没有其他方法可以精确地做到这一点?还可以使用哪些其他电子设备进行精确测量?
    • @Simon 根据您的应用程序,您可能会发现my answer 很有帮助(计步器或基于 RSSI 的本地化)。不准确的来源是陀螺仪的白噪声;使用环形激光陀螺仪(1 磅加上电池 :))您可以获得更好的精度,这就是他们在飞机上所做的。
    【解决方案3】:

    您应该使用 Simple iPhone motion detect 中描述的 Core Motion 接口。特别是所有旋转都可以非常准确地跟踪。如果你打算做一些与线性运动相关的事情,这是非常困难的事情。看看Getting displacement from accelerometer data with Core Motion

    【讨论】:

    • 赞成。令人惊讶的是,这个问题出现了多少次,人们不断地以正方形的形式重新发明轮子...... :(
    • @Ali 是的,我计划在接下来的几个月内写一篇博客文章来解决这个问题并发布我的结果(没有找到解决方案,但有一些很好的解决方法),然后将摘要发布为常见问题在这里。题外话:我不知道如何通过这个聊天来联系你 :( 你也在做 iPhone 编程吗?我有一个请求(通过 SO :) 签约(布拉格),但我很忙。放下我如果您有兴趣,请通过我的网站发送电子邮件。顺便说一句:恭喜您达到 2k 代表 :)))
    • 谢谢 :) 我刚刚给你发了电子邮件,所以你会有我的电子邮件地址以供将来参考。我也在考虑写一篇文章来清理这个烂摊子。不幸的是,我没有时间这样做。 :(无论如何,当你完成你的工作时请通知我,这样我就可以告诉别人!
    【解决方案4】:

    我对此进行了尝试并放弃了(深夜,似乎一无所获)。这是针对 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);
    
        }
    }
    

    【讨论】:

      【解决方案5】:

      (acc_x[i-1]+acc_x[i])/2 是一个低通滤波器,它是两个时间度量之间的平均值

      也看这里:http://www.freescale.com/files/sensors/doc/app_note/AN3397.pdf 第 3 页

      【讨论】:

        【解决方案6】:

        Navisens

        https://navisens.com/#how-work

        声明如下 - Navisens 正在申请专利的技术以独特的方式处理加速度计和陀螺仪数据来定位您的手机。

        试用了演示应用程序,该应用程序主要用于在设置初始位置和方向后在不使用定位服务或 WiFi 的情况下绘制运动地图。

        iOS SDK - https://github.com/navisens/iOS-SDK

        Android SDK - https://github.com/navisens/Android-SDK

        注意:这不是开源的

        【讨论】:

          【解决方案7】:

          这里是answer。之前有人问过。

          有一个名为 RangeFinder 的应用在做同样的事情(在 App Store 中可用)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-04-25
            • 1970-01-01
            • 2019-05-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-11-10
            相关资源
            最近更新 更多