0

I have been working on an app that uses a side-to-side tilt motion gesture. I have it working using the CMDeviceMotion data via the CMQuaternion values to get "roll" via Using quaternion instead of roll, pitch and yaw to track device motion but I have one weird bit of behaviour where the output will sometimes work perfectly and others not.

The app is locked to landscape orientation (both ways) but I have noticed that if I start the app held in portrait orientation my roll code works perfectly with a pi/2 modifier. If I open the app with the device held in landscape it works on pitch with no modifier.

The problem is that I have no way of knowing which to use! Is there some way of detecting or reseting the frame of reference?

UPDATE:

I tell a lie, if I start in landscape orientation it seems to just pick a random axes :( I assume this is again a Gimbal Lock thing but the original question still applies - how do I get this to be consistent when I start the device in a landscape orientation?

UPDATE 2:

Some token code (coming from a NSNotification) for people who can't read and feel the need to downvote without.

CMDeviceMotion *data = [[note userInfo] valueForKey:@"data"];
CMQuaternion quat = data.attitude.quaternion;
CGFloat roll  = atan2(2*(quat.y*quat.w - quat.x*quat.z), 1 - 2*quat.y*quat.y - 2*quat.z*quat.z);

CGFloat pitch = atan2(2*(quat.x*quat.w + quat.y*quat.z), 1 - 2*quat.x*quat.x - 2*quat.z*quat.z);
CGFloat yaw   = 2*(quat.x*quat.y + quat.w*quat.z);


NSLog(@" - - ");
NSLog(@"raw roll: %f",roll);
NSLog(@"raw pitch: %f",pitch);
NSLog(@"raw yaw: %f",yaw);

NSLog(@"q.x: %f",quat.x);
NSLog(@"q.y: %f",quat.y);
NSLog(@"q.z: %f",quat.z);
NSLog(@"q.w: %f",quat.w);

Launched from startDeviceMotionUpdatesToQueue in AppDelegate.

This is irrelevant however as the issue is that the quaternion data is stable when the device is in a portrait orientation at launch but not with a landscape orientation. What I choose to do with the device data is a totally separate issue.

This is a similar issue without a satisfactory answer (or any code in the question :|) CMDeviceMotion yaw values unstable when iPhone is vertical

Community
  • 1
  • 1
Martin
  • 1,135
  • 1
  • 8
  • 19
  • If you have code that isn't working as you expect, _show_ your code. Your question talks only in the vaguest generalities; who knows what you're doing, or even what the problem is? – matt Aug 04 '16 at 16:58
  • The code isn't where the issue is. I have taken a calculation using CMQuaternions as I have said but the device output differs and is unstable based on launch orientation - how is that related to my code? – Martin Aug 05 '16 at 09:35
  • "how is that related to my code?" Because the only way you know what the "device output" is, is through your code. – matt Aug 05 '16 at 15:44
  • Okay, so you see, you have now added the code and sure enough, I was right. I'm putting my answer back. I was spot on. You are doing exactly what I said you cannot do. – matt Aug 05 '16 at 15:44
  • Ok, I might be being ignorant of the quirks of quaternions and rotationMatrices (I am) but isn't my calculated roll just a transform of those numbers? Assuming not... How would I go about finding out which way is down then selectively detecting a tip left or right - it's for a fake water level progress widget thing. Do you have a link to a decent primer? – Martin Aug 05 '16 at 15:57
  • You would do what I said in my answer. For example, having obtained the `rotationMatrix`, you can _apply_ that matrix in your code (for example, as a transform to some visible view). You do not _convert_ to individual angles. (The second half of this section of my book shows how to apply the `rotationMatrix` as a layer's `transform`: http://www.apeth.com/iOSBook/ch35.html#_gyroscope) – matt Aug 05 '16 at 16:01

1 Answers1

0

my roll code works perfectly

Your "roll code" doesn't work perfectly. You should not have any "roll code". In a situation where you can get gimbal lock, don't use Euler angles at all. You cannot "reduce" to Euler angles such as roll. Instead, use quaternions or (easier) rotationMatrix and stay in that world. You cannot "calculate" your way out of the problem by starting with the quaternion and converting to an Euler angle. And that is exactly what you are trying to do. If you think this is possible, you have not understood what gimbal lock is (or how atan works, perhaps).

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I am using quaternions to calculate a roll for that reason. If I trace all the numbers out I get different sets that respond to tilting to the side if I start in landscape but one consistent set of behaviour if I start in portrait. – Martin Aug 04 '16 at 11:22