わふうの人が書いてます。

iOSアプリケーション開発、BLEのファームウェアとハードウェア試作のフリーランスエンジニア。

iOS8の高度計(気圧計)

iOS8の高度計(気圧計)

iPhone6 Plus および iPhone6には、気圧計が入っています。

今どき気圧計は高精度で、気圧の値の変化から、1メートル程度の高さの変化が十分にわかります。これがあると、例えば、ユーザが今ビルの何階にいるかがわかるわけです。

サンプルコードはこんな感じ。

1秒に1回の頻度で、気圧値が更新されて通知されてきます。相対高度(relativeAltitude)は、前回の通知から今回の通知までの高度の変化分を通知しています。今の実装は、おそらく、単純に気圧値の差分に定数をかけるとか、そんな感じなのかもしれません。

更新頻度を指定する方法は、今のところないみたい。

ハードウェから見ると、iPhone6の分解 http://www.techinsights.com/teardown.com/apple-iphone-6/ から、センサは Bosch Sensortec BMP280 Barometric Sensor

仕様を見ると、動作範囲(full accuracy) 300 ~ 1100 hPa、平均測定時間 5.5ミリ秒、分解能0.01 hPa (< 10cm)、温度 0.1度、絶対精度(950 ~ 1050 hPa) +- 1hPa、相対精度 +ー0.12 hPa (高さ+ー1m相当)。 (1hPa(ヘクトパスカル) は 100パスカル。)

センサの仕様から、今の振る舞いは、ほぼセンサの値をそのまま利用する単純な実装をしているのかな、と思いました。

Githubのサンプルアプリ。
https://github.com/reinforce-lab/ObjC_Codes/tree/master/barometer

ここの気圧と高度の計算式で、標高ゼロメートル、温度27度(絶対温度で300K)のときに、1mあたりの気圧の変化は、11パスカル。

http://keisan.casio.jp/has10/SpecExec.cgi?path=05000000.%95%A8%97%9D%8C%F6%8E%AE%8FW%2F02100100.%92n%8Aw%2F12000200.%95W%8D%82%82%A9%82%E7%8BC%88%B3%82%F0%8Cv%8EZ%2Fdefault.xml

アプリの値の変化を見ていると、たしかにそれっぽい感じで、とれている。

ソースコード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@interface ViewController () {
CMAltimeter *_altimater;
bool _isFirstSample;
double _currentValue;
double _averageValue;
double _altitudValue;
}

@property (weak, nonatomic) IBOutlet UILabel *currentValueTextLabel;
@property (weak, nonatomic) IBOutlet UILabel *averageValueTextLabel;
@property (weak, nonatomic) IBOutlet UILabel *variationValueTextLabel;
@property (weak, nonatomic) IBOutlet UILabel *warningTextLabel;
@property (weak, nonatomic) IBOutlet UILabel *altitudeValueTextLabel;

@end


@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.
_isFirstSample = YES;

self.warningTextLabel.hidden = [CMAltimeter isRelativeAltitudeAvailable];
if([CMAltimeter isRelativeAltitudeAvailable]) {
_altimater = [[CMAltimeter alloc] init];
[_altimater startRelativeAltitudeUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAltitudeData *data, NSError *error) {
[self altitudeDataHandlr:data error:error];
}];
}
}

-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];

[_altimater stopRelativeAltitudeUpdates];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

-(void)altitudeDataHandlr:(CMAltitudeData *)data error:(NSError *)error {
if(error != nil) return;

double altitude = [[data relativeAltitude] doubleValue];
double pressure = [[data pressure] doubleValue];

_currentValue = pressure;
_altitudValue = altitude;

if(_isFirstSample) {
_averageValue = pressure;
} else {
_averageValue = 0.1 * _currentValue + (1 - 0.1) * _averageValue;
}
_isFirstSample = NO;

self.currentValueTextLabel.text = [NSString stringWithFormat:@"%1.5e", _currentValue];
self.averageValueTextLabel.text = [NSString stringWithFormat:@"%1.5e", _averageValue];
self.altitudeValueTextLabel.text = [NSString stringWithFormat:@"%1.3e", _altitudValue];

}