2012-03-17 8 views
12

Ho un'app che ruota attorno al GPS del dispositivo e alle informazioni che ne derivano. È importante che i dati sulla posizione siano accurati e aggiornati. So che il dispositivo è limitato dal suo GPS e dai limiti del GPS, ma mi chiedevo se c'è qualcosa che posso fare per migliorare/migliorare le prestazioni del GPS di iPhone, in particolare nell'area della velocità. Poiché gli aggiornamenti di posizione sono in ritardo di circa 3-5 secondi rispetto alla posizione in tempo reale del dispositivo, anche la velocità rilevata dal gestore di località è troppo indietro rispetto al valore in tempo reale. Nel mio caso, è semplicemente troppo lungo. Capisco che potrebbe non esserci nulla che io possa fare, ma qualcuno ha avuto qualche successo nel migliorare la reattività del GPS dell'iPhone? Ogni piccola cosa fa la differenza.Responsività di CLLocationManager

Edit 1:

mia location manager è all'interno di una classe Singleton, come Apple consiglia.

Interno 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]; 

All'interno MapView.m (in cui il gestore di posizione viene effettivamente utilizzata):

- (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 
} 

Il trattamento dei dati avviene all'interno locationManager:didUpdateToLocation:fromLocation:. Non credo che l'inefficienza qui sia la causa del ritardo.

locationManager:didUpdateToLocation:fromLocation: chiama questo metodo per aggiornare l'interfaccia utente:

- (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]; 
} 

Con un paio di NSDates e NSLogs ho trovato che l'esecuzione dell'intero (non solo il metodo di aggiornamento etichetta) locationManager:didUpdateToLocation:fromLocation: non richiede più di circa 8ms sul mio iPhone 4; in altre parole, la gestione dei dati non è il problema.

+0

Mostraci come ottenere i dati sulla posizione. Questo ritardo non è normale. – sosborn

+0

Codice aggiunto. Posso postare di più se necessario. –

+0

3-5 secondi potrebbero essere un po 'esagerati; è tardi e la gamma 3-5 mi è venuta in mente per qualche motivo. Domani eseguirò alcuni test per ottenere numeri esatti. –

risposta

27

OK, un paio di cose potrebbero migliorare il tuo ritardo. Prima di tutto, usa sempre kCLLocationAccuracyBestForNavigation. Non esiste una reale differenza di utilizzo della batteria tra questo e kCLLocationAccuracyBest, entrambi utilizzano il GPS alla massima velocità. La principale differenza è nella post-elaborazione di Apple.

In secondo luogo, non è necessario filtrare per velocità == 0. Apple già esegue tale filtraggio: se la velocità del GPS scende sotto una certa soglia (circa 4 km/h), il sistema operativo presuppone che si sia fermi e sostituisce lo stesso valore di posizione per tutti i campioni successivi. Lo fa fino a quando non pensi di essere di nuovo in movimento. Presumo che lo facciano per evitare di "tremare" sulla mappa quando sei fermo. Infatti, la velocità scende a 0 già per l'ultimo valore reale di una sequenza di valori "immobili", quindi se filtri sulla velocità == 0 di quanto ti manca un campione GPS reale.

Sfortunatamente, non è possibile evitare tale filtraggio e ottenere veri campioni GPS. Ne ho parlato con Apple, e la loro risposta è stata che non hanno intenzione di cambiare il comportamento. kCLLocationAccuracyBestForNavigation effettua un filtro meno aggressivo rispetto a kCLLocationAccuracyBest, quindi è meglio usarlo.

In terzo luogo, probabilmente lo stai già facendo, ma assicurati di chiamare "setNeedsDisplay" sulla tua vista direttamente da "didUpdateFromLocation:", per assicurarti che la mappa sia effettivamente ridisegnata.

