In a iOS prototype I use a combination of CMDeviceMotion.deviceMotion.yaw and CLHeading.trueHeading to make stable compass heading that is responsive and accurate. This work
The problem is a bit confusing because there are at least two different ways to think about Yaw. One is from the phone's perspective, and one from the world perspective.
I'll use this image from Apple to explain further:
If the phone is flat on a table:
If the phone is flat against a wall:
Use blkhp19's code above which sums up yaw and roll. If you import SwiftUI
, you can leverage the Angle
struct to make radian + degrees conversion easier:
let yaw = Angle(radians: deviceMotion.attitude.yaw)
let roll = Angle(radians: deviceMotion.attitude.roll)
var compassHeading: Angle = yaw + roll
if roll.degrees < 0 && yaw.degrees < 0 {
compassHeading = Angle(degrees: 360 - (-1 * compassHeading.degrees))
}
You'll need to use atan2
and inspect gravity as in this example.
let rotation = atan2(data.gravity.x,
data.gravity.y) - .pi
Also note that if you don't need the actual angle, and all you need is the relationship (e.g. isPhoneUpright), you can simply read gravity values for those.