2

I would like to calculate compass heading to true north using CoreMotion (Not CoreLocation if possible). I have found some formulas, but working only when phone is flat on the table. Can someone help me find a way to calculate compass heading, which will work in every device position like compass app?

Damian Dudycz
  • 2,622
  • 19
  • 38
  • What is your reason for not using CoreLocation? – jbehrens94 Aug 06 '16 at 10:03
  • I'm making an AR app, that already uses CoreMotion to display objects. I need this compass for the radar view. I have noticed that when I use CoreLocation trueHeading, then sometimes dots on the radar gets a little shifted from what I see on the AR view. Probably some additional filtering is used to calculate heading by CoreLocation. Anyway if this would be possible to get heading from core motion attitude, then I think this problem would not exist. – Damian Dudycz Aug 06 '16 at 16:08

1 Answers1

2

I have found an answer. This is how I get compass heading in radians from CoreMotion:

guard let a = motionManager.deviceMotion?.attitude, g = motionManager.deviceMotion?.gravity else { return }

let deviceAngle = { () -> Double in
    switch interfaceOrientation {
    case .LandscapeLeft:  return -M_PI_2 + atan2(g.x, g.y)
    case .LandscapeRight: return  M_PI_2 + atan2(g.x, g.y)
    default:              return  M_PI   + atan2(g.x, g.y)
    }
}()

// Calculate Heading.
let cA = cos(a.yaw), sA = sin(a.yaw), sB = sin(a.pitch), cG = cos(a.roll), sG = sin(a.roll)
let rA = cA * sG + sA * sB * cG
let rB = sA * sG - cA * sB * cG
var compassHeading = -atan(rA / rB) + M_PI + deviceAngle
if rB > 0 { compassHeading += M_PI }

Still need to test this, but for now it seems to work.

Damian Dudycz
  • 2,622
  • 19
  • 38
  • What if you only had the CMMagneticField x, y, z (not attitude) and gravity? Is there a way to get compass heading from the that? – wcochran Oct 09 '21 at 17:14