Detect 360° iOS device rotation using gyroscope - ios

I want my app to be able to detect a device rotation while the device is held horizontally. I could use readings from a compass but I believe yaw values from the gyroscope would be more accurate. Given yaw readings, what would be the best algorithm to determine a 360° rotation (either clockwise or counter-clockwise). And it has to be a full 360°, not just turning the phone 180° in one direction and back 180° in the opposite direction.

You would use CoreMotion to get the rotation about the vertical axis. You need to add the delta of rotation events. Every time more than a minimal value is in a different direction than the previous you reset your starting point. Then when you arrive at either plus or minus 360 degrees from this start point you have the rotation.

Here is an idea assuming that you can obtain the readout in short intervals, and that the yaw can be zeroed at a specific start point. This is different from the other answer, which detects full circles from a continuously adapted start point.
In this approach, we keep comparing the current yaw to the previous yaw, asking whether a checkpoint at 180 degrees, or PI has been passed. Initially, the checkpoint flag cp_pi is NO, and passing it in either direction toggles its state. Note that yaw changes its sign in two places, at the zero point and again at PI to -PI.
Assuming your object has two properties that are persistent between ticks of the detector, BOOL cp_pi; and float prev_yaw;, we consider that d_yaw is less than PI for crossing 0 and larger than PI for crossing at the opposite end of your circle. When crossing the opposite end, we toggle cp_pi. When cp_pi is YES while crossing 0, we are guaranteed to have passed a full circle - since otherwise, cp_pi would have been toggled back to NO:
-(void)tick
{
float yaw = [self zeroedYaw];
if ((fabs(yaw) == PI) || (yaw == 0.0f)) return;
if (yaw * prev_yaw < 0)
{
float d_yaw = fabs(yaw - prev_yaw);
if (d_yaw > PI)
{
cp_pi = ! cp_pi;
}
else if (cp_pi)
{
// fire detection event
}
}
prev_yaw = yaw;
}
Note that in order to make our life easier, we skip the detector function entirely if yaw is sitting right on one of the checkpoints.

Related

Questions about how scene kit translations work, and accelerometer

I have done a tiny bit of 3d graphics in the past. When you move or rotate a Scene Kit sprite does it automatically update its translation matrix, or do you have to make it yourself?
Are "position" and "eulerAngles" both properties that are... absolute.
For example if I am in sprite kit and set the translation to (1, 0) it will be at that point relative to the origin.
And if I set the z rotation to 90 it will be rotated 90 degrees.
And if I incrament the translation (with +=) x it will start going in a line.
And same for zRotation if incremented it will rotate. In scene kit if I do similar things to the translation and euler angle values will they do the same thing?
Also what exactly does the accelerometer think its measuring, it is like the amount of motion in a certain period? So basically is it the delta between the two simultaneous points that the device was in.
Yes, this question is definitely broad, however they are much better placed here, then scattered in three tiny posts.
Doe, let me see if I can help
Translation matrix? It has a TRANSFORM matrix that includes translation, scale and rotation, and yes, it is automatically updated when you change one of these 3, and vice-versa.
If I understood well, yes, just like in SpriteKit. They are related to their parent coordinates. The position (1,0,0) would mean the Node (its center, unless you change its pivot (anchorPoint in spriteKit)) will be at distance 1 along the X axis of its parent from its parent origin).
The same works for the rotation, if a NodeA has 30 degrees rotation at axis X and you add a NodeB with 20 degrees rotation at X in NodeA, you would have the NodeA having visually a 50 degrees rotation at X.
Accelerometer measures the acceleration forces given to the device in a specific moment, in the three axis of the device. Its unit is not [m^2/s] but [Gravity/s] (would be approximately [10m^2/s]). An important detail is that this measure includes the gravity acceleration as well.
So, if you try to measure the acceleration with the device standing ortogonal to the ground, you would expect (0, 0, -1) (or 0,0,1, if upside down).
Lying down the device on the ground it would be (0, 1or-1, 0) (depending if the screen is facing the ground or the ceiling)
For for every tick (of update rate of the accelerometer) it calculates what was the acceleration imposed to the device at that moment. That's not the delta itself, but it can be easily calculated if you store the values.

How to measure user distance from wall

I need to measure distance of wall from user. When user open the camera and point to the any surface i need to get the distance. I have read some link Is it possible to measure distance to object with camera? and i used code for find the iphone camera angle from here http://blog.sallarp.com/iphone-accelerometer-device-orientation.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
// Get the current device angle
float xx = -[acceleration x];
float yy = [acceleration y];
float angle = atan2(yy, xx);
}
d = h * tan angle
But nothing happen in the nslog and camera.
In the comments, you shared a link to a video: http://youtube.com/watch?v=PBpRZWmPyKo.
That app is not doing anything particularly sophisticated with the camera, but rather appears to be calculate distances using basic trigonometry, and it accomplishes this by constraining the business problem in several critical ways:
First, the app requires the user to specify the height at which the phone's camera lens is being held.
Second, the user is measuring the distance to something sitting on the ground and aligning the bottom of that to some known location on the screen (meaning you have a right triangle).
Those two constraints, combined with the accelerometer and the camera's lens focal length, would allow you to calculate the distance.
If your target cross-hair was in the center of the screen, it greatly simplifies the problem and it becomes a matter of simple trigonometry, i.e. your d = h * tan(angle).
BTW, the "angle" code in the question appears to measure the rotation about the z-axis, the clockwise/counter-clockwise rotation as the device faces you. For this problem, though, you want to measure the rotation of the device about its x-axis, the forward/backward tilt. See https://stackoverflow.com/a/16555778/1271826 for example of how to capture the device orientation in space. Also, that answer uses CoreMotion, whereas the article referenced in your question is using an API that has since been deprecated.
The only way this would be possible is if you could read out the setting of the auto-focus mechanism in the lens. To my knowledge this is not possible.

