Mapping device tilt to player character (etc) movement behaviour - ios

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.

Related

Quadcopter PID Controller for distance

I am trying to use a PID controller to stop a quadcopter at a specific location while travelling horizontally, however currently it overshoots/undershoots depending on the max velocity. I have tried manually tuning the P,I and D gains with limited success. Essentially the velocity needs to go from maxSpeed to 0 at the very end of the flight path.
I run a loop that executes every 0.1 of a second.
The pitch input to the quadcopter is in m/s and I recalculate the distance to the target on each iteration.
some pseudo code
kP = 0.25
kI = 0.50
kD = 90
timeStep = 0.1
maxSpeed = 10
currentError = initialDistanceToLocation - currentDistanceToLocation
derivativeError = (currentError - previousError) / timeStep
previousError = currentError
output = kP * currentError + kI * integralError + kD * derivativeError
integralError = integralError + currentError * timeStep
if >= maxSpeed {
output = maxSpeed
} else if output <= 0 {
output = 0
}
return output
Is there a way to reliably tune this PID controller to this system that will work for different max velocities, and/or are there other factors I need to consider?
A few ideas:
check in your code if you calculate the integralError after you calculate the output, too. This can, of course, lead to undefined behavior since in the output calculation, integralError could be anything depending on the programming language.
From my experience, you should get rid of the D part entirely, since in a digital environment and due to measurement noise, it could have destabilizing effects
I highly recommend looking at this tutorial which guides you through important aspects (even though it concentrates on fixed-point PI controllers)
Summary
To stop on a point, one easy way is to switch from a velocity PID controller to a position PID controller whenever you want to stop on a point, and turn up D (which dampens velocity in a position controller) to prevent position overshoot of your target point. See below for details.
Reminder: D in a velocity controller = useless. D in a position controller = essential. See my comment here, and notes below.
Details
I've done this before. I didn't spend a ton of time optimizing it, but what I found to work well was to switch from a velocity controller which tries to overfly waypoints, to a position controller which tries to stop on them, once you are near the desired stopping point.
Note that your position controller can also be forced into a velocity controller by scaling your gains to produce desired velocities, or even by scaling your position error to arbitrarily produce a desired velocity, and by moving the desired position point continually to keep the vehicle following a path. The video below demos that last part too.
The position controller was a PID controller on position: the vehicle's pitch angle was directly proportional to the distance from the target in the y-axis, and the vehicle's roll angle was directly proportional to the distance from the target in the x-axis. That's it. The integral would take out steady-state error to ultimately stop perfectly on the desired position, despite disturbances, wind, imperfections, etc., and the derivative was a dampening term which would reduce the pitch and roll angles as velocity increased, so as to not overshoot the target. In other words: P and D fight against each other, and this is good and intended! Increasing P tries harder to make the vehicle tilt when the vehicle has no velocity, and increasing D causes the vehicle to tilt less and therefore overshoot less the more velocity (derivative of position) that it has! P gets it moving quickly (increases acceleration), and D stops it from moving at too high of a velocity (decreases velocity).
For any controller where neutralizing the driving force (pitch and roll in this case) instantly stops a change in the derivative of the error, D is NOT needed. Ex: for velocity controllers, the second you remove throttle on a car for instance, velocity stops changing, assuming small drag. So, D is NOT needed. BUT, for position controllers, the second you remove throttle on a car (or tilt on a quadcopter), position keeps changing rapidly due to inertia and existing velocity! So, D very much is needed. That's it! That's the rule! For position-based controllers, D very much is needed, since it dampens velocity and acts as the dampening term to prevent overshoot of the target.
Watch this video here, from 0:49 to 1:10 to see the vehicle quickly take off autonomously in this PID position control mode, and auto-position itself at the center of the room. This is exactly what I'm talking about.
At approximately 3:00 in the video I say, "[the target waypoint] is leading the vehicle by two-and-one-half meters down the waypoint path." You should know that that 2.5 meters is the forced distance error (position error) that I am enforcing in the position PID controller in order to keep the vehicle moving at the shown fixed velocity at that point in the video. So...I'm basically using my position controller as a crude sort of velocity controller with a natural filter on the commanded path shape due to my "pure pursuit" or "vector flow-field" waypoint-following algorithm.
Anyway, I explain a lot of the above concepts, and much more, in my more-thorough answer here, so study this too: Physics-based controls, and control systems: the many layers of control.

UIAccelleration value range

