Android - 如何计算行驶距离

Android - How to Calculate Distance Traveled

我在设置 LocationRequest 属性后使用 FusedLocationProviderClient 获取 locationUpdates。

要计算 'distance traveled' 我想我会做以下事情:

Location lastLocation;   // initialized to start location with getLocation() - code not shown.
LocationCallback locationCallback;
Double DistanceTraveled = 0.0;

locationCallback = new LocationCallback() {
    @Override
    public void onLocationResult(LocationResult locationResult) {
        if (locationResult != null) {
            // Get last location in result if more than one are returned.
            Location thisLocation = locationResult.getLastLocation();
            // Sum up DistanceTraveled
            DistanceTraveled = DistanceTraveled + lastLocation.distanceTo(thisLocation);
            // Save thisLocation for next time onLocationResult() is called
            lastLocation.set(thisLocation);
        }
    }
}

好吧,这不是很好。在每次回调中,由于结果的准确性,确切位置会随机变化 0 米到 10 米。所以,如果我完全静止不动 10 分钟并使用此算法进行 5 秒更新,它会总结我已经走过的几米,而我根本没有移动!

我应该怎么做才能准确计算我的行进距离?存在哪些选项?

好的 - 我 post 在这里提出问题已经 12 天了。大量阅读、测试、编码,更多测试,更多阅读。我现在有责任为这个给我很多的网站做出贡献。就这样吧。

首先,以下 post 有许多信息花絮和 link 可以提供帮助。 calculate actual distance travelled by mobile

现在,我特别关心跟踪某人步行的距离;准确地说是在观鸟时。我的应用程序适用于观鸟者。因此,我有兴趣记录看到的鸟类及其位置,并跟踪步行的总距离。事实证明这是两个不同的问题。获取目击鸟类的当前坐标很容易;只是得到的位置。准确度是报告的准确度。

现在,针对这个post的问题。计算步行距离。那是完全不同的问题。这就是我在 post 提出问题时所寻找的。人们在步行时如何准确计算所走的距离?因为仅仅注册位置更新然后总结 Location1.distanceTo(Location2) 通常会给一个人一个疯狂膨胀的总距离。为什么?我不明白这个问题。现在我知道了。如果我有这样的理解,那么解决问题的路径就会更加清晰。

我举个例子。假设我走了 10 秒钟。在第二个 0 (t0) 是我开始的地方。假设我通过 t1 移动了 1 米。我站在这个位置直到t5,然后再走5秒直到t10。 walking/standing的组合有助于说明问题。

每个 GPS 位置更新都包含一个坐标 (lat/lng) 或一个点,以及以米为单位的准确度等级。连同其他数据,但我唯一关心的是时间(以毫秒为单位)。在此示例中,始终比上次更新多 1000 毫秒。

将此 GPS 更新视为圆心的一个点,返回的半径精度为米。理论上,您的实际位置可以在该圆圈内或圆圈边缘的任何位置。不确定以米为单位的精度有多准确(似乎它应该有自己的精度等级),但我们假设它是准确的,并且您的真实位置与报告点的距离不超过以米为单位的精度。事实上,为了便于说明,我们假设它始终与您的真实位置相距该距离。我们还假设此示例中返回的每个点的精度(以米为单位)为 20m。

因此,在 t0,我的真实位置可能比报告的位置提前 20 米。我向前走了 1 米,t1 的位置更新报告说我比实际位置提前了 20 米。因此,计算 t0.distanceTo(t1) 报告我移动了 40m,而我实际上只移动了 1m。开始看图了?继续阅读...

现在,我站在这里直到 t5。我又获得了 4 个位置更新,例如,前方 20 米,后方 20 米,左侧 20 米,右侧 20 米。 (这是一个极端的例子,但使用简单的数字来说明)。因此,除了我假设的 1 秒后 40 米的行程外,它现在认为我还移动了大约 20x4 或 80 米,总计 120 米。而我在现实中只移动了1m!继续再走 5 米到 t10,当您在 10 秒内只走了 6 米时,您的距离可能再次增加 5x20 或 100 米,总计 220 米。这就是为什么简单地总结行进的距离永远不会准确,只要准确性有任何误差。

这就是问题所在。直到有人明白这一点,你才会对这个蹩脚的 Galaxy S9 如何对你这样做感到困惑。

平均分呢? "midpoint(t0,t1).distanceTo(midpoint(t2,t3)" 等等?这将始终产生小于真实行进距离。取决于运动,有时会很多。

有很多方法(参见上文 link)可以尝试减少行驶距离计算中的错误。我发现我的以下方法在步行时产生的结果比 Google 的 MyTracks 应用程序更准确。我在200m、500m、1000m的距离上反复测试过。这始终如一地产生良好的结果,通常误差 < 10%。有一半时间,Google 的 MyTracks 说我在 200 米测试中走了 500 米以上。

onLocationResult(LocationResult locationResult) {

    lastLocationReceived.set(locationResult.getLastLocation());
    // Throw away updates that don't meet a certain accuracy. e.g. 30m
    if (lastLocationReceived.hasAccuracy() && locatLocationReceived.getAccuracy() <= MIN_ACC_METERS_FOR_DISTANCE_TRAVELED) {
        // Don't use it if the current accuracy X 1.5 > distance traveled since last valid location
        if ((lastLocationReceived.getAccuracy() * 1.5) < loastLocationReceived.distanceTo(lastLocationUsedForDistanceTraveled) {
            // Calculate speed of travel to last valid location; avg walking speed is 1.4m/s; I used 2.0m/s as a high end value. 
            // Throw away values that are too high because it would have required that you run to get there.
            // Sometimes the location is somewhere you could not have gotten to given the time.
            long timeDelta = lastLocationReceived.getTime() - lastLocationUsedForDistanceTraveled.getTime();
            if ((lastLocationReceived.distanceTo(lastLocationUsedForDistanceTraveled) / timeDelta) > MAX_WALKING_SPEED) {
                // NOW we have a value we can use to minimize error
                distanceTraveled += lastLocationReceived.distanceTo(lastLocationUsedForDistanceTraveled);
                // Update last valid location
                lastLocationUsedForDistanceTraveled.set(lastLocationReceived);
            }
        }
    }
};

备注:

  1. onPause() for activity 停止 locationUpdates。
  2. onResume() 重启 locationUpdates。
  3. Setting/using locationRequest.setSmallestDisplacement() 对我产生了奇怪的结果。我最终从未在我的 locationRequest 中设置此值。当 hAccuracy 为 20m 时,它怎么知道你移动了 5m?
  4. 我觉得不需要在应用程序暂停(放在口袋里)的情况下继续获取位置更新。一旦你从口袋里掏出 phone 用它来记录目击事件,它就会很快重新获取。更多的测试可能证明这是容易出错的。不过目前看来还可以。

我测试过的方法比我记忆中的要多,结果却截然不同。在我的测试中,这种简单的方法最适合步行。我确信我可以做更多的事情,这可能会将错误进一步细化几个百分点。如果有人有关于如何实现更严格准确性的具体示例,请 post 发表评论。

在我的测试中,我创建了一个 activity 允许我实时调整 locationRequest() 设置(更改时需要停止并重新启动 locationUpdates);以及修改最小准确度级别和准确度乘数(在上面的代码中用作 1.5)。所以我能够测试和使用不同的参数设置,看看什么产生了最好的结果。

我希望这能帮助其他人第一次走上这条路。如果有人有任何评论、更正和改进,我很乐意听到。