The problem can be solved by seeing which angle you attain after t tics and equating them with your constraints. I assumed you do
angle += ang_vel, ang_vel -= deceleration. I also assumed ang_vel is positive, but you can just switch the sign and check.
v0 is your angular velocity entering the stopping sequence
(t = 0).
c is your deceleration constant.
q is how many degrees left to rotate until you're back at 0°.
q0 is your angle entering the stopping sequence.
T is for how many tics you want this stopping sequence to last.
I found this by setting:
Code: Select all
v(t = 0) = v0
v(1) = v0 - c
v(2) = v0 - 2c
...
v(T) = v0 - Tc
You set a constraint:
v(T) = v0 - Tc = 0, then
c = v0 / T.
Your rotation at any time is found by adding them up from a starting rotation q0:
Code: Select all
Deg(t = 0) = q0
Deg(1) = q0 + v(0) = q0 + v0
Deg(2) = q0 + v(0) + v(1) = q0 + v0 + v0 - c
Deg(3) = q0 + v0 + v0 + v0 - c - 2c
...
Deg(T) = q0 + v(0) + ... + v(T - 1) = q0 + (T - 1) * v0 - (1 + 2 + ... + T - 1) c =
= q0 + (T - 1) * v0 - 0.5 * T(T - 1) c
The last equals sign uses the Gauss summation formula for the coefficient of c.
Then we want
Deg(T) = q0 + q, that is,
(T-1)*v0 - 0.5 T(T-1) c = q. This is a linear equation in
c and easily solved:
rate = 2/T * ( ang vel - degrees left / (T-1) )
From before, we had
rate = ang vel / T. With that equation we find that
degrees left / ang vel = T, which appears physically sensible, suggesting my ideas are not too far-fetched. Now you can find rate with the equation by calculating T and using my formula. To summarise:
T = degrees left / ang vel
rate = 2/T * ( ang vel - degrees left / (T - 1) )
For the constraint |rate| <= 1: Calculate T, then rate, then if rate does not fit the constraint, don't enter the stopping sequence and keep on rotating as usual (edit: or decrease v by 1, but don't enter stop sequence). Try again next tic. You'll likely experience slight overshooting. Play with that yourself.
Note that you should be able to use the very same formulas for some linear, decelerating movement which you want to end in a certain position, by substituting degrees left with distance left, and angular velocity with movement velocity.
edit: I didn't mention this, but you'll have an easier time doing a stopping motion like this by ditching the idea of "I have to add a velocity every tic" during the stopping sequence. I'd linearly interpolate the angle towards the end angle* (watch for crossing 360°), and if the difference between new and old position is greater than the velocity as the stopping sequence started (again, no longer changing velocity), I'd set the new position to be the old + velocity instead. If the new position is close enough to the desired angle, lock onto it and exit the stopping sequence. This is far easier to work with.
* That is, add a fraction of the remaining distance. Over time, this fraction converges against 0 as you requested.