Updated 20 May 2024
The iPhone packs in a number of sensors. We’ve covered the accelerometer, gyroscope, and magnetometer, and will now take a look at the built in barometer which first appeared in the iPhone 6 and 6 plus smartphones several years ago.
The barometer can be used to detect elevation changes by sensing the changes in air pressure as the phone increases or decreases in altitude.
In todays tutorial we’ll take a look at CMAltimeter which is the class we use to access the barometer.
CMAltimeter Tutorial
Lets begin by creating a single view application. Open up Main.storyboard and add the labels as seen in the image. We have 4 labels here. The two on the left indicate what the reading represents, and on the right we will use these labels to update the readings on screen as provided by CMAltimeter.
The numbers we are provided with are meters for relative altitude, and kilopascal for pressure although we will convert this to hPa which is a common measure for pressure. The difference between then is that you just multiply by 10 to convert from kilopascal to hPa.
First, you need to import CoreMotion at the top:
import CoreMotion
In ViewController.swift, add the following IBOutlets:
@IBOutlet weak var relativeAltitude: UILabel!
@IBOutlet weak var pressure: UILabel!
Next, open up a split view with the storyboard on the left with the view controller selected, and on the right the ViewController.swift file. You can then drag from the small circle on the line number on the left over to the appropriate UILabel on the storyboard as seen in the screenshot below.
Below the IBOutlets, add the following:
let altimeter = CMAltimeter()
This creates our CMAltimeter that we need to kick off the service.
Add the following code to viewDidLoad:
if CMAltimeter.isRelativeAltitudeAvailable() {
altimeter.startRelativeAltitudeUpdates(to: OperationQueue.main) { (data, error) in
DispatchQueue.main.async {
if let validData = data {
self.relativeAltitude.text = String.init(format: "%.1fM", validData.relativeAltitude.floatValue)
self.pressure.text = String.init(format: "%.2f hPA", validData.pressure.floatValue * 10)
} else {
self.relativeAltitude.text = "N/A"
self.pressure.text = "N/A"
}
}
}
}
On line 1 we are checking if the device has a barometer. If it’s a 5s or older, this will return false, and we won’t need to start the updates.
Line 2 we call startRelativeAltitudeUpdates: and put it on the main operation queue. The handler used here is the CMAltitudeHandler which provides us with an optional CMAltitudeData object as well as an optional error.
Line 3 we dispatch to the main queue because of the UILabel.text updates later on.
Line 4 we check if there is data available. If the user has declined the prompt to access motion data, then this will be nil and will cause a crash. We put the code in an if let to validate if there is data, and if so, we fetch it and display it with lines 5 and 6.
The output is made a little more friendly for the user. For relative altitude in meters, we’ll drop the precision to 1 decimal place. For pressure, we’ll convert kilopascal to hPa and provide 2 decimal places.
On line 5, we set the relativeAltitude.text attribute by initialising a string with format. The format is %.1f which means that we want to replace that with a float with 1 decimal place. The M afterwards is the actual string, which is appended to the end of the number (so it provides 0.1M as an example). We then get the validData.relativeAltitude, but then access the floatValue of that property.
Line 6 is very similar, except we specify two decimal places. We also have a space and hPa to be appended to the value. We get the pressure almost the same way as the relative altitude, but we multiply that result by 10 to convert from kilopascal to hPa.
One final adjustment is to add the NSMotionUsageDescription to info.plist. Navigate to that file, then right click on “Information Property List” at the top left of the list. Select “Add Row”. On the left side paste in NSMotionUsageDescription, and on the right, provide a reason that will display to the user why you want to access their motion usage. When you paste in the NSMotionUsageDescription, it will be changed to Privacy – Motion Usage Description because the plist file shows friendly names.
Challenges
Please be aware that the relative altitude starts at zero from whatever altitude you start the service. The numbers given are the relative altitude. When it starts at zero and your altitude changes by 3 meters, the change should show 3 meters or there abouts. The mems type barometer isn’t 100% accurate from my testing. With my phone resting on the desk next to me I’m seeing changes of around 20 cm either way. At the moment it’s sitting on -0.1M for me. But, it should be accurate enough for apps that might use it to calculate elevation climbed. A 20cm or so difference won’t make that much of a difference.
Also, hPa appears to be a little lower than what a weather reporting app indicates to me. The DarkSky API indicates that pressure in the area where I am should be around 1025.9 at the moment. Perhaps augmenting the hPa reading with a call to a weather API could be useful in adjusting the pressure. Likewise, using the Google Elevation API might also be a good way to get current elevation based on your coordinates. For my location, Google suggests that my elevation if stood on the ground would be 203.097 meters. This might also be useful if you wanted your actual elevation, and then used the barometer to adjust that number based on where you moved to.
Closing
Overall, the barometer is a useful sensor. From what I understand, it is used for counting how many floors you ascended or descended throughout the day. It can also be used by running/cycling or other similar apps that track your elevation throughout a walk.
You can download the completed project here.
Morten Engelstad says
Good guide, but at the beginning you have to add ‘import CoreMotion’. Works in the downloadable example.
MatthewN says
Thank you. I added it.
Alexey Schu says
Good guide! Thank you! I made this, but data is updated no more than 1 time per second. how can I make them update faster?
MatthewN says
I don’t believe there is a way to increase the frequency of updates. I think it is managed by iOS with no setting (unlike the gyroscope which can be adjusted).