Sign in to follow this  
Kirl

preserve turn radius at varying speeds?

Recommended Posts

I have a vehicle of sorts which moves at various speeds, I'm steering it by adding or subtracting vr to/from vehicle.angle, but because of the varying speed the radius of the turns increases/decreases. How can I adjust the vr value to ensure that the turning radius stays the same? movement code
var radians = vehicle.angle *Math.PI/180;	
var xSpeed = Math.cos(radians)*vehicle.speed;
var ySpeed = Math.sin(radians)*vehicle.speed;

Share this post


Link to post
Share on other sites
v = r . w

r = v / w

for different velocities v0 and v1, if your radius remains constant

v0 / w0 = v1 / w1

w1 = w0 . (v1 / v0)

assuming constant frame rate, I suppose you will have to modulate your vr by the increase in linear speed.

Share this post


Link to post
Share on other sites
Thanks for the reply, but I don't know what the variables are representing. I haven't had much formal math teaching so I might not understand many common notations, but understanding theory and aplying it shouldn't be a problem.

I guess v is velocity and r is probably rotation, but I'm completely lost on w.

Hate to sound like a noob, but alas... :|

Share this post


Link to post
Share on other sites
If 'theta' is your car's angle, then w = (d/dt)theta . Really it's an "omega," but that looks like 'w.' FYI, the use of 'omega' for angular velocity is a standard convention.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kirl
Funny... really... =/

Once upon a time I used to get good help here, any chance of that?


I thought your only problem was that you didn't know what 'w' is. So what else are you confused about?

Basically, here's the punchline:

[The amount you add to vehicle.angle each frame] =
[timestep]*([vehicle speed]/[turning radius]).

Calling vehicle.angle 'theta,' the vehicle speed 'v,' and the turning radius 'R,' you might write this as an ordinary differential equation (ODE) like,

(d/dt)theta = v/R .

What I am doing when I also include a timestep is approximating the solution to this ODE by Euler integration.

I think this explains everything?

Share this post


Link to post
Share on other sites
w is angular velocity. basically, you rate of turn per frame whatever your angle increment is, as long as your frame rate is constant. Else, you need to factor in your frame timestep.

in short, you modify your angle step by the ratio of velocities, since the relationship between radius of turn, rotation and linear velocity is linear.

That's what I come up with anyway :)

Share this post


Link to post
Share on other sites
actually it's quite simple.

You know your velocity, you know your radius, the angular velocity will be v / r. That means, your maximum rate of turn every frame will be (v / r) * frame_timestep.

Share this post


Link to post
Share on other sites
Thanks for the elaboration guys, I got it now! =) It is indeed quite simple in hindsight, weird how my mind can complicate things sometimes.

Sorry emergent, I thought you were having a bit of fun at my expense by throwing in some more mystery variables (theta, omega? d? dt?). How do you guys come up with w as radius anyhow? I guess it's convention but as I mentioned, I'm probably not aware of those...


I stumbled upon another little problem with my movement code though. To the eye the vehicles seem to descibe a perfect circle, but after a certain number of rounds it becomes clear they're wandering. It seems there's a slight inacuracy in my movement code somewhere. Doh, I'll be back probably.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kirl
Sorry emergent, I thought you were having a bit of fun at my expense


No, not my style. :-)

Quote:
mystery variables (theta, omega? d? dt?)


The notation "d/dt" does not represent the ratio of two variables 'd' and 'dt.' Rather, it denotes the time derivative (i.e., rate of change) from calculus.

Quote:
How do you guys come up with w as radius anyhow?


To be clear, 'w' is not the radius. Rather, it's the rate of change of the angle. The convention comes from physics, where Roman letters are used for linear position/velocity/acceleration, and corresponding Greek letters are used for angular position/velocity/acceleration. I.e., linear velocity is 'v' but angular velocity is 'omega;' linear acceleration is 'a' but angular acceleration is 'alpha.'

Quote:
I stumbled upon another little problem with my movement code though. To the eye the vehicles seem to descibe a perfect circle, but after a certain number of rounds it becomes clear they're wandering. It seems there's a slight inacuracy in my movement code somewhere.


I would guess that this is the result of integration error. The player slowly spirals out, right?

Here's what "integration error" means: Basically, Euler integration (see the previous Wikipedia link) is only an approximation, and errors build up over time (there's a good graphic to describe this at the Wikipedia article). Usually in games, the character is controlled by a human player so this doesn't really matter; the player won't even notice, and he'll just subconsciously correct for it. From your description, I would guess that this is what's going on. So long as the effect is small, I might not bother trying to "fix" it.

This said, it's quite possible to avoid most of this error (you'll end up using some sines and cosines) and if you'd like we can talk more about it, but I'll hold off on that for now (sleep calls me).

Share this post


Link to post
Share on other sites
As a side note, you can make more accurate turning dynamics by reducing a car to a few simple elements.



(front wheel)

/
/ (rear wheel)
/ --------------------- ====+====
/ <------- wheelbase ------->
/



The angle of steering here is approximately 60 degrees (very exagerated, of course).

