2012-03-17 35 views
12

Tôi có một ứng dụng xoay quanh GPS của thiết bị và thông tin đến từ nó. Điều quan trọng là dữ liệu vị trí phải chính xác và cập nhật. Tôi biết rằng thiết bị bị giới hạn bởi GPS và giới hạn của GPS, nhưng tôi đã tự hỏi liệu có bất kỳ điều gì tôi có thể làm để tinh chỉnh/cải thiện hiệu suất của GPS iPhone, đặc biệt là ở khu vực tốc độ. Bởi vì cập nhật vị trí tụt hậu khoảng 3-5 giây sau vị trí thời gian thực của thiết bị, vận tốc được báo cáo bởi trình quản lý vị trí cũng chậm hơn nhiều so với giá trị thời gian thực. Trong trường hợp của tôi, điều đó đơn giản là quá dài. Tôi hiểu rằng có thể không có bất cứ điều gì tôi có thể làm, nhưng có ai có bất kỳ thành công trong việc cải thiện sự đáp ứng của iPhone GPS? Mỗi chút tạo nên sự khác biệt.CLLocationQuản lý phản hồi

Chỉnh sửa 1:

Trình quản lý vị trí của tôi nằm trong một lớp đơn, như Apple khuyến cáo.

Bên SingletonDataController.m:

static CLLocationManager* locationManager; 
locationManager = [CLLocationManager new]; 
locationManager.distanceFilter = kCLDistanceFilterNone; 
locationManager.headingFilter = kCLHeadingFilterNone; 

if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)) { 
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation; 
} else { 
    locationManager.desiredAccuracy = kCLLocationAccuracyBest; 
} 

[sharedSingleton setLocationManager:locationManager]; 
[locationManager release]; 

Bên MapView.m (nơi quản lý địa điểm được thực sự sử dụng):

- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil { 
    //setup 
    [SingletonDataController sharedSingleton].locationManager.delegate = self; 
    //more setup 
} 

- (void)batteryChanged { 
    if(([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) || ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateFull)) { 
     [SingletonDataController sharedSingleton].locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation; 
    } else { 
     [SingletonDataController sharedSingleton].locationManager.desiredAccuracy = kCLLocationAccuracyBest; 
    } 
} 

- (void)viewDidLoad { 
    //setup 
    [[NSNotificationCenter defaultCenter] 
     addObserver:self 
     selector:@selector(batteryChanged) 
      name:UIDeviceBatteryStateDidChangeNotification 
      object:nil]; 
    //other setup 
} 

Việc xử lý dữ liệu xảy ra bên locationManager:didUpdateToLocation:fromLocation:. Tôi không tin rằng sự kém hiệu quả ở đây là nguyên nhân của sự tụt hậu.

locationManager:didUpdateToLocation:fromLocation: cuộc gọi phương pháp này để cập nhật giao diện người dùng:

- (void)setLabels:(CLLocation*)newLocation fromOldLocation:(CLLocation*)oldLocation { 
    //set speed label 
    if(iterations > 0) { 
     if(currentSpeed > keyStopSpeedFilter) { 
      if(isFollowing) { 
       [mapViewGlobal setRegion:MKCoordinateRegionMake([newLocation coordinate], mapViewGlobal.region.span)]; 
      } 

      NSString* currentSpeedString; 
      if(isCustomary) { 
       currentSpeedString = [[NSString alloc] initWithFormat:@"%.1f miles per hour", (currentSpeed * 2.23693629f)]; 
      } else { 
       currentSpeedString = [[NSString alloc] initWithFormat:@"%.1f km per hour", (currentSpeed * 3.6f)]; 
      } 

      [speedLabel setText:currentSpeedString]; 
      [currentSpeedString release]; 
     } else { 
      speedLabel.text = @"Not moving"; 
     } 
    } 

    //set average speed label 
    if(iterations > 4 && movementIterations > 2) { 
     NSString* averageSpeedString; 
     if(isCustomary) { 
      averageSpeedString = [[NSString alloc] initWithFormat:@"%.1f miles per hour", (float)((speedAverages/(long double)movementIterations) * 2.23693629f)]; 
     } else { 
      averageSpeedString = [[NSString alloc] initWithFormat:@"%.1f km per hour", (float)((speedAverages/(long double)movementIterations) * 3.6f)]; 
     } 
     [averageSpeedLabel setText:averageSpeedString]; 
     [averageSpeedString release]; 
    } 

    //set elapsed time label 
    NSInteger seconds = [[NSDate date] timeIntervalSinceDate:dataObject.locationManagerStartDate]; 
    NSInteger minutes = seconds/60; 
    NSInteger hours = minutes/60; 

    //get remainder 
    seconds %= 60; 

    NSString* timeString; 
    NSString* secondsString; 
    NSString* minutesString; 
    NSString* hoursString; 

    if((seconds % 60) < 10) { 
     secondsString = [[NSString alloc] initWithFormat:@"0%i", seconds]; 
    } else { 
     secondsString = [[NSString alloc] initWithFormat:@"%i", seconds]; 
    } 

    if((minutes % 60) < 10) { 
     minutesString = [[NSString alloc] initWithFormat:@"0%i", minutes]; 
    } else { 
     minutesString = [[NSString alloc] initWithFormat:@"%i", minutes]; 
    } 

    if((hours % 60) < 10) { 
     hoursString = [[NSString alloc] initWithFormat:@"0%i", hours]; 
    } else { 
     hoursString = [[NSString alloc] initWithFormat:@"%i", hours]; 
    } 

    timeString = [[NSString alloc] initWithFormat:@"%@:%@:%@", hoursString, minutesString, secondsString]; 

    [elapsedTimeLabel setText:timeString]; 

    [timeString release], timeString = nil; 
    [secondsString release], secondsString = nil; 
    [minutesString release], minutesString = nil; 
    [hoursString release], hoursString = nil; 

    NSString* totalDistanceString; 
    if(isCustomary) { 
     totalDistanceString = [[NSString alloc] initWithFormat:@"Total: %.2f mi", (float)distance * 0.000621371192f]; 
    } else { 
     totalDistanceString = [[NSString alloc] initWithFormat:@"Total: %.2f km", (float)distance/1000.0f]; 
    } 
    [customTopBar setTitle:totalDistanceString]; 
    [totalDistanceString release]; 
} 

