2012-01-08 77 views
16

我试图构建一个iOS应用程序,显示跑步或步行时的总行程。我已经阅读并重新阅读了所有我能找到的文档,但是我无法提供给我一个准确的总距离。使用CLLocationManager计算准确的总步行距离/跑步距离

与Nike + GPS或RunKeeper相比,我的应用持续报告更短的距离。他们会首先报告,但随着我不断移动,我的应用与其他正在运行的应用的价值逐渐漂移。例如,如果我步行0.3公里(通过我的车的里程表进行验证),Nike + GPS和RunKeeper都会每次报告〜.3公里,但我的应用程序会报告~13.3公里。 newLocation.horizo​​ntalAccuracy始终为5.0或10.0。

这是我正在使用的代码。我错过了明显的东西吗?关于如何改善这一点以获得更准确的阅读的任何想法?

#define kDistanceCalculationInterval 10 // the interval (seconds) at which we calculate the user's distance 
#define kNumLocationHistoriesToKeep 5 // the number of locations to store in history so that we can look back at them and determine which is most accurate 
#define kValidLocationHistoryDeltaInterval 3 // the maximum valid age in seconds of a location stored in the location history 
#define kMinLocationsNeededToUpdateDistance 3 // the number of locations needed in history before we will even update the current distance 
#define kRequiredHorizontalAccuracy 40.0f // the required accuracy in meters for a location. anything above this number will be discarded 

- (id)init { 
    if ((self = [super init])) { 
     if ([CLLocationManager locationServicesEnabled]) { 
      self.locationManager = [[CLLocationManager alloc] init]; 
      self.locationManager.delegate = self; 
      self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation; 
      self.locationManager.distanceFilter = 5; // specified in meters 
     } 

     self.locationHistory = [NSMutableArray arrayWithCapacity:kNumLocationHistoriesToKeep]; 
    } 

    return self; 
} 

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { 
    // since the oldLocation might be from some previous use of core location, we need to make sure we're getting data from this run 
    if (oldLocation == nil) return; 
    BOOL isStaleLocation = [oldLocation.timestamp compare:self.startTimestamp] == NSOrderedAscending; 

    [self.delegate locationManagerDebugText:[NSString stringWithFormat:@"accuracy: %.2f", newLocation.horizontalAccuracy]]; 

    if (!isStaleLocation && newLocation.horizontalAccuracy >= 0.0f && newLocation.horizontalAccuracy < kRequiredHorizontalAccuracy) { 

     [self.locationHistory addObject:newLocation]; 
     if ([self.locationHistory count] > kNumLocationHistoriesToKeep) { 
      [self.locationHistory removeObjectAtIndex:0]; 
     } 

     BOOL canUpdateDistance = NO; 
     if ([self.locationHistory count] >= kMinLocationsNeededToUpdateDistance) { 
      canUpdateDistance = YES; 
     } 

     if ([NSDate timeIntervalSinceReferenceDate] - self.lastDistanceCalculation > kDistanceCalculationInterval) { 
      self.lastDistanceCalculation = [NSDate timeIntervalSinceReferenceDate]; 

      CLLocation *lastLocation = (self.lastRecordedLocation != nil) ? self.lastRecordedLocation : oldLocation; 

      CLLocation *bestLocation = nil; 
      CGFloat bestAccuracy = kRequiredHorizontalAccuracy; 
      for (CLLocation *location in self.locationHistory) { 
       if ([NSDate timeIntervalSinceReferenceDate] - [location.timestamp timeIntervalSinceReferenceDate] <= kValidLocationHistoryDeltaInterval) { 
        if (location.horizontalAccuracy < bestAccuracy && location != lastLocation) { 
         bestAccuracy = location.horizontalAccuracy; 
         bestLocation = location; 
        } 
       } 
      } 
      if (bestLocation == nil) bestLocation = newLocation; 

      CLLocationDistance distance = [bestLocation distanceFromLocation:lastLocation]; 
      if (canUpdateDistance) self.totalDistance += distance; 
      self.lastRecordedLocation = bestLocation; 
     } 
    } 
} 

回答

11

事实证明,我上面发布的代码工作很好。问题发生在我的应用程序的不同部分。我意外地将距离从米转换为英里,而不是从米到公里。哎呀!

无论如何,希望我的帖子仍然有一些优点,因为我觉得这是一个非常可靠的例子,说明如何使用Core Location跟踪用户的距离。

+0

不要忘记接受这个答案,以防止它显示为未解决的问题。顺便说一句好例子。 – 2012-01-09 15:13:28

+0

丹尼尔,你好,我从一个多星期以来一直在提取相同的问题,但仍然没有得到任何解决方案。所以,你能帮我吗? – 2012-03-21 12:19:30

+0

@Daniel ....请帮助我。 – 2012-03-21 12:36:39

0

您可能已将kRequiredHorizo​​ntalAccuracy设置得太低。如果历史中没有精确度为< kRequiredHorizo​​ntalAccuracy的位置,则忽略所有这些点并将距离加0。

+0

不幸的是,我不认为这样做。第一个原因是我正在记录horizo​​ntalAccuracy,并且它始终保持在10.0或5.0。此外,即使点> kRequiredHorizo​​ntalAccuracy被忽略,只要我得到一个有效的位置,我将它与上一个有效的位置进行比较,以获得距离,所以我不扔掉距离数据。 – Daniel 2012-01-09 00:19:53

+0

@Daniel ...和最后一个有效位置(lastRecordedLocation)是newLocation,以防列表中没有很好的准确性。这意味着你重新设置lastRecordedLocation而不增加距离。顺便说一句,10和5都很低。我在测试中经常得到100-150的准确度。 – fishinear 2012-01-09 12:57:52

+0

感谢您的关注。 lastRecordedLocation应该只有零,如果一个有效的位置尚未记录,因为我设置self.lastRecordedLocation = bestLocation在底部。也感谢关于100-150精度的建议。我会做更多的测试...可能需要将我的kRequiredHorizo​​ntalAccuracy从40增加到 – Daniel 2012-01-09 14:25:35