I'm wanting to detect the orientation of the iPhone at 45 degree increments. Ideally I'd like to be able to get the angle of orientation along any axis.
The detection I need to do is similar to how Trism for the iPhone flashes an arrow towards the current bottom position of the screen when orientation changes.
I have something coded up but really don't understand how the accelerometer readings work and could use a nudge in the right direction. My current code logs the current angle but even when the phone is flat I get readings varying wildly a few times a second.
- (void) checkOrientation:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{
int accelerationX = acceleration.x * kfilteringFactor + accelerationX * (1.0 - kfilteringFactor);
int accelerationY = acceleration.y * kfilteringFactor + accelerationY * (1.0 - kfilteringFactor);
float currentRawReading = (atan2(accelerationY, accelerationX)) * 180/M_PI;
NSLog(#"Angle: %f",currentRawReading);
}
Sample from log while phone is flat:
2009-06-16 17:29:07.987 [373:207] Angle: 0.162292
2009-06-16 17:29:07.994 [373:207] Angle: 179.838547
2009-06-16 17:29:08.014 [373:207] Angle: 179.836182
2009-06-16 17:29:08.032 [373:207] Angle: -90.000000
2009-06-16 17:29:08.046 [373:207] Angle: 179.890900
2009-06-16 17:29:08.059 [373:207] Angle: -90.000000
2009-06-16 17:29:08.074 [373:207] Angle: 179.917908
2009-06-16 17:29:08.088 [373:207] Angle: -179.950424
2009-06-16 17:29:08.106 [373:207] Angle: 90.000000
2009-06-16 17:29:08.119 [373:207] Angle: 90.000000
2009-06-16 17:29:08.134 [373:207] Angle: -179.720245
I think your problem is that you're using int variables when you want float.
I think the accelerationX and –Y should be instance variables and thus:
accelerationX = acceleration.x * kfilteringFactor + accelerationX * (1.0 - kfilteringFactor);
accelerationY = acceleration.y * kfilteringFactor + accelerationY * (1.0 - kfilteringFactor);
Should give you more what you were looking for.
The reason is that you're using local variables, while they shouldn't be local.
Try to do the following:
Declare instance variables:
#interface YourViewControllerClass: UIViewController {
float accelerationX, accelerationY;
}
...
other declarations
Update variables in accelerometer delegate:
accelerationX = acceleration.x * kfilteringFactor + accelerationX * (1.0 - kfilteringFactor);
accelerationY = acceleration.y * kfilteringFactor + accelerationY * (1.0 - kfilteringFactor);
It should give more precise results without sudden jumps.
Related
I'm rotating a UIView based on the accelerometer data, and it works fine except that the UIView is deformed. I'm not sure how to fix the issue. Here's the code in my didAccelerate method:
float kFilteringFactor = 0.175;
CGFloat x = acceleration.x * kFilteringFactor + acceleration.x * (1.0 - kFilteringFactor);
CGFloat y = acceleration.y * kFilteringFactor + acceleration.y * (1.0 - kFilteringFactor);
float radians = M_PI - atan2(y, x);
[_horizonView setTransform:CGAffineTransformMakeRotation(radians)];
Am I performing the rotation incorrectly? I've changed the origin point in Xcode, but that appears to have no effect.
what kind of deformation occures? I think the the rotation is fine.
I need to calculate iphone velocity in space, punch speed for example.
My first question is: Are the acceleration values accelerometer:didAcceleratewith this filtering actions:
gravity_x = acceleration.x * kFilteringFactor + gravity_x * (1.0 - kFilteringFactor);
gravity_y = acceleration.y * kFilteringFactor + gravity_y * (1.0 - kFilteringFactor);
gravity_z = acceleration.z * kFilteringFactor + gravity_z * (1.0 - kFilteringFactor);
float gravityNorm = sqrt(gravity_x * gravity_x + gravity_y * gravity_y + gravity_z * gravity_z);
accelX = acceleration.x - gravity_x / gravityNorm;
accelY = acceleration.y - gravity_y / gravityNorm;
accelZ = acceleration.z - gravity_z / gravityNorm;
the same as using CoreMotion's
motionManager.deviceMotion.userAcceleration.x;
motionManager.deviceMotion.userAcceleration.y;
motionManager.deviceMotion.userAcceleration.z; ?
Next, according to same questions, I do the following
const float accuracy=10;
float accx = (float) ((int) (accelX * accuracy))/ accuracy;
float accy= (float) ((int) (accelY * accuracy))/ accuracy;
float accz= (float) ((int) (accelZ * accuracy))/ accuracy;
for rounding values, then, as I think, I obtain current speed
float dx = accx*9.81+prevX*9.81;
float dy = accy*9.81+prevY*9.81;
float dz = accz*9.81+prevZ*9.81;
speed_after_x = dx/2*myAccelerometer.updateInterval+speed_before_x;
speed_after_y = dy/2*myAccelerometer.updateInterval+speed_before_y;
speed_after_z = dz/2*myAccelerometer.updateInterval+speed_before_z;
according to iphone accelerometer speed and distance
then
prevX=accx;
prevY=accy;
prevZ=accz;
speed_before_x=speed_after_x;
speed_before_y=speed_after_y;
speed_before_z=speed_after_z;
and finally calculating speed as vector's length
float speed = sqrt(speed_after_x*speed_after_x+speed_after_y*speed_after_y+speed_after_z*speed_after_z);
if (max_speed<speed) max_speed = speed;
But speed value, that is containing in label, is always increasing. I mean if i moved device and then stopped, speed value doesn't become to 0. Doesn't acceleration compensate itself at 0?
Here's the example code I managed to hash out. I'll just put it here for now:
//
// ViewController.m
// Acce
//
// Created by Diziet on 14/05/2012.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "ViewController.h"
#interface ViewController () {
UIAccelerationValue gravX;
UIAccelerationValue gravY;
UIAccelerationValue gravZ;
UIAccelerationValue prevVelocity;
UIAccelerationValue prevAcce;
}
#property (strong) UIAccelerometer *sharedAcc;
#end
#implementation ViewController
#synthesize sharedAcc = _sharedAcc;
#define kAccelerometerFrequency 50.0 //Hz
#define kFilteringFactor 0.1
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.sharedAcc = [UIAccelerometer sharedAccelerometer];
self.sharedAcc.delegate = self;
self.sharedAcc.updateInterval = 1 / kAccelerometerFrequency;
gravX = gravY = gravZ = prevVelocity = prevAcce = 0.f;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (UIAccelerationValue)tendToZero:(UIAccelerationValue)value {
if (value < 0) {
return ceil(value);
} else {
return floor(value);
}
}
#define kAccelerometerFrequency 50.0 //Hz
#define kFilteringFactor 0.1
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
gravX = (acceleration.x * kFilteringFactor) + (gravX * (1.0 - kFilteringFactor));
gravY = (acceleration.y * kFilteringFactor) + (gravY * (1.0 - kFilteringFactor));
gravZ = (acceleration.z * kFilteringFactor) + (gravZ * (1.0 - kFilteringFactor));
UIAccelerationValue accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (gravX * (1.0 - kFilteringFactor)) );
UIAccelerationValue accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (gravY * (1.0 - kFilteringFactor)) );
UIAccelerationValue accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (gravZ * (1.0 - kFilteringFactor)) );
accelX *= 9.81f;
accelY *= 9.81f;
accelZ *= 9.81f;
accelX = [self tendToZero:accelX];
accelY = [self tendToZero:accelY];
accelZ = [self tendToZero:accelZ];
UIAccelerationValue vector = sqrt(pow(accelX,2)+pow(accelY,2)+pow(accelZ, 2));
UIAccelerationValue acce = vector - prevVelocity;
UIAccelerationValue velocity = (((acce - prevAcce)/2) * (1/kAccelerometerFrequency)) + prevVelocity;
NSLog(#"X %g Y %g Z %g, Vector %g, Velocity %g",accelX,accelY,accelZ,vector,velocity);
prevAcce = acce;
prevVelocity = velocity;
}
#end
It'll need modifying for your needs, especially as I'm just throwing the values away afterwards. The resultant value 'velocity' logged as 'Velocity' tends back towards extremely small negative values after acceleration events have ceased, e.g. *10^-17. So yeah, that's practically zero in my book. You'll want to do some rounding in there and probably even scale the values up. I don't think I could get it higher than 0.2 or 0.3 but then again I don't want to hurl my phone across the room (yet).
float mcount=0;
mcount += 0.3;
CGAffineTransform transform = CGAffineTransformMakeRotation(mcount);
Clock.transform = transform;
i want GET Degree!
how to get rotation(degree) of this Object ? for exampke 90 degree.
i have Action Script 3 example :
myInt = clock_mc.rotation;
i need this method on Cocoa Touch
If I'm understanding your question correctly then a bit of mathematics can help here:
angleInRadians = angleInDegrees * M_PI / 180.0
To get the reverse, you reverse your equation. So first moving the division by 180 on the right to the left results in multiplying by 180.0
angleInRadians * 180.0 = angleInDegrees * M_PI
Now move the multiply by M_PI (the value of PI which is something like 3.1415962...) to the left, you reverse the operation:
(angleInRadians * 180.0) / M_PI = angleInDegrees
Now to make it nice for the program to use, we write it like so:
angleInDegrees = (angleInRadians * 180.0) / M_PI
So in your program, you could write your code like this:
var angleInDegrees = 0;
...
angleInDegrees = mcount * 180.0 / M_PI;
If you want to use a function then:
-(float) getAngleInDegrees:(float) radians
{
float angleInDegrees = 0;
angleInDegrees = radians * 180.0 / M_PI;
return angleInDegrees;
}
I think you want how to convert degrees into radians:-
for this you can use this formula:-
static inline double radians (double degrees) { return degrees * M_PI/180; }
UPDATED!
Do you want to get result rotation angle of Clock object?! If so, use this:
double rotationInRadians = atan2(Clock.transform.b, Clock.transform.a);
int rotationInDegrees = (int)round(rotationInRadians * 180 / M_PI);
Read this for details & explanation.
I am using glLookAt to control my camera view.
I use the following code to rotate around.
SPEED_TURN is a Const of 0.16 (speed we turn at)
GLfloat v[] = {[self centerAtIndex:0] - [self eyeAtIndex:0],
[self centerAtIndex:1] - [self eyeAtIndex:1],
[self centerAtIndex:2] - [self eyeAtIndex:2]};
[self setCenter:[self eyeAtIndex:0] + cos(SPEED_TURN / 2)*v[0] - sin(SPEED_TURN / 2)*v[2] atIndex:0];
[self setCenter:[self eyeAtIndex:2] + sin(SPEED_TURN / 2)*v[0] + cos(SPEED_TURN / 2)*v[2] atIndex:2];
My question is, how to I get the angle of the camera in degrees?
I tried this
rotAngleDegs = (cos(-SPEED_TURN)*v[0] - sin(-SPEED_TURN)*v[2]) * 180 / PI
However that give numbers from -620 to +620
I don't think you are trying the right functions to give you the angle. The functions "cos()" and "sin()" both take your angle and map it to [-1,1]. If SPEED_TURN is the angle in radians, then you would just use:
float angleInDegrees = (SPEED_TURN * 180) / M_PI;
Take the degress you want and multiply them by pi divided på 180. Then you get the radians to enter:
Radians = Degrees * (pi / 180)
To get the degrees from radians:
Degrees = Radians * (180 / pi)
I'm trying to rotate a sprite using the accelerometer. when I tilt right, I want him to rotate slightly to the right, and when I tilt left, I want him to rotate slightly to the left...
Thanks in advance,
Reed
Firs off - in your h file you need to make the following variables:
UIAccelerationValue accelerationX;
UIAccelerationValue accelerationY;
float currentRawReading;
float calibrationOffset;
Also ensure that your h file has:
#interface myViewName : UIViewController <UIAccelerometerDelegate>
Then in your .m file just below your imports at the top put:
#define kFilteringFactor 0.05
CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;};
Then in your .m file on your viewDidLoad Function put:
UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer];
accel.delegate = self;
accel.updateInterval = 1.0f/60.0f;
also add the following function to your .m file:
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
accelerationX = acceleration.x * kFilteringFactor + accelerationX * (1.0 - kFilteringFactor);
accelerationY = acceleration.y * kFilteringFactor + accelerationY * (1.0 - kFilteringFactor);
// keep the raw reading, to use during calibrations
currentRawReading = atan2(accelerationY, accelerationX);
float rotation = -RadiansToDegrees(currentRawReading);
targetView.transform = CGAffineTransformMakeRotation(-(DegreesToRadians(rotation)));
//targetView.transform = CGAffineTransformRotate(targetView.transform, -(rotation * 3)); //if you want easing
}
you will have to tweak it slightly based on what view or object you are targeting -- but thats pretty much it.
Hope this helps,
Michael
Shouldn't be too difficult. Just have somewhere in your code that handles the UIAccelerometerDelegate class and apply changes to your sprites based on the values you receive through parameters to the – accelerometer:didAccelerate: callback.
Apple docs for the delegate class are available at...
https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIAccelerometerDelegate_Protocol/UIAccelerometerDelegate/UIAccelerometerDelegate.html
In the delegate function of accelerometer just write the code -->>
float angleRadians = atanf((float)X_Position / (float)Y_Position);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = 1 * angleDegrees;
sprite.rotation = cocosAngle;
and the sprite will get rotated to desired angle with changes in the values of X_position, Y_Position and angle.
Njoy.. :)