Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Measuring tilt angle with CMMotionManager

Suppose you are holding an iphone/ipad vertically in front of you with the screen facing you, in portrait orientation. You tilt the device to one side, keeping the screen facing you. How do you measure that static tilt angle using CMMotionManager? It seems a simple question which should have a simple answer, yet I cannot find any method that does not disappear into quaternions and rotation matrices.

Can anyone point me to a worked example?

like image 394
millport Avatar asked Mar 26 '13 20:03

millport


People also ask

How do you find the angle of tilt?

One way to measure tilt angle with reference to the earth's ground plane, is to use an accelerometer. Typical applications can be found in the industry and in game controllers. In aircraft, the "ball" in turn coordinators or turn and bank indicators is sometimes referred to as an inclinometer.

How do you find the accelerometer on an angle?

Measuring Tilt Angle using One Axis If you want to measure tilt in both x and y axis with a 2-axis accelerometer then you can simply use sin-1(a) where a is the output from one axis of the accelerometer.


1 Answers

Look at gravity:

self.deviceQueue = [[NSOperationQueue alloc] init]; self.motionManager = [[CMMotionManager alloc] init]; self.motionManager.deviceMotionUpdateInterval = 5.0 / 60.0;  // UIDevice *device = [UIDevice currentDevice];  [self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical                                                         toQueue:self.deviceQueue                                                     withHandler:^(CMDeviceMotion *motion, NSError *error) {     [[NSOperationQueue mainQueue] addOperationWithBlock:^{         CGFloat x = motion.gravity.x;         CGFloat y = motion.gravity.y;         CGFloat z = motion.gravity.z;     }]; }]; 

With this reference frame (CMAttitudeReferenceFrameXArbitraryZVertical), if z is near zero, you're holding it on a plane perpendicular with the ground (e.g. as if you were holding it against a wall) and as you rotate it on that plane, x and y values change. Vertical is where x is near zero and y is near -1.


Looking at this post, I notice that if you want to convert this vector into angles, you can use the following algorithms.

If you want to calculate how many degrees from vertical the device is rotated (where positive is clockwise, negative is counter-clockwise), you can calculate this as:

// how much is it rotated around the z axis  CGFloat angle = atan2(y, x) + M_PI_2;           // in radians CGFloat angleDegrees = angle * 180.0f / M_PI;   // in degrees 

You can use this to figure out how much to rotate the view via the Quartz 2D transform property:

self.view.layer.transform = CATransform3DRotate(CATransform3DIdentity, -rotateRadians, 0, 0, 1); 

(Personally, I update the rotation angle in the startDeviceMotionUpdates method, and update this transform in a CADisplayLink, which decouples the screen updates from the angle updates.)

You can see how far you've tilted it backward/forward via:

// how far it it tilted forward and backward  CGFloat r = sqrtf(x*x + y*y + z*z); CGFloat tiltForwardBackward = acosf(z/r) * 180.0f / M_PI - 90.0f; 
like image 142
Rob Avatar answered Oct 02 '22 21:10

Rob