In my app I need to display a horizontal line on the screen, so I've decided to turn to CMMotionManager. Here's my code, it's quite straightforward:
if ([_motionManager isDeviceMotionAvailable]) {
if ([_motionManager isDeviceMotionActive] == NO) {
[_motionManager setDeviceMotionUpdateInterval:0.1];
[_motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical toQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion *motion, NSError *error){
CMQuaternion quat = _motionManager.deviceMotion.attitude.quaternion;
double yaw = asin(2*(quat.x*quat.z - quat.w*quat.y));
// drawing line stuff.
}];
}
} else {
NSLog(#"Motion not avaliable!");;
}
Eveything works fine when I put my phone in upward portrait mode. But since the asin method gives me only a number in range of (-pi/2,+pi/2), I can't draw a perfectly horizontal line if I hold my phone in landscape mode, or upside-down portrait mode, the line just stuck at angle of around -pi/2 or pi/2, and won't keep rotating.
So, how can I fix this, is there any more general way to handle quaternion? Thanks in advance!
Related
Based on device movement i need to set the frames to the view. I had tried using core motion, there I'm getting x, y, z values, but unable to get device moved distance based on those coordinates.
[self.manager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
xValue = motion.userAcceleration.x;
yValue = motion.userAcceleration.y;
zValue = motion.userAcceleration.z;
}];
What happens is you can try to calculate this distance but you'll have too much error, see this video.
You didn't state what you're really trying to do, so if you trying to create the parallax effect you can use UIInterpolatingMotionEffect.
I receive the RotationMatrix from my CMMotionManager and want to calculate my phone's heading from it, e.g. 38 degrees North (and avoid CLLocationManager), in order to make a more accurate compass:
[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical toQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *deviceMotion, NSError *error) {
CMRotationMatrix rm = deviceMotion.attitude.rotationMatrix;
// Get the heading.
motionHeading = M_PI + atan2(rm.m22, rm.m12);
motionHeading = motionHeading*180/M_PI;
However this only works when the phone is flat on the table. What should i use as formula to allow for all phone's positions in my hand, being in landscape mode, and the device looking above or under the horizon ?Thanks.
I finally used this answer that works pretty well in terms of movement stability.
I was wondering how to get the iphones orientation with respect to cardinal direction using Core Motion. I think the best route to go is to use the attitude of the device with respect to the magnetic field given by the magnetometer. From the appl e documentation it describes the attitude as:
A CMAttitude object represents a measurement of attitude—that is, the orientation of a body relative to a given frame of reference.
I was wondering how I could make this "given frame of reference" the cardinal directions. Maybe by using using CMCalibratedMagneticField?
Can anybody tell me how to do this or go an easier alternate route.
I'm not 100% sure if this is what you're looking for, but you can get device attitude values from the motion manager using the CMAttitudeReferenceFrameXMagneticNorthZVertical reference frame with the following. This code will dump the attitude of the device to log 30 times per second. If seems to me that yaw values are around 0 facing east, and extend to 180 degrees in both directions, positive values being counter clockwise, and negative being clockwise.
- (void)startMonitoring
{
if (!self.motionManager) {
self.motionManager = [CMMotionManager new];
[self.motionManager setDeviceMotionUpdateInterval:1.0 / 30.0];
}
NSOperationQueue *currentQueue = [NSOperationQueue currentQueue];
[self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXMagneticNorthZVertical
toQueue:currentQueue
withHandler:^(CMDeviceMotion *motion, NSError *error) {
NSLog(#"%#",motion.attitude);
}];
}
I want to apply a moving background according to device orientation. If device is held vertically upright an it is rotated around y axis then the background should move left or right according to the value of rotation.
Other icons on the background will static so it will give a 3d effect. For reference i need the exact same effect as shown in this video: http://www.youtube.com/watch?v=429kM-yXGz8
The code i have developed till now is:
- (void)updateViewsWithAcceleration:(CMAcceleration)acceleration;
{
_accelX = ((acceleration.x* 0.1) + (_accelX*.9));
_accelY = ((acceleration.y* 0.1) + (_accelY*.9));
_accelZ = ((acceleration.z* 0.1) + (_accelZ*.9));
[_backgroundShadow setFrame:CGRectMake(_accelY*50,_accelZ*50, _backgroundShadow.bounds.size.width, _backgroundShadow.bounds.size.width)];
[_titleShadow setFrame:CGRectMake(_accelY*50, _accelZ*50, _titleShadow.bounds.size.width, _titleShadow.bounds.size.width)];
}
Just an FYI: You're looking at the acceleration, not the gyroscope; try this instead:
- (void)viewDidLoad {
[super viewDidLoad];
cmmm = [[CMMotionManager alloc] init];
if (cmmm.gyroAvailable) {
cmmm.gyroUpdateInterval = 1.0/60.0;
[cmmm startGyroUpdates];
CMGyroHandler gyroHandler = ^ (CMGyroData *gyroData, NSError *error) {
CMRotationRate rotate = gyroData.rotationRate;
NSLog(#"rotation rate: {%6.2f, %6.2f, %6.2f}", rotate.x, rotate.y, rotate.z);
};
} else {
NSLog(#"No gyro");
[cmmm release];
}
}
I would like to know how many degrees is the iPhone leaning when being held upright - that is, if I point the iPhone up, I would like to know how many degrees it is looking up at? I think that I can use the gyroscope and core motion for this, and I think that it is pitch that I want, however, the pitch is a "rate of speed" in radians per second. I am not really interested in how quickly a user moved the iPhone, I am just interested in the leaning angle. So if I am pointing a phone up to take a picture, I would like to know the angle of pointing up - any ideas??
Thank you.
Gyro data is in radians per second, but what you are looking for is CMMotionManager.attitude property. It shows the attitude of the object in radians relative to a some frame of reference.
create class variable motionManager and init:
motionManager = [[CMMotionManager alloc] init];
motionManager.deviceMotionUpdateInterval = 0.1f;
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
[self processMotion:motion];
}];
process the updates, you are looking for pitch, but in this sample it will show you all three values so you can play around and decide what you need:
-(void)processMotion:(CMDeviceMotion*)motion {
NSLog(#"Roll: %.2f Pitch: %.2f Yaw: %.2f", motion.attitude.roll, motion.attitude.pitch, motion.attitude.yaw);
}
these are Euler Angles, you also have an option to get rotationMatrix, or quaternion format. Each with their own advantages and disadvantages.