Với một vài NSDates và NSLogs Tôi đã phát hiện ra rằng việc thực hiện của toàn bộ locationManager:didUpdateToLocation:fromLocation: (không chỉ là nhãn phương pháp cập nhật) không bao giờ mất hơn về 8ms trên iPhone 4 của tôi; nói cách khác, việc xử lý dữ liệu không phải là vấn đề.

+0

Cho chúng tôi biết cách bạn đang nhận dữ liệu vị trí. Độ trễ đó không bình thường. – sosborn

+0

Đã thêm mã. Tôi có thể đăng thêm nếu cần. –

+0

3-5 giây có thể là một chút cường điệu; nó trễ và tầm 3-5 chỉ xuất hiện trong đầu tôi vì một lý do nào đó. Ngày mai tôi sẽ chạy một số xét nghiệm để có được con số chính xác. –

Trả lời

27

OK, một vài điều có thể cải thiện độ trễ của bạn. Trước hết, hãy sử dụng kCLLocationAccuracyBestForNavigation luôn. Không có sự khác biệt về sử dụng pin thực sự giữa điều đó và kCLLocationAccuracyBest, cả hai đều sử dụng GPS ở tốc độ tối đa. Sự khác biệt chính là trong quá trình hậu xử lý mà Apple làm.

Thứ hai, không cần phải lọc tốc độ == 0. Apple đã thực hiện việc lọc đó: nếu tốc độ của bạn từ GPS giảm xuống dưới ngưỡng nhất định (khoảng 4 km/h), hệ điều hành giả định bạn đang đứng yên và nó thay thế cùng một giá trị vị trí cho tất cả các mẫu tiếp theo. Nó làm điều đó cho đến khi nó nghĩ rằng bạn đang di chuyển một lần nữa. Tôi cho rằng họ làm điều đó để tránh "jittering" trên bản đồ khi bạn đang đứng yên. Trong thực tế, tốc độ giảm xuống 0 đã cho giá trị thực cuối cùng của một chuỗi các giá trị "đứng yên", vì vậy nếu bạn lọc trên tốc độ == 0 hơn bạn đang thiếu một mẫu GPS thực.

Thật không may, họ không có cách nào để tránh việc lọc và nhận mẫu GPS thực. Tôi đã nói chuyện với Apple về nó, và phản ứng của họ là họ sẽ không thay đổi hành vi. kCLLocationAccuracyBestForNavigation lọc ít tích cực hơn kCLLocationAccuracyBest, vì vậy tốt nhất nên sử dụng nó.

Thứ ba, có thể bạn đã làm điều này, nhưng đảm bảo rằng bạn gọi "setNeedsDisplay" trên chế độ xem của bạn ngay từ "didUpdateFromLocation:", để đảm bảo rằng bản đồ thực sự được vẽ lại.

Nếu bạn làm tất cả điều đó, bạn sẽ có độ trễ khoảng 1 giây. Nếu bạn muốn cải thiện trên 1 giây hơn bạn có thể thử sử dụng các kỹ thuật tiên đoán. Từ hai vị trí cuối cùng và tốc độ đã cho, bạn có thể tính vị trí tiếp theo có khả năng ở đâu và đã hiển thị vị trí đó. Tôi đã có kết quả hỗn hợp với điều đó. Nó hoạt động tốt cho chuyển động nhanh mà không thay đổi đột ngột tốc độ, như lái xe.Nó hoạt động kém hơn cho các chuyển động chậm hơn như đi bộ hoặc đi xe đạp.

