产品故事

从等待 GPS 到传感器辅助计距:AimiRun 的定位优化经历

从 iOS 上顺利起步,到 Android 定位慢、漂移、成簇和中断,记录 AimiRun 如何一步步调整开跑等待、双路定位与传感器辅助计距。

AimiRun发布于

博客 · zh-CN
散落的 GPS 原始位置点与一条经过整理的跑步路线

刚开始做 AimiRun 时,iOS 上的跑步定位很顺利。开启定位后,位置回调基本正常,我们几乎不需要专门处理 GPS 信号。那时很容易以为,跑步记录只要持续接收位置、连成路线就可以了。

真正的难题是在 Android 上逐渐出现的。我们每解决一个问题,真实跑步又带来下一个:先是等不到位置,后来发现收到的位置会漂、会成簇,也会突然消失。GPS 优化就这样从「等信号」开始,慢慢变成了同时考虑什么时候开跑、哪些位置可用,以及定位空窗里的距离怎么办。

第一个问题:Android 开了定位,却迟迟没有回调

在一些 Android 手机上,开启定位服务后,应用经常要等很久才收到第一个位置,有时一段时间内完全没有回调。若直接从第一个 GPS 点开始计时和计距,用户可能已经准备跑了,记录却还没真正开始。

我们先尝试加一道 GPS 门控:进入跑步页面后先等待定位,收到足以开始的位置信息,再进入正式跑步状态。固定等几秒并不能保证信号已经就绪,所以后来把等待做成单独的状态,并在等待过久时给出提示。这个阶段解决的是「什么时候开始记录」,还没有解决「位置准不准」。

有了回调,位置也可能离实际很远

继续看真机记录后,我们发现 Android 的位置点会漂移。有时手机还会先交付一个缓存的上次位置,也就是 last known location。它虽然来得早,却可能已经过时,和跑者当前所在的位置相差很远。把它当成此刻的位置,开跑点和第一段路线都会被带偏。

在公园和小区里,问题更明显。树木、建筑和周边环境会让手机收到的位置偏到跑道或道路之外;一些记录里,位置误差达到一两百米。还有些时候,点不是均匀地沿路线分布,而是一簇簇挤在某个区域,再突然跳到另一处。地图上看起来像跑者瞬间拐弯、横穿公园,实际上只是设备交付的位置不稳定。

下面这张图来自一次公园跑步记录。橙色折线是原始定位连接出的路径,蓝色是整理后的路线。原始路径里那些尖角和长长的斜线,让一段普通的绕圈跑变得很难辨认。

公园跑步记录中抖动的橙色原始定位路径与蓝色整理后路线的对比

图 1:同一段记录里的原始定位路径与整理后的路线。

这让我们意识到,「收到一个位置」不能自动等同于「得到一个可信的跑步位置」。开跑判断要考虑位置是否新鲜,路线也要能承受少量漂移和异常点;与此同时,还要尽可能保留操场弯道和真实转向,不能为了让线条顺眼就把路线抹平。

回放原始定位,才能看清问题

为了看清每次跑步到底收到了什么,我们把原始定位点和整理后的路线放在一起回放。下面的视频里,黄色点随着记录逐步出现,绿色线展示对应的路线。这样回看,比只盯着跑完后的一条线,更容易找到哪些地方出现了抖动或异常位置。

视频:一段真实记录中,原始定位点与路线逐步形成的过程。

信号更差的时候,情况会像下面这张图一样:原始位置散在路线两侧,一些点甚至远远偏离正常绕圈的范围,连起来便出现横穿整个区域的长线。我们在反复回看这些记录的过程中,逐步调整对漂移、跳点和成簇信号的处理。

大量黄色原始 GPS 点散落在环线两侧,与绿色整理后的路线形成对比

图 2:另一段定位更不稳定的记录。黄色为原始位置点,绿色为整理后的路线。

接下来遇到的是一段一段的信号空窗