The AppleDeveloper guide seem to imply that UIAccelerationValue can range between a double value of -1.0 and +1.0.
I have logged the values from a real device whilst "shaking" with crazy gestures my iPod touch and got x values above 2.0 (e.g. +2.1, -2.1) and NO y value above 2.0f.
Could anyone explain this?
Has anyone identified the MAX and MIN values for UIAccelerationValue?
My take on this is that Apple has implemented some algorithm that approximates the force of gravity and takes as 1.0 values that are above a standard speed approximation (e.g. have values 9.8 m/s of speed).
Any other guesses?
You may be misunderstanding a part of the documentation. Nowhere does it say that the value ranges between -1.0. and 1.0, as far as I can see. It says that:
The device accelerometer reports values for each axis in units of
g-force, where a value of 1.0 represents acceleration of about +1 g
along a given axis. When a device is laying still with its back on a
horizontal surface, each acceleration event has approximately the
following values:
"g" is used in a particular technical sense here; 1 g is one standard gravity; a phone accelerating faster than this will register readings higher than 1. Violent shaking in the hand is easily enough to cause acceleration and deceleration values higher than 9.8m/s2.

Detect programmatically if iPhone is dropped using CoreMotion/Accelerometer

So I am writing a piece of code where I have to detect different movement gestures using Accelerometer and gyroscope in iOS 4.3 above.
Q1: Is there any existing opensource code which has achieved any movement/gesture detection?
If not
Q2: For now I want to detect if the iPhone is dropped.
What I have achieved so far:
CoreMotion API gives userAcceleration, which (afaik) is the acceleration that the user is giving to the device or the acceleration of device in some direction (x, y or z) with out considering the gravity so what I can do is: store, let's say, previous 5-6 values of acceleration parameters and can check where any of them hits large negative value, which basically represents the sudden deceleration.
But this solution is not very optimal, I think I need to somehow detect the freefall/downwards motion of the device too first. Any idea how to approach this problem?
UPDATE:
Thanks Misch for sharing your approach. I was not at all thinking about total acceleration. I did exactly what you said:
"You would however have to test yourself, what means "total acceleration corresponds
approximately to earth acceleration" and "for some time" in your case."
The acceleration value is actually in G's so I tested the "total acceleration" values with in range of 0.9 - 1.1. And I checked them over some time, initially I checked four consecutive values when updateInterval is set to 1/20.0. For now I have relaxed the condition of consecutiveness a little.
Here's a sample output:
Acceleration = 0.090868
Acceleration = 0.074473
Acceleration = 0.159797
Acceleration = 1.157513
Acceleration = 1.224588
Acceleration = 1.036272
Acceleration = 0.914698
Acceleration = 0.904093
Acceleration = 0.941516
Acceleration = 0.046362
Acceleration = 0.045109
Acceleration = 0.060045
I think, I still have to keep on testing and adjusting values. If you have any optimization in mind kindly do share, I know in order to help you'd need to see the many samples of freefall acceleration values. For now I am thinking to:
round off the values of acceleration to 3 decimal places and play with the acceleration range I am using.
May be check if, after the freefall condition is met, total acceleration value suddenly goes down.
Do you think the acceleration values I have quoted are a bit noisy?
To Q2:
Checking for large negative values does not tell you whether the phone is being dropped.
First, the user could just move the phone with a rapid gesture, this would also result in a large (maybe negative) value.
Secondly, the phone could fall in another direction than you imagine, and therefore, the acceleration could be positive, although the phone is moving towards the ground.
You could just calculate the total acceleration (a = sqrt(ax^2 + ay^2 + az^2)) and check whether this total acceleration corresponds approximately to earth acceleration (9.81). The phone is falling if the acceleration corresponds to earth acceleration for some time.
You would however have to test yourself, what means "total acceleration corresponds approximately to earth acceleration" and "for some time" in your case.
The physics behind this:
Let's assume you drop your phone in a way, that the y axis of the phone shows upwards. Then the x and z accelerations will be 0 and the y acceleration will be like this:
The acceleration will be 0 in the beginning, will then reach -9.81 the moment, you release your phone. Then it will hit the ground, which you see in the small acceleration peak, and then the acceleration is zero again.
However you can't use only the acceleration in y direction, because your phone may fall in a different angle.
So you have to watch the total acceleration of your phone:
Here you don't see a negative acceleration anymore. However, here it doesn't matter anymore in which direction your phone is facing, as a free fall will always be characterized by an acceleration of 9.81.
To your edits:
1. Why would you want to round off the values of acceleration to 3 decimal places? If you test 0.9 < x < 1.1, it doesn't matter if x is 0.914698 or 0.915.
2. What if someone drops the phone but then catches it again, so the total acceleration does not necessarily have to go down again. Additionally, there should be a large acceleration value (a sudden deceleration) the moment the phone hits the floor. Maybe the reason one does not see this in your values is that it is so short, that it falls between two consecutive measurements. However this could be measured, so don't suppose that immediately after the free fall, the acceleration should decrease again.

how can i get velocity with UIAcceleration?

