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
    Feb 20 '17 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\$ Feb 20 '17 at 8:46
  • \$\begingroup\$ Do you rotate the quaternion or do you create a new one every frame? \$\endgroup\$
    – Bálint
    Feb 20 '17 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\$ Feb 20 '17 at 9:19

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.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.