GPSから精度の高いデータを取得する方法/コード
iPhoneでGPSを使い位置情報を取得する方法/コードはネット上にたくさん出ています。またAppleのiPhone Dev Center にある LocateMe サンプルはとても有用です。しかし、これらの情報/コードを元にGPSで位置情報を取得してみると全然違う位置情報が取得されてしまったりします。
私も色々と試しながら、なんとか満足な位置情報を取得できる方法/コードをみつける事が出来ました。
取得方法ですが、以下のようにしました。
- GPS取得を開始し一定時間計測を行い、その中で一番 精度(newLocation.horizontalAccuracy)の高い値を使う
- 以下のようなデータは無視する
- 取得時間(newLocation.timestamp)が古いもの。これはLocateMeサンプルに書かれています。
- 精度の悪い(newLocation.horizontalAccuracy が一定以上大きい)データ
iPhoneのGPSは衛星から情報以外にWiFi基地局の位置情報、携帯電話基地局の位置情報などを使い、高い精度の値を短い時間で取得しようとします。したがって、かなり精度の低い情報が最初に取得されてしまう事もあります。都内を電車で移動しながら測定してみたところ 誤差 8km などという精度の低い情報が取得されてしまう事もありました。
コード
完全なコードではありませんが、主要な部分を書きました。
SampleViewController.h
#import <UIKit/UIKit.h> #import <CoreLocation/CoreLocation.h> @interface SampleViewController : UIViewController <CLLocationManagerDelegate> { IBOutlet UILabel *statusLable; // ステータス表示用 label IBOutlet UIActivityIndicatorView *activityIndicator; // GPS取得中にクルクルするindicator CLLocationManager *locationManager; CLLocation *bestEffortAtLocation; .... } @end
SampleViewController.m
#import "SampleViewController.h" #define GPS_MEASURING_TIME 3.0 #define GPS_DESIRED_ACCURACY 100.0 #define GPS_UNADOPTABLE_ACCURACY 2000.0 // GPS測定開始処理。ここではView表示時に測定開始 - (void)viewWillAppear:(BOOL)animated { locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; bestEffortAtLocation = nil; locationManager.desiredAccuracy = GPS_DESIRED_ACCURACY; // GPS測定開始 [locationManager startUpdatingLocation]; // GPS_MEASURING_TIME 秒後に 測定終了(stopUpdatingLocation:)メソッドを実行 [self performSelector:@selector(stopUpdatingLocation:) withObject:nil afterDelay:GPS_MEASURING_TIME]; NSLog(@"locationManager startUpdatingLocation"); statusLable.text = @"GPS 取得中..."; [activityIndicator startAnimating]; [super viewWillAppear:animated]; } // GPS情報の処理。OSからGPS情報取得時に呼び出される - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { // newLocation.descriptionで位置情報の全てが文字列で取得できる NSLog(@"newLoc: %@", newLocation.description); // 不要なデータは無視 if (-[newLocation.timestamp timeIntervalSinceNow] > 5.0) return; if (newLocation.horizontalAccuracy > GPS_UNADOPTABLE_ACCURACY) return; // 一番精度の高い情報を記憶 if (bestEffortAtLocation == nil || newLocation.horizontalAccuracy < bestEffortAtLocation.horizontalAccuracy) { [bestEffortAtLocation autorelease]; bestEffortAtLocation = [newLocation retain]; } } // GPSエラー処理 - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { [activityIndicator stopAnimating]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"GPS Error" message:@"Error" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; [alert release]; } // GPS測定終了処理 - (void)stopUpdatingLocation:(NSObject *)args { [locationManager stopUpdatingLocation]; [activityIndicator stopAnimating]; if (bestEffortAtLocation == nil) { statusLabel.text = @"GPS 取得失敗"; return; } statusLabel.text = @"GPS 取得完了"; float longitude = bestEffortAtLocation.coordinate.longitude; float latitude = bestEffortAtLocation.coordinate.latitude; // 位置情報を使った処理 .... .... }