Sign in to follow this  
yenal

Need help about simple car steering in 2D

Recommended Posts

yenal    126
I am trying to make the car turn in 2D. There is really no physics involved. It should be as simple as possible. I know I have to calculate the angular velocity. But all the tutorials I've found are complex for my case. All I need is the position and the heading vector after time dt. Let's say that I have the following information: - Position vector - Direction vector - Current speed (For now think that the car moves in constant speed. No acceleration) - Turning angle How can I find the next position and direction with the given info? Thanks, Yenal

Share this post


Link to post
Share on other sites
oliii    2196
if you have the wheelbase, you're sorted.




you can find the point of rotation (O) given the turning angle and the wheelbase.

the rate of turn is also given by the equation.

w = V / r

r is calculated from the wheel turning angle. And so is the centre of rotation O.

Share this post


Link to post
Share on other sites
Cybernator    122
How about this? (haven't tested it, might be erroneous)

Position vector += Directrion vector * Current speed
Direction vector.x = Direction vector.x * cos (Turning angle) - Direction vector.y * sin (Turning angle)
Direction vector.y = Direction vector.x * sin (Turning angle) + Direction vector.y * cos (Turning angle)

Where Direction vector is the absolute orientation (and unit vector, of course), and Turning angle is relative to the Direction vector.

Share this post


Link to post
Share on other sites
MrRowl    2490
You need to define what you mean by "turning angle" and even speed...

Bear in mind that the two front wheels will turn different amounts:

When the car is turning the normals to each wheel will all point towards one single point (as in oliii's diagram, but with an extra pair of wheels)

and

The inner rear wheel will rotate slower than the outer rear wheel (and the front wheels will go at different rotation speeds too) - so the inner side of the car travels slower than the outer side.

Anyway - to get your answer then you know that each wheel follows a circle, radius R. If you know the speed S of that wheel, you know how far along the circle it goes in a given period of time, t. Divide this distance by the circle circumference (2*pi*R), and multiply by 360 will give the car orientation change in degrees:

orientation angle change = (S * t / (2 * pi * R)) * 360

Share this post


Link to post
Share on other sites
yenal    126
What I mean by turning angle is the angle between the heading vector and the wheel. I am trying to solve Homicidal Chauffeur Problem. http://www.google.com/search?hl=en&q=homicidal+chauffeur . Before solving the problem I have to get the car moving so it can pursuit the pedestrian. This is not a 3D game. I don't simulate any wheels or anything. All I have is a sprite. Maybe I am underestimating the complexity of the car's movement.

Share this post


Link to post
Share on other sites
yenal    126
Quote:
Original post by Cybernator
How about this? (haven't tested it, might be erroneous)

Position vector += Directrion vector * Current speed
Direction vector.x = Direction vector.x * cos (Turning angle) - Direction vector.y * sin (Turning angle)
Direction vector.y = Direction vector.x * sin (Turning angle) + Direction vector.y * cos (Turning angle)

Where Direction vector is the absolute orientation (and unit vector, of course), and Turning angle is relative to the Direction vector.


I don't think that would work because that's the regular rotation by the angle. I need a way to calculate the new direction vector. Thanks

Share this post


Link to post
Share on other sites
yenal    126
Ok I took it this far:

// ( mHeight * 0.75f ) -> this is my wheelbase, mHeight is the sprite's height.
float turningRadius = ( mHeight * 0.75f ) / ( 2.0f * cosf( TORAD( 90 - mMaxTurningAngle / 2 ) ) );

// This is the change in angle for the time elapsed.
float angularVelocity = ( ( mMaxSpeed * elapsedTime ) / ( 2.0f * PI * turningRadius ) ) * 360.0f;

// This is just for drawing the sprite
mRotationAngle += angularVelocity;

// I rotate the Direction vector by the amount of angularVelocity
mDirection = mDirection.rotateAboutGlobalZ( TORAD( angularVelocity ) );

// Here comes the problematic line
mPosition += ( mDirection * mMaxSpeed * elapsedTime );

As long as the simulation runs constantly this line works expected. But if the app stops for a while the elapsedTime becomes too high and car moves too much. How can I fix this behavior?

Maybe I can fix the issue by figuring out if the game is not running. In SDL when you drag the window it somehows stops rendering. But still this solution seems like frame rate dependent. Some help would be appreciated. Thanks.

Yenal

Share this post


Link to post
Share on other sites
yenal    126
I think I know what is wrong but I do not know how to formulate it. In each update, the car is moved in a straight line. This is fine as long as you have a solid framerate. But to be accurate the car's movement should follow the circle. Correct me if I am wrong. Thanks.

Share this post


Link to post
Share on other sites
yenal    126
I solved the problem like this:

void Game::Car::Move( float turningAngle, double elapsedTime )
{
if ( turningAngle == 0.0f )
{
mPosition += ( mDirection * float( elapsedTime ) * mCurrentSpeed );
}
else
{
// If the turning angle has changed then calculate the rotation center again
if ( mLastTurningAngle != turningAngle )
{
float angleToFindRotationCenter = 90.0f;
// Set the rotation center
//if ( turningAngle < 0.0f ) // Turning right
// angleToFindRotationCenter = -90.0f;

Vec3 tmpPosition = mPosition + ( mDirection * GetTurningRadius( turningAngle ) );
mRotationCenter.x = cosf( DEG2RAD( angleToFindRotationCenter ) ) * (tmpPosition.x - mPosition.x ) - sinf( DEG2RAD( angleToFindRotationCenter ) ) * (tmpPosition.y - mPosition.y);
mRotationCenter.y = sinf( DEG2RAD( angleToFindRotationCenter ) ) * (tmpPosition.x - mPosition.x ) + cos( DEG2RAD( angleToFindRotationCenter ) ) * (tmpPosition.y - mPosition.y);
mRotationCenter += mPosition;
}

// Calculate the angular velocity
float angularVelocity = ( ( mCurrentSpeed * float( elapsedTime ) ) / ( 2.0f * PI * GetTurningRadius( turningAngle ) ) ) * 360.0f;

// Update the car's direction
mDirection = mDirection.rotateAboutGlobalZ( DEG2RAD( angularVelocity ) );

// Update the current angle of the car, used in sprite drawing
mRotationAngle += angularVelocity;
if ( mRotationAngle > 360.0f)
mRotationAngle -= 360 * ( int( mRotationAngle ) / 360 );

// Calculate the new position
Vec3 tmpPosition = mPosition;
mPosition.x = cosf( DEG2RAD( angularVelocity ) ) * (tmpPosition.x - mRotationCenter.x ) - sinf( DEG2RAD( angularVelocity ) ) * (tmpPosition.y - mRotationCenter.y);
mPosition.y = sinf( DEG2RAD( angularVelocity ) ) * (tmpPosition.x - mRotationCenter.x ) + cos( DEG2RAD( angularVelocity ) ) * (tmpPosition.y - mRotationCenter.y);
mPosition += mRotationCenter;
}

// Assign the last turning angle
mLastTurningAngle = turningAngle;
}

I am sure this is not the most efficient way to do it. Comments are appreciated.

Share this post


Link to post
Share on other sites
oliii    2196
you sure it's cos? for me it's a tangent.

tan(90 - a) = rad / wheelbase
-> rad = wheelbase * tan(90 - a)

and w = v / r

also remember that car have physical limits. They can't turn as fast as they want at high speed. so you can cap the angular velocity given the speed of turn, by for example, using the centrifugal force formulae.

the grip limit is usually a ratio betwee the upward force on the tyre and the longitudinal and side force on the tyre. exceed that, and the car will not turn steadily.

to make it even simpler, you can work with accelerations, and the grip limit would be the coefficient of the centrifugal force and longitudinal force (acceleration), against the gravity. The grip limit of a tyre in the region of 1.0.

-> (car_break_or_accel + centrifugal_accel) / grav < grip


float r = car.wheelbase() * tan(pi/2 - car.steerAngle());
float lf = car.forwardAcceleration(); // brake or accel pedal
float sf = car.forwardVelocity() * car.forwardVelocity() * / r; // centrifugal accel : v^2 / r
float slip = car.tyreGrip() * world.gravity() / (lf + sf); // slippage
if (slip > 1.0f) slip = 1.0f;
car.anglularVelocity() = car.steerAngle() * slip;




something like that. So if you turn the wheels violently at high speed, you'd understeer, just to keep car physics in check. You can also use that for the AI to throttle their inputs and predict how much they can steer, accelerate or brake around a corner.

EDIT : the real slip equation would be something like...

if((lf + sf) > grip * grav)....
turnRad = car.vel() * car.vel()) / (grip * grav - carAccel);
turnAngle = atan(turnRad / wheelbase) - pi/2;

if the grip is exceeded. Something similar. Putting on paper and solving it should be easy.

Share this post


Link to post
Share on other sites
yenal    126
Like I have specified before, this is not a car simulation. It's a solution to a classical problem. There is only a turning radius and speed involved. Nothing else. But thank you for pointing that out.

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