I am doing an app with a functionality like a 3D compass, it can point to the direction where I want. The code is

extension AR: CLLocationManagerDelegate{
    func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {

        heading = Float(newHeading.trueHeading)

        motionManager.deviceMotionUpdateInterval = 1.0/60.0
        if motionManager.isDeviceMotionAvailable {
            motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: { (devMotion, error) -> Void in
                self.node.orientation = self.orient(q: (self.motionManager.deviceMotion?.attitude.quaternion)!,angle: self.heading)




func orient(q:CMQuaternion,angle:Float) -> SCNQuaternion{
    let gq1: GLKQuaternion = GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(-angle), 0, 0, 1)
    // add a rotation in z axis
    let gq2: GLKQuaternion = GLKQuaternionMake(Float(q.x), Float(q.y), Float(q.z), Float(q.w))
    // the current orientation
    let qp: GLKQuaternion = GLKQuaternionMultiply(gq1, gq2)
    // get the "new" orientation
    var rq = CMQuaternion()
    rq.x = Double(qp.x)
    rq.y = Double(qp.y)
    rq.z = Double(qp.z)
    rq.w = Double(qp.w)
    return SCNQuaternion(Float(rq.x), Float(rq.y), Float(rq.z), -Float(rq.w))

At first I got the device's orientation to apply to my object ("node") in z axis so that it can point to the right direction. However, I figure out there is gimbal lock coming. When I rotate the device in x & y axis, the object can rotate in x & y axis as well. But if I rotate the device in z axis, there are two situations:

one, the device is holding up, the object still rotates in y axis (Seems rotation in z axis disappears).

two, the device is lying down, the object rotates in z axis.

How can I avoid first situation?

  • \$\begingroup\$ You literally tagged the question with "quaternion", so you probably have your answer... \$\endgroup\$
    – Bálint
    Commented Feb 20, 2017 at 8:43
  • \$\begingroup\$ Actually none of them in my mind works... Now I have totally no idea about it. Did I do wrong quaternion calculation? \$\endgroup\$ Commented Feb 20, 2017 at 8:46
  • \$\begingroup\$ Do you rotate the quaternion or do you create a new one every frame? \$\endgroup\$
    – Bálint
    Commented Feb 20, 2017 at 8:51
  • \$\begingroup\$ I make a new quaternion(let's call it rotation quaternion) which rotates around z axis and then I multiply with another quaternion( get from iPhone's sensor, let's call it sensor quaternion) to get the desire quaternion. Since I set motionManager.deviceMotionUpdateInterval = 1.0/60.0, I believe the three quaternions (rotation quaternion, sensor quaternion, desire quaternion) will change continuously so that the object can point to the right direction at any time. \$\endgroup\$ Commented Feb 20, 2017 at 9:19

1 Answer 1


Actually there is no gimbal lock. The reason is that if I rotate the device around z axis, the direction data comes out continuously. As a result, I can't use CLLocationManagerDelegate to achieve my goal. This thread is what I want.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .