Подтвердить что ты не робот

Ответ CLLocationManager

У меня есть приложение, которое вращается вокруг устройства GPS и информации, поступающей от него. Важно, чтобы данные о местоположении были точными и актуальными. Я знаю, что устройство ограничено GPS и GPS-ограничениями, но мне было интересно, есть ли что-нибудь, что я могу сделать, чтобы настроить/улучшить производительность iPhone GPS, особенно в области скорости. Поскольку обновления местоположения отстают примерно на 3-5 секунд от местоположения устройства в режиме реального времени, скорость, сообщаемая менеджером местоположений, также значительно отстает от значения реального времени. В моем случае это слишком долго. Я понимаю, что не может быть ничего, что я могу сделать, но кто-нибудь имел успех в улучшении чувствительности iPhone GPS? Каждый бит имеет значение.

Изменить 1:

Мой менеджер местоположений находится в классе singleton, как рекомендует Apple.

Внутри 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];

Внутри MapView.m(где фактически используется менеджер местоположений):

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

Обработка данных происходит внутри locationManager:didUpdateToLocation:fromLocation:. Я не считаю, что неэффективность здесь является причиной отставания.

locationManager:didUpdateToLocation:fromLocation: вызывает этот метод для обновления пользовательского интерфейса:

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

С несколькими NSDates и NSLogs я обнаружил, что выполнение всего locationManager:didUpdateToLocation:fromLocation: (а не только метода обновления меток) никогда не занимает более 8 мс на моем iPhone 4; другими словами, обработка данных не является проблемой.

4b9b3361

Ответ 1

Хорошо, пара вещей может улучшить ваше отставание. Прежде всего, всегда используйте kCLLocationAccuracyBestForNavigation. Нет реальной разницы в использовании батареи между этим и kCLLocationAccuracyBest, они оба используют GPS на максимальной скорости. Основное различие заключается в последующей обработке, которую делает Apple.

Во-вторых, нет необходимости фильтровать скорость == 0. Apple уже делает эту фильтрацию: если ваша скорость от GPS падает ниже определенного порога (около 4 км/ч), ОС предполагает, что вы стоите на месте, и он заменяет одно и то же значение местоположения для всех последующих выборок. Он делает это, пока не подумает, что вы снова двигаетесь. Я предполагаю, что они делают это, чтобы избежать "дрожания" на карте, когда вы стоите на месте. Фактически, скорость падает до 0 уже для последнего действительного значения последовательности "стоячих" значений, поэтому, если вы фильтруете на скорости == 0, вам не хватает одного реального образца GPS.

К сожалению, они не могут избежать этой фильтрации и получить реальные образцы GPS. Я поговорил с Apple об этом, и их ответ заключался в том, что они не собираются менять поведение. kCLLocationAccuracyBestForNavigation делает менее агрессивную фильтрацию, чем kCLLocationAccuracyBest, поэтому лучше всего использовать это.

В-третьих, вы, вероятно, уже это делаете, но убедитесь, что вы вызываете "setNeedsDisplay" в своем представлении прямо из "didUpdateFromLocation:", чтобы убедиться, что карта действительно перерисована.

Если вы все это сделаете, у вас должно быть отставание около 1 секунды. Если вы хотите улучшить на 1 секунду, вы можете попытаться использовать прогностические методы. Из последних двух мест и заданной скорости вы можете рассчитать, где, вероятно, будет следующее местоположение, и уже отображать это местоположение. У меня были смешанные результаты. Он отлично работает для быстрого движения, которое не меняет скорость внезапно, как вождение автомобиля. Он работает менее эффективно для медленного движения, например, ходьбы или езды на велосипеде.

Ответ 2

В iPhone мы можем настроить службы определения местоположения двумя способами -

  • Используя Standard Location Services, это спутниковый GPS, который предоставляет вам более точные данные.
  • Используя Significant Location Changes, который использует A-GPS или получает местоположение через wi-fi, которые предоставляют менее точные данные.

Мы можем настроить службы определения местоположения любым из этих двух методов, но это зависит от того, что является требованием к приложению. Если приложение является navigation app или location tracking app, тогда мы должны использовать Standard Location Services, но перед использованием стандартных сервисов мы имеем в виду, что если вы хотите получить более точные данные, вам придется страдать с помощью battery consume more quickly. Если приложение не требует более частого обновления местоположения, а также accuracy doesn't matter, тогда мы должны Significant Location Changes, потому что он будет save a lot of battery потреблять по сравнению со стандартной службой определения местоположения.

Стандартная служба определения местоположения использует desiredAccuracy и distanceFilter значение, чтобы определить, будет ли и когда отправляться событие.

desiredAccuracy - это параметр, в котором вы можете определить, какую точность вы хотите получить от оборудования GPS. Он использует некоторые предопределенные константы как -

kCLLocationAccuracyBestForNavigation
kCLLocationAccuracyBest
kCLLocationAccuracyNearestTenMeters
kCLLocationAccuracyHundredMeters
kCLLocationAccuracyKilometer
kCLLocationAccuracyThreeKilometers

distanceFilter - это параметр, в котором вы должны определить расстояние, означает, сколько промежутков между расстояниями вы хотите попросить оборудование GPS отправить обновление местоположения.

В вашем случае вы имеете дело с параметром скорости, поэтому я думаю, что это связано с навигацией. Поэтому вы должны использовать Standard Location Services. Я думаю, вы тоже это делаете, но проблема, с которой вы столкнулись, - это отставание от обновлений местоположения. Здесь я предлагаю вам изменить значение desiredAccuracy и distanceFilter на это -

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

установив значения на это, вы получите обновление местоположения менее чем за 1 секунду, если вы едете.

Еще одна вещь, о которой вы должны подумать, что когда вы получаете обновление местоположения, вы должны проверить его значение timestamp, чтобы игнорировать старые обновления местоположения. Потому что, когда вы начинаете locationManager, вызывая startUpdatingLocation, тогда первое место, которое вы получите, может быть вашим старым местоположением. Также вы должны проверить значение horizontalAccuracy, потому что первые несколько обновлений местоположения, которые вы получаете, всегда не точны и могут иметь точность в 1000 или более, которые вы не ищете. Поэтому вы должны проверить его значение, чтобы игнорировать неточное обновление местоположения.

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.

Ответ 3

Помимо других хороших примеров использования Core Location, также учитывайте общую технику получения хорошей кинематики от не очень большого датчика (например, службы определения смартфона) Фильтр Калмана.

Это много математики и тестирования и настройки, но это позволяет вам получать то, что пользователи будут рассматривать лучше, чем простые данные от датчика.

Это то, что используется в авионике и таких вещах, как системы радиолокационной обработки.