Do you know the app "motion ruler"? It can be used to get the length of an object by moving an iPhone.
How can I get the velocity from UIAcceleration when moving an iPhone?
Velocity is just acceleration * time. I.e. you can use the formula
v = u + acceleration * time.
As a starter you could look at assuming the initial speed is 0, 'u' can be ignored to get accelration * time.
if you want distance just use
distance = initial velocity * time + 0.5 * acceleration * time * time.
or better still use dead reckoning and keep adding your velocity vectors as frequently as you get updates from the accelerometers.
To get acceleration as a scalar you can do a = sqrt(x*x+y*y+z*z). You will want to remove gravity from this before though! Also this will only give you distance in straight line, you may prefer to measure velocity in x,y,z independently and use vector analysis to measure the path for a more accurate reading. Be warned though, you may also need to take into account any rotations to be super accurate and this feature is only on iPhone4s. This can get tricky and you'll probably want to use some matrix maths to orientate the 'space' the phone is in.
You will also need to do a low pass filter on the accelerometer to get rid of the 'shakes' and this is where a significant error margin will creep in and why I'd expect all rulers in appstore have spent a long time refining this.
to do a filter, a very simple one is filteredValue = ((lastValue * n) + accelerationValue )/(n+1) where a larger n value gives a smoother result but less responsive.

Easy code sample for formula for simulating deceleration of a rotating sphere due to friction and gravity?

I have a rotating sphere that the user rotates by applying a virtual force, like a virtual accelerator. I want to be able to simulate a nice momentum effect so that when they lift off the accelerator the ball winds down in speed in a natural and realistic way, as if due to friction and/or gravity. I don't want to get into any deep physics equations. I'd like to do this quick so if I could find a code sample that shows how to do this, or even a page of formulas clear enough that I could encode, that would be great.
I'd like a formula that has one or two adjustable coefficients that I could tune to make the ball decelerate faster or slower depending on my needs. I don't want to get into anything heavy like an open source physics library or the like. Just something simple.
I'm using Delphi 6 Pro but I also know C/C++, Basic, Java, and Javascript.
Velocity is change in displacement. Acceleration is change in velocity.
Gravity or friction just causes an acceleration (possibly negative).
So all you need to do is apply a negative acceleration when they do not activate the accelerator.
So lets assume you have an angle that is changing. Applying the accelerator increases the amount the angle changes by each iteration or time step. If your angle is t and your change in angle is called dt (angular velocity) then when the accelerator is applied you'll have:
t = t + dt
dt = dt + a
where a depends on how much force you're applying, or how much they've 'pressed' the accelerator (i.e. this is the acceleration).
You'll probably want to limit dt (i.e. speed of rotation) - if you only want to spin in one direction you'll have an upper positive limit and a lower limit of 0. If you want both directions, you can have a lower negative limit and an upper positive limit.
All you need to do is make a some negative number when the accelerator is not applied (if dt is positive - make a positive if dt is negative), and ensure you don't 'wrap' (i.e. make dt 0 when it gets near 0).
It has been some time ago, but according to my dynamics study books the Mass Moment of Inertia for a sphere is defined as I=(2/5)m*r^2. m is the mass, r is the radius of the sphere (all in SI untis). On this page you'll find some examples to use the mass moment of inertia to calculate deceleration of the sphere as a result of the applied negative torque. This toqrue is a result of the friction. Since you are not defining the material of the surface of the sphere and the surroudings you cannot calculate the friction and will have to choose a good force yourself.
As long as you are not solving stellar problems, I don't see how gravity has much to do with decelerating the rotation.
Friction is almost proportional to the current rotation speed (actually the speed on the surface of the sphere).
So a formula for the current rotation speed over time w(t) may be something like this:
w(t) = w0*exp(-c*(t - t0))
with t0 being the time the friction starts, wt being the rotation speed at that time.
The coefficient c > 0 determines how fast the speed will decrease - the higher c, the faster the speed will go down. This formula is valid for all t >= t0.
Note that for t = t0 the exp function returns 1 and you get the initial speed, while for t -> ∞ the exp function (and so the resulting speed) returns -> 0 (the minus in front of the c guarantees this).
You've already accepted an answer, but I'll put in my piece.
I'll assume you already know how to make the sphere spin at a constant rate, and how to make it accelerate under the applied torque. Making it decellerate is just a matter of applying another torque, one that must be calculated.
When an object slides on a solid surface, the rate of deceleration is constant. The force is in the direction opposite to motion, and its magnitude depends on a couple of things but not speed. When the object comes to a full stop, the force vanishes. The same applies to a globe turning on a solid pivot.
When an object passes through a fluid, the force of decelleration increases with speed, so the faster the object the greater the drag. As the object slows down, decelleration grows weaker, and the object keeps slowing down but never stops. This describes a globe spinning in air or water. At reasonably high speeds, drag is proporional to v2, and at very low speeds it is proportional to v (I don't know about the transition between these domains).
So I suggest t = -a wb, where w is angular velocity. The parameter a is the strength of the friction, and b describes the kind of decelleration; b=0 is like friction on a solid pivot, b=2 is like spinning in air, and b=1 is like rotating in syrup. Other values of b may or may not look realistic or be realistic.

Resources