then you can work out the radius of turn depending on the steering angle



(front wheel)

/
/ (rear wheel)
/ --------------------- ====+====
/ . |
/ . |
. |
. |
. |
. |
. | (radius of turn)
. |
. |
. |
. |
. |
. |
+ (centre of rotation)



So, depending on the steering angle, and the wheelbase of the car, you get the ideal turning radius of the car.

turn_radius = wheelbase * tan(90 - steering_angle);

The problem is that you cannot go as fast as you want given a turning radius, due to the limited amount of grip from the tires.

The maximum amout of grip (u) is basically the ratio of the force acting down on the tires by the force acting along the contact surface. It tells how much lateral force you can get from a tire, given the load on the tire.

f = u * m * g

(maximum lateral force = coefficient of friction times mass times gravity).

When rotating, the force acting on the contact surface is the centripetal force

f = m * v^2 / r

so the maximum velocity that you can apply, given a radius of turn 'r', a car mass 'm', the gravity 'g', and the coefficient of friction on tires 'u' is

v = sqrt(r * u * g)

and we know the turning radius

r = wb * tan(90 - sa)

('wb = wheelbase, 'sa' = steering angle).

so given the steering angle of a car, and the car properties (wheebase, grip, gravity), the maximum velocity 'v' that can be applied before the car skids out of control is

v = sqrt(wb * tan(90 - sa) * u * g).

if you have an excess of velocity when the turn starts, the car will either oversteer or understeer, meaning it will follow an more accute, or more shallow trajectory than the steering input suggests.

And that's also not taking into account the force added onto the tires, such as braking force or engine power, which 'eats' grip from the tire and limits the amount of steering you can apply through corners. or the downforce that pushes the car down, giving more grip.

Interestingly, it's independent from the actual mass of the car.

Share this post


Link to post
Share on other sites
Well, in this case my "vehicle" is the head of a snake. Thanks for the note though oliii, that will come in handy another day!

I'm doing a one-button snake game (for as many players as there are usable keys on a keyboard). The snakes start out turning in circles around their own score/length displays, until a player presses their button they will continue to move in circles, however slowly but surely the snakes move off-center from the score display. This is indeed probably caused by the inacuracy of the euler method. I've read about it before, but I never actually noticed it until now. Wikipedia also says the inacuracy increases as the step size increases and I'm taking quite large steps, as big as possible without obvious jags.

It doesn't matter much for gameplay, but for aesthetic reasons it's still unacceptable to have the snakes wandering off like that. If it's an easy fix without too much extra cpu cost I would like to give that a try.

[Edited by - Kirl on May 10, 2010 8:15:58 AM]

Share this post


Link to post
Share on other sites
If the turning radius is not infinite (a left or right arrow key is pressed) then you should rotate and translate the object at the same time. If the radius is infinite, then you just do the translation.

In order to do the translation and rotation at the same time, construct a rotation matrix that has a center of rotation at the center of the circle you'd like to make with the object, the angle of rotation in radians should be linearSpeed / radius * deltaTime.

Linear speed in this case is essentially your radian velocity, or the velocity around the circumference.

If you organize your movement this way, the turning radius and speed will be independent and not subject to precision.

Share this post


Link to post
Share on other sites
Letting the timestep be 'tau' and the position vector be p=(x,y), the exact update rule is,

theta[k+1] = theta[k] + w[k] tau
p[k+1] = p[k] + (v[k]/w[k]) R(theta[k]) ( sin(w[k] tau), 1 - cos(w[k] tau) )

where R(theta[k]) denotes the rotation matrix,

              [ cos(theta[k]) -sin(theta[k]) ]
R(theta[k]) = [ ]
[ sin(theta[k]) cos(theta[k]) ]


(assuming I haven't made a silly mistake).

This will avoid integration error. Rounding errors will however creep in, but these are much smaller.

Notice that the first line of the above (the 'theta' update) is what you're doing already. And the 'p' update, to first order in 'tau,' is

p[k+1] ~= p[k] + (v[k]/w[k]) R(theta[k]) ( w[k] tau, 0 )
= p[k] + v[k] R(theta[k])(1, 0) tau
= p[k] + v[k]( cos(theta[k]), sin(theta[k]) ) tau

which is what (I think) you're doing now. So what you're doing is the first-order-accurate approximation to the exact update.

Oh yeah! Also... you have a fixed turning radius 'r,' right? Then the exact rule just becomes,

theta[k+1] = theta[k] + w[k] tau
p[k+1] = p[k] + u[k] r R(theta[k]) ( sin(w[k] tau), 1 - cos(w[k] tau) )

where u[k] is one of,
u[k] = 0 ===> Go straight
u[k] = +1 ===> Go left
u[k] = -1 ===> Go right.

Share this post


Link to post
Share on other sites
I managed a quick and clean fix for the starting animations. I just reset them every full turn. When the player starts playing, this behaviour is automatically overwritten by the normal behaviour.

Thanks for the help, it probably would've taken me a few days/weeks of confusion to remember eulers inacuracy.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this