Se si fa tutto questo, si dovrebbe avere un ritardo di circa 1 secondo. Se vuoi migliorare il tempo di 1 secondo di quello che puoi provare a utilizzare le tecniche predittive. Dalle ultime due posizioni e dalla velocità specificata, puoi calcolare dove si trova la prossima posizione e visualizzare già quella posizione. Ho avuto risultati contrastanti con quello. Funziona bene per il movimento veloce che non cambia improvvisamente la velocità, come guidare una macchina.Funziona meno bene per movimenti più lenti come camminare o andare in bicicletta.

+0

Grazie mille '' 'kCLLocationAccuracyBestForNavigation'' mi ha davvero aiutato. I metodi di delega della posizione vengono eseguiti molto più rapidamente ora :) – Supertecnoboff

6

In iPhone possiamo configurare servizi di localizzazione con due metodi -

  1. Utilizzando Standard Location Services, cioè GPS satellitare che forniscono dati più precisi.
  2. utilizzando Significant Location Changes che utilizza A-GPS o ottenere la posizione tramite Wi-Fi che forniscono dati meno precisi.

Possiamo configurare i servizi di localizzazione con uno di questi due metodi, ma dipende da quale è l'esigenza dell'app. Se l'app è navigation app o location tracking app, allora dovremmo usare Standard Location Services ma prima di utilizzare i servizi standard abbiamo in mente che se vuoi dati più precisi allora devi soffrire con battery consume more quickly. Se l'app non richiede l'aggiornamento della posizione più frequentemente e anche il accuracy doesn't matter molto, allora dovremmo perché sarà pari a save a lot of battery consumare come confronto al servizio di posizione standard.

Il servizio di posizione standard utilizza il valore desiredAccuracy e distanceFilter per determinare se e quando consegnare l'evento.

desiredAccuracy è il parametro in cui è possibile definire l'accuratezza desiderata dall'hardware GPS. Esso utilizza alcune costanti predefinite come -

kCLLocationAccuracyBestForNavigation 
kCLLocationAccuracyBest 
kCLLocationAccuracyNearestTenMeters 
kCLLocationAccuracyHundredMeters 
kCLLocationAccuracyKilometer 
kCLLocationAccuracyThreeKilometers 

distanceFilter è il parametro in cui è necessario definire la distanza, mezzi per la quantità di gap distanza che si vuole chiedere l'hardware GPS per inviare un aggiornamento di posizione.

Nel tuo caso hai a che fare con il parametro di velocità, quindi credo che sia qualcosa relativo alla navigazione. Quindi dovresti usare Standard Location Services. Penso che lo stiate facendo anche voi, ma il problema che state affrontando è il ritardo tra gli aggiornamenti di posizione. Qui ti suggerisco di modificare il tuo valore desiredAccuracy e distanceFilter -

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

impostando valori su questo si otterrà l'aggiornamento della posizione in meno di 1 secondo se si sta guidando.

Un'altra cosa che devi mettere in mente è che quando ottieni l'aggiornamento della posizione dovresti controllare il suo valore timestamp per ignorare i vecchi aggiornamenti di posizione. È perché quando si avvia locationManager chiamando startUpdatingLocation, la prima posizione che si ottiene potrebbe essere la posizione precedente. Inoltre devi verificare il valore horizontalAccuracy perché i primi aggiornamenti di posizione che ottieni non sono sempre precisi e potrebbero avere una precisione di 1000 o più che non stai cercando. Quindi devi controllare il suo valore per ignorare gli aggiornamenti di posizione imprecisi.

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

A parte gli altri buoni esempi di come utilizzare Core Location, anche tenere a mente la tecnica generale per ottenere buoni risultati da una cinematica non-così-grande sensore (servizi di localizzazione ad esempio smartphone) di Kalman Filtering.

È un sacco di matematica, test e tweaking, ma consente di ottenere ciò che gli utenti considererebbero risultati migliori rispetto ai dati semplici forniti dal sensore.

Questo è ciò che viene utilizzato in avionica e cose come i sistemi di elaborazione radar.

Problemi correlati