Gyro angle way off on iOS

When I start the motion manager, keeping the phone basically still in my hand, I get erroneous values for the attitude. To get the rotation value, I use the CMAttitude object:
CMDeviceMotionHandler motionHandler = ^(CMDeviceMotion *motion, NSError *error) {
[self calculateNewPosition:motion];
_rotationMatrix = [self rotationToMat:[motion attitude].rotationMatrix];
};
[_motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical toQueue:_motionQueue withHandler:motionHandler];
Now, I know that there is noise in the measurements with tiny sized gyros, and the gravity vector probably needs calibration, but this seems to be too much off. After 0.5-1 seconds, the value of the rotations goes from 0 to over 20°?! Two examples for roll, pitch and yaw:
-1.001736 22.637596 -0.197573
-0.095075 29.075712 -0.014112
If it was the position drifting, when I use double integration, I would understand, but the rotation coming directly from the sensors?
Do you have any idea why this happens?
I just realized by seeing pictures in this question: Gyroscope on iPhone and testing out a bit more, that values are zero for a little while when starting the gyro, then, according to my configured coordinate frame (Z vertical), the values are adjusted to the current position of the phone.
So if I started with the phone in my hand at a 20° pitch, the value for pitch will be 0 for some small amount of time, then switch to 20°. Which means I have to wait for the rotation matrix to be non-zero to start tracking rotations.

Blackberry Device Movement Angle Difference

I am working on a Blackberry application in which I need to retrieve the Angle difference when the device moves. It means the difference of angle between when the movement starts and ends. It must be 25 degrees to call some function.
In simple words, call a function when the device moves by 25 degrees.
Please read AccelerometerSensor docs, it is available in API 4.7.0 and higher. All data that you can retrieve is described in class AccelerometerData, it is orientation and acceleration (gravity data).
It is described more in details how to get angle from gravity sensor data in JavaME docs, "Mobile Sensor API" section:
If the phone was placed flat, the accelerometer would tell us that the acceleration along the z-axis (up and down) is about 1000 (this value represents 1G). The accelerations along the X and Y axises (sideways) would be about 0 since the phone is sitting still and gravity only works downwards. Flipping the phone over with the screen facing down, the accelerometer would give us the value of -1000 on the Z-axis. Standing on its side, would give us a value of 1000 or -1000 along either the X- or the Y-axis, depending on which side you put it. Putting the phone in a 45 degree angle along the X-axis would give us a value of ±707 on the Z-axis and ±707 on the Y-axis, since gravity cannot affect either axis with its full force (You can easily calculate what the value should be for a certain angle for each axis using the sine and cosine functions). Using the values from the X and Y-axis from the accelerometer, we can determine the position of the phone at any time, and then use that value to move our ship to avoid the incoming asteroids.
So, having accelerometer data for all 3 axes we may figure it out what is horizontal angle of a device.

Mapping device tilt to player character (etc) movement behaviour

The context is an iPad game in which I want an on-screen object to be controlled by X/Y tilt of the device.
I was wondering if anybody can point me in the direction of resources for deciding on an appropriate mapping of tilt to the movement behaviour (e.g. whether people tend to use the "raw" rotation values to control the acceleration, velocity or direct position, and how comfortable players have been found to be with these different types of 'mapping' of device rotation to object movement).
I appreciate that the appropriate choice can depend on the particular type of game/object being controlled, and that some trial and error will be needed, but I wondered as a starting point at least what existing knowledge there was to draw on.
First you're going to want to apply a low-pass filter to isolate tilt from noise and your user's shaky hands, Apple shows this in their accelerometer examples
x = accel.x * alpha + x * (1.0 - alpha);
y = accel.y * alpha + y * (1.0 - alpha);
more alpha causes more responsiveness at the cost of more noisy input.
Unless your game is intentionally simulating a ball balancing on the face of the screen, you probably don't want to apply your tilt values to acceleration, but rather to target velocity or target position, applying "fake" smooth acceleration to get it there.
Also, this answer has a neat idea if Unity3d is acceptable for your project, and this paper has some handy numbers on the practical limits of using tilt control as input, including making the important point that users have a much easier time controlling absolute angle position than velocity of tilt.
So, we desire to move our character - we'll call him 'loco' - based on the accelerometer's x and y data.
Now, if we do want the magnitude of the tilt to affect the rate of loco's travel, we can simply factor the accelerometer x or y value directly into our algorithm for his movement.
For example: (psuedocode)
// we'll call our accelerometer value for x 'tiltX'
// tiltX is .5; // assume that accelerometer updated the latest x value to .5
// unitOfMovement = 1; // some arbitraty increment you choose for a unit of movement
loco.x += unitOfMovement * tiltValueX;
This will cause loco to move that number of pixels for each game cycle (or whatever cycle you are driving the updates for movement by) and that here is 1 pixel multiplied by the accelerometer value. So if the character normally moves 1 pixel right at full tiltX (1.0), then if tiltX comes in from the accelerometer at .5, loco will move half that. When the value of tiltX increases, so too will the movement of Loco.
Another consideration is whether you want the movement tied directly to the rate of accelerometer events? Probably not, so you can use an array to just hold the last ten x values (same concept for y values too) sent by the accelerometer and use the latest average of the array (sum of x values / number of elements in array) at each game loop. That way, the sensitivity will feel more appropriate than driving the movement by whatever the update rate of the accelerometer may be.
Have a look at Point in Tilt Direction - iPhone which is first answer is very helpful I think.

Resources