公园和小区里的定位问题不只表现为偏差大。有些跑步记录会连续一段时间收不到合适的位置,过一会儿又突然恢复。地图因此断开,距离也可能少算;若恢复时收到一个跳得很远的位置,又可能把缓存位置之间的直线误当成实际移动。

同一次跑步,把不同设备和 App 放在一起对照

为了看清问题出在哪里,我们在同一次跑步中同时带上 iPhone 和 Android 手机。iPhone 上使用 AimiRun,Android 上则分别用高德、Keep 和当时开发中的 AimiRun 记录。下面这张图,就是那次跑步留下的四组结果。

同一次跑步的四组记录,从左到右为 iPhone 版 AimiRun、Android 高德、Android Keep 和 Android 版 AimiRun

图 3:同一次跑步的四组记录,从左到右依次为 iPhone 版 AimiRun、Android 高德、Android Keep 和当时开发中的 Android 版 AimiRun。

这一次,iPhone 版 AimiRun 显示的距离是 12.03 公里,路线能够比较清楚地看出公园里的绕圈过程。Android 上,高德显示了 30.86 公里,轨迹中出现了大量跳动和横穿公园的长线;Keep 显示了 11.42 公里,也有类似的跨区域连线。最右侧的 Android 版 AimiRun 同样留下了明显漂移的轨迹——那时,我们自己的处理也还没有做好。

这些记录的起止时间和显示时长并不完全一致,我们主要用它们回看轨迹问题,没有据此计算精度排名。真正让我们注意到的是:同一个跑步场景下,几份 Android 记录都出现了位置不稳定的表现。iOS 上顺利的开发经验,不能直接套到 Android 上;换一个跑步 App,也不会自动消除设备和系统定位本身的问题。这促使我们继续往定位来源和距离计算上找解决办法。

系统更新后,换一个定位来源也没有立刻解决

后来,有一次手机系统升级之后,这台手机的 GPS 响应时间变得更长,等待十几分钟仍可能没有可用定位。我们尝试接入高德地图定位,希望换一个来源能更快拿到位置。

实际调试时,高德也持续返回了一些很模糊的位置。回头看,这次问题主要出在那台手机的系统环境;单独换一个定位 SDK,并没有让原始位置变得可靠。这个尝试没有白费,它帮助我们确认了问题边界:应用可以判断和处理收到的位置,却不能保证手机及时提供高质量定位。

Android 开始前,让两路定位同时寻找可用信号

在这之后,我们尝试引入双路定位竞争。开跑前并行获取两路定位信息,根据先到的数据和当时的质量判断能否开始;当一路提供稳定、可用的位置后,再确定后续采用的来源。这样做是为了减少某一路迟迟没有响应时的等待。

双路定位改善的是「从哪里更早拿到可用信息」,不是对 GPS 精度的保证。两路数据如果都来自同一台手机的弱信号环境,也可能同时模糊。我们逐渐不再把「等到理想 GPS」当成开始跑步和累计距离的唯一前提。

距离不再只靠 GPS 点之间的变化

最后一个转变来自信号空窗:如果一段时间没有可靠 GPS 点,跑者可能还在继续跑,但仅靠前后两个位置无法知道这段时间实际经过了多远。我们开始让手机传感器提供的运动信息参与距离估算,并结合断点前的跑步状态,尽量连续地记录这段移动。

这不意味着 GPS 不再重要。可用的 GPS 位置仍然帮助我们绘制路线和判断跑步状态;在定位空窗里,手机传感器和已有的运动信息则可以帮助估算距离。估算段不是那段时间里真实收到的 GPS 轨迹,所以在回放中需要和实测位置区分开。

回看这条开发过程,我们最初只是在等 GPS 回调,后来才看到:有回调不等于位置可信,位置可信也不代表信号会一直连续。每次真实跑步都让问题更具体,也让处理方式从「等一个 GPS 点」逐渐变成分别看待开跑、路线和距离。

如果想了解跑完后如何查看路线和定位空窗,可以继续阅读跑步轨迹回放。


下一次跑步,从这里开始

有计划地跑,跑完知道下一步。

下载 AimiRun,把下一个跑步目标变成可以跟着完成的训练。