+0

Cảm ơn rất nhiều '' 'kCLLocationAccuracyBestForNavigation''' thực sự đã giúp tôi. Các phương thức đại biểu vị trí chạy nhanh hơn rất nhiều ngay bây giờ :) – Supertecnoboff

6

Trong iPhone chúng ta có thể cấu hình các dịch vụ vị trí bằng hai phương pháp -

  1. Bằng cách sử dụng Standard Location Services, đó là GPS vệ tinh cung cấp cho bạn dữ liệu chính xác hơn.
  2. Bằng cách sử dụng Significant Location Changes sử dụng A-GPS hoặc nhận vị trí qua wi-fi cung cấp dữ liệu ít chính xác hơn.

Chúng tôi có thể định cấu hình dịch vụ vị trí theo bất kỳ phương pháp nào trong hai phương pháp này nhưng tùy thuộc vào yêu cầu của ứng dụng là gì. Nếu ứng dụng là navigation app hoặc location tracking app thì chúng tôi nên sử dụng Standard Location Services nhưng trước khi sử dụng dịch vụ tiêu chuẩn, chúng tôi lưu ý rằng nếu bạn muốn có dữ liệu chính xác hơn thì bạn phải chịu battery consume more quickly. Nếu ứng dụng không yêu cầu cập nhật vị trí thường xuyên hơn và cũng là accuracy doesn't matter rất nhiều thì chúng tôi nên Significant Location Changes vì nó sẽ save a lot of battery tiêu thụ so với Dịch vụ vị trí chuẩn.

Dịch vụ vị trí chuẩn sử dụng giá trị desiredAccuracydistanceFilter để xác định xem có nên phân phối sự kiện hay không.

desiredAccuracy là thông số mà bạn có thể xác định mức độ chính xác mà bạn muốn từ phần cứng GPS. Nó sử dụng một số các hằng số được xác định trước như -

kCLLocationAccuracyBestForNavigation 
kCLLocationAccuracyBest 
kCLLocationAccuracyNearestTenMeters 
kCLLocationAccuracyHundredMeters 
kCLLocationAccuracyKilometer 
kCLLocationAccuracyThreeKilometers 

distanceFilter là tham số, nơi bạn có để xác định khoảng cách, có nghĩa là cho bao nhiêu khoảng cách chênh lệch bạn muốn hỏi phần cứng GPS để gửi cập nhật vị trí.

Trong trường hợp của bạn, bạn đang xử lý thông số tốc độ, vì vậy tôi đoán điều gì đó liên quan đến điều hướng. Vì vậy, bạn nên sử dụng Standard Location Services. Tôi nghĩ rằng bạn cũng đang làm điều đó nhưng vấn đề mà bạn đang phải đối mặt là sự chậm trễ giữa các cập nhật vị trí. Ở đây tôi đề nghị bạn sửa đổi giá trị desiredAccuracydistanceFilter của mình thành điều này -

[locationManager setDesiredAccuracy: kCLLocationAccuracyNearestTenMeters]; [locationManager setDistanceFilter: 10.0f];

bằng cách đặt giá trị cho điều này, bạn sẽ nhận được cập nhật vị trí trong ít hơn 1 giây nếu bạn đang lái xe.

Một điều nữa bạn phải lưu ý khi cập nhật vị trí, bạn nên kiểm tra giá trị timestamp để bỏ qua các cập nhật vị trí cũ. Bởi vì khi bạn bắt đầu locationManager bằng cách gọi startUpdatingLocation thì vị trí đầu tiên bạn nhận được có thể là vị trí cũ của bạn. Ngoài ra, bạn phải kiểm tra giá trị horizontalAccuracy vì vài bản cập nhật vị trí đầu tiên mà bạn nhận được luôn không chính xác và có thể có độ chính xác từ 1000 trở lên mà bạn không tìm kiếm. Vì vậy, bạn phải kiểm tra giá trị của nó để bỏ qua các cập nhật vị trí không chính xác.

Note: If you try with different accuracy and different distance filter value then you will be more clear about it how accurate data iPhone GPS hardware return. 
1

Bên cạnh những ví dụ tốt khác về cách sử dụng lõi Vị trí, cũng cần lưu ý kỹ thuật chung cho việc chuyển động tốt kết quả từ một cảm biến không-để-tuyệt vời (dịch vụ ví dụ: smartphone địa điểm) của Kalman Filtering.

Đó là rất nhiều toán và thử nghiệm và tinh chỉnh, nhưng nó cho phép bạn để có được những gì người dùng sẽ xem xét kết quả tốt hơn so với dữ liệu đơn giản từ cảm biến cung cấp.

Đây là những gì được sử dụng trong hệ thống điện tử và những thứ như hệ thống xử lý radar.

Các vấn đề liên quan