2012-03-17 15 views
12

Tengo una aplicación que gira en torno al GPS del dispositivo y la información que proviene de él. Es importante que los datos de ubicación sean precisos y estén actualizados. Sé que el dispositivo está limitado por su GPS y los límites del GPS, pero me preguntaba si hay algo que pueda hacer para modificar/mejorar el rendimiento del iPhone GPS, particularmente en el área de velocidad. Debido a que las actualizaciones de ubicación se retrasan de 3 a 5 segundos detrás de la ubicación en tiempo real del dispositivo, la velocidad informada por el administrador de ubicación también está muy por detrás del valor en tiempo real. En mi caso, eso es simplemente demasiado largo. Entiendo que quizás no haya nada que pueda hacer, pero ¿alguien ha tenido éxito en mejorar la capacidad de respuesta del iPhone GPS? Cada poco hace la diferencia.Capacidad de respuesta de CLLocationManager

Edición 1:

Mi manager ubicación es dentro de una clase Singleton, ya que Apple recomienda.

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

Dentro MapView.m (donde se utiliza en realidad el jefe de locación):

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

El manejo de datos ocurre en el interior locationManager:didUpdateToLocation:fromLocation:. No creo que la ineficacia aquí sea la causa del retraso.

locationManager:didUpdateToLocation:fromLocation: llama a este método para actualizar la interfaz de usuario:

- (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 par de NSDates y NSLogs he encontrado que la ejecución de la totalidad (no sólo el método de actualización etiqueta) locationManager:didUpdateToLocation:fromLocation: nunca toma más de unos 8ms en mi iPhone 4; en otras palabras, el manejo de datos no es el problema.

+0

Muestre cómo obtiene los datos de ubicación. Ese retraso no es normal. – sosborn

+0

Código agregado. Puedo publicar más si es necesario. –

+0

3-5 segundos puede ser un poco exagerado; es tarde y el rango 3-5 acaba de aparecer en mi cabeza por alguna razón. Mañana haré algunas pruebas para obtener los números exactos. –

Respuesta

27

OK, un par de cosas podrían mejorar su retraso. Antes que nada, use kCLLocationAccuracyBestForNavigation siempre. No existe una diferencia real de uso de la batería entre eso y kCLLocationAccuracyBest, ambos usan el GPS a la velocidad máxima. La principal diferencia está en el procesamiento posterior que hace Apple.

En segundo lugar, no es necesario filtrar la velocidad == 0. Apple ya hace ese filtrado: si su velocidad del GPS cae por debajo de un cierto umbral (alrededor de 4 km/h), el sistema operativo asume que está parado y sustituye el mismo valor de ubicación para todas las muestras posteriores. Lo hace hasta que cree que te estás moviendo de nuevo. Supongo que lo hacen para evitar el "tintineo" en el mapa cuando estás quieto. De hecho, la velocidad cae a 0 ya por el último valor real de una secuencia de valores de "inmovilización permanente", por lo que si filtra en velocidad == 0 entonces le falta una muestra de GPS real.

Desafortunadamente, no es forma de evitar ese filtrado y obtener muestras de GPS reales. Hablé con Apple al respecto, y su respuesta fue que no van a cambiar el comportamiento. kCLLocationAccuracyBestForNavigation filtra menos agresivamente que kCLLocationAccuracyBest, por lo que es mejor usarlo.

En tercer lugar, probablemente ya esté haciendo esto, pero asegúrese de llamar a "setNeedsDisplay" en su vista directamente desde "didUpdateFromLocation:", para asegurarse de que el mapa se vuelva a dibujar realmente.

Si hace todo eso, debe tener un retraso de aproximadamente 1 segundo. Si quiere mejorar en 1 segundo, puede intentar usar técnicas predictivas. Desde las dos últimas ubicaciones, y la velocidad dada, puede calcular dónde será la próxima ubicación y ya mostrar esa ubicación. He tenido resultados mixtos con eso. Funciona bien para un movimiento rápido que no cambia la velocidad de repente, como conducir un automóvil.Funciona menos bien para movimientos más lentos como caminar o andar en bicicleta.

+0

Muchas gracias '' 'kCLLocationAccuracyBestForNavigation''' realmente me ayudó. Los métodos de delegado de ubicación se ejecutan mucho más rápido ahora :) – Supertecnoboff

6

En iPhone podemos configurar los servicios de localización por dos métodos -

  1. Mediante el uso de Standard Location Services, es decir satélite GPS que proporcionan datos más precisos.
  2. Al usar Significant Location Changes que usa A-GPS u obtiene la ubicación a través de wi-fi que proporciona datos menos precisos.

Podemos configurar los servicios de ubicación mediante cualquiera de estos dos métodos, pero depende de cuál sea el requerimiento de la aplicación. Si la aplicación es navigation app o location tracking app entonces deberíamos usar Standard Location Services pero antes de usar servicios estándar tenemos en cuenta que si quiere datos más precisos, entonces tiene que sufrir con battery consume more quickly. Si la aplicación no requiere la actualización de la ubicación con más frecuencia y también el accuracy doesn't matter mucho, entonces deberíamos Significant Location Changes porque consumirá en comparación con el servicio de ubicación estándar de save a lot of battery.

El servicio de ubicación estándar usa el valor desiredAccuracy y distanceFilter para determinar si se debe entregar el evento y cuándo.

desiredAccuracy es el parámetro donde puede definir cuánta precisión desea del hardware del GPS. Utiliza algunas constantes predefinidas como -

kCLLocationAccuracyBestForNavigation 
kCLLocationAccuracyBest 
kCLLocationAccuracyNearestTenMeters 
kCLLocationAccuracyHundredMeters 
kCLLocationAccuracyKilometer 
kCLLocationAccuracyThreeKilometers 

distanceFilter es el parámetro en el que tiene que definir la distancia, medios para la cantidad de brecha de distancia que desea pedir el hardware GPS para enviar una actualización de ubicación.

En su caso, usted está tratando con el parámetro de velocidad, así que supongo que es algo relacionado con la navegación. Entonces debería usar Standard Location Services. Creo que también lo estás haciendo, pero el problema al que te enfrentas es el retraso entre las actualizaciones de ubicación. Aquí le sugiero que modifique su valor desiredAccuracy y distanceFilter a este -

[conjunto de locationManagerDescriptedAccuracy: kCLLocationAccuracyNearestTenMeters]; [setManager setDistanceFilter: 10.0f];

estableciendo valores para esto, obtendrá la actualización de la ubicación en menos de 1 segundo si está conduciendo.

Una cosa más que debe recordar es que cuando obtenga la actualización de la ubicación, debe verificar su valor timestamp para ignorar las actualizaciones de ubicación anteriores. Es porque cuando comienzas locationManager llamando al startUpdatingLocation, la primera ubicación que obtengas puede ser tu ubicación anterior. También debe verificar el valor horizontalAccuracy porque las primeras actualizaciones de ubicación que obtiene no siempre son precisas y pueden tener una precisión de 1000 o más que no está buscando. Por lo tanto, debe verificar su valor para ignorar actualizaciones de ubicación inexactas.

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

Aparte de los otros buenos ejemplos de cómo utilizar Core Location, también tener en cuenta la técnica general para conseguir buenos resultados cinemática de un no tan gran sensor (por ejemplo, servicios de localización de teléfonos inteligentes) de Kalman Filtering.

Es un montón de matemáticas y pruebas y ajustes, pero le permite obtener lo que los usuarios considerarían mejores resultados que los datos simples del sensor.

Esto es lo que se usa en aviónica y cosas como los sistemas de procesamiento de radar.

Cuestiones relacionadas