Need some Math Help

Hi,

I am trying to achive some realistic AI control of a vehicle using UNITY 3D. I need a little math help. I’ve got the vehicle and wheels working just fine in Unity. The vehicle is moving and turning towards a randomly generated point on the surface. I’m having a probem with how to smoothly come out of the turn.

Take a look at my code:

if (angleVehicleToTarget > 1)
{
if (localTargetPoint.x > 0)
turningAngle += Time.deltaTime;

if (localTargetPoint.x < 0)
turningAngle -= Time.deltaTime;

if (turningAngle > 10)
turningAngle = 10;
if (turningAngle < -10)
turningAngle = -10;
}
else
turningAngle = 0;


turningAngle gets incrememnted or decrememnted (depending on the value of targetPoint.x in the transforms local space) by Time.deltaTime each time through FixedUpdate. This produces a nice steering effect when turningAngle gets passed to the wheels script. The steering gets clamped at an angle of 10 for now.

The problem is the else part: turningAngle =0.

This just snaps the wheels back to zero when we are on target. Ugh. Very unrealistic and ugly.

I’ve been trying with much failure to figure out the math to anticipate when to begin to come out of the turn. I’ve been studying a lot of AI code about chasing and evading, prey and predator pursuit, and pouring over the OpenSteer material on the net. I’m firing blanks.

If there are any math gurus out there who can point me in the right direction, I would be grateful.

How do I realistically come out of the turn to be on target. What is the math to anticipate that?

Thanks in advance for any help.

Mitch

Maybe I misunderstood your question, but can’t you just do this?

if (localTargetPoint.x > 0){
	turningAngle = Mathf.Lerp(turningAngle,Mathf.Clamp(anglevehicleToTarget,-10,10),0.5); 
}
else if (localTargetPoint.x < 0){
	turningAngle = Mathf.Lerp(turningAngle,Mathf.Clamp(-anglevehicleToTarget,-10,10),0.5); 
}

Grtz,
kaaJ

Thanks for the suggestion. I thought about using Mathf.Lerp and I played around with your code, but it’s not producing the desired result.

I’m sending the turningAngle variable to a wheels script each time through the FixedUpdate loop. So this is a physics/math issue. I’m looking for the math that will look at the velocity of the rigidbody, the relative position of the transform and the target, the rate of change in the turningAngle … so that the vehicle smoothly begins the turn and smoothly comes out of the turn so it is on target to intercept.

If Lerp can mimic or cheat that math, that would be cool, but I think I need the math algorithm to update the steeringAngle.

I did take physics and calculus back in college 25 years ago. I believe this is a differential equation or a quadratic solution since I am dealing with a rate of change in the turningAngle and rigidbody velocity. But I’m just so rusty.

Any thoughts (besides that I’m crazy!)?

Thanks Mitch

if (angleVehicleToTarget > 1)
{
if (localTargetPoint.x > 0)
turningAngle = Mathf.Lerp (turningAngle, 10, Time.deltaTime);
else if (localTargetPoint.x < 0)
turningAngle = Mathf.Lerp (turningAngle, -10, Time.deltaTime);
}


Here is how I revised the code and it kind of works, it smoothly steers in and out of a turn which is great - much cleaner then what I had.

But it produces an oscillating effect, it never really straightens out to be on target. It begins to turn back once it goes past the intercepttion path. And then it oscillates back and forth - as my simple coding tells it to.

So I still have the same problem - what is the math to anticipate when to begin come out of the turn given velocity, turning angle and distance?

I’ll tweak some more, but if anyone can suggest the algorithm, I would be grateful.

Mitch

What about a cusion range. You will never be at absolute 0. You need a few points of cusion I would think, in either positive or negative, so instead of trying to drive a tight wire, you are driving more of a wider rope.

Try something like this:

if (angleVehicleToTarget > 10)
{
if (localTargetPoint.x > 0)
turningAngle = Mathf.Lerp (turningAngle, 10, Time.deltaTime);
else if (localTargetPoint.x < 0)
turningAngle = Mathf.Lerp (turningAngle, -10, Time.deltaTime);
}
else if (angleVehicleToTarget > 3)
{
if (localTargetPoint.x > 0)
turningAngle = Mathf.Lerp (turningAngle, 3, Time.deltaTime);
else if (localTargetPoint.x < 0)
turningAngle = Mathf.Lerp (turningAngle, -3, Time.deltaTime);
}
else turningAngle = Mathf.Lerp (turningAngle, 0, Time.deltaTime);

That way the wheels will have a few ranges to work with. I’ve used something similar for a boat and it works quite well. There is very little oscillation and the vehicle will drive straight because it doesn’t always overshoot.

Jeff

Well, I got it all to work - I posted the code below for anyone to see and benefit.

I found that the Mathf.Lerp function was a decent cheat, but it only worked well at low velocity. As the rigidbody gains speed, Lerp falls short and the vehicle begins to oscillate back and forth and criss cross the intercept vector.

So I needed to dig down deep in my old tired brain and figure out the proper math from my physics/calculus college days. The math is essentiallty:

var turnBack = Mathf.Pow(curTurnAngle,2) * maxTurn/deltaSteer;

turnBack is the value in the if statement that tells the vehicle to begin to come out of the turn to wind up at zero turning angle when it reaches the intercept vector.

I’m not sure if the math is exactly correct, but it works. I have to explicitly set the curTurnAngle to zero when it’s on course or the vehicle goes wonky when it should go straight on course by itself. So that’s an unfortunate kludge for now. I probably have a if/else mistake somewhere in my code.

But it all works like a charm now - very realistic and smooth.

The rest of the code deals with incrementing or decrementing the turn angle but not going over the maximum turning angle for the vehicle. Not shown in this code snippet is the vehicle motor force and the part where the values get passed to the wheels script.

Anyway, thanks for all the help and suggestions - I’m posting the code in the hopes it will help someone else.

If anyone can suggest improvements (I’m a relative newbie at programming), please let me know.

Mitch

	// stuff for intercept
	var closingVelocity = Vector3.zero - rigidbody.velocity;  // since the targetpoint is not moving, it's velocity is zero
	var closingRange = targetPoint - transform.position;
	var closingTime = closingRange.magnitude/closingVelocity.magnitude;
	var predictedPosition =  targetPoint + (Vector3.zero * closingTime);

	// distance to target
	var targetDistance = Vector3.Distance (transform.position, predictedPosition);

	// when we reach the targetPoint, generate a new target
	if (targetDistance < 5)
		targetPoint = Vector3 (Random.Range (-100, 100), .5, Random.Range (-100, 100));

	// convert global corordinates to local coordinates 
	var localTargetPoint = transform.InverseTransformPoint (predictedPosition);
	// and normalize it
	Vector3.Normalize (localTargetPoint);
	
	// what is current angle to the target
	var curAngleToTarget = Vector3.Angle(localTargetPoint, Vector3.forward);
	// is it a positive or negative angle?
	if (localTargetPoint.x < 0)
		curAngleToTarget = -curAngleToTarget;

	// turnbackangle is the point in the turn where we have to begin to come out of the turn for proper smooth intercept
	var turnBack = Mathf.Pow(curTurnAngle,2) * maxTurn/deltaSteer;

  	if (curAngleToTarget > 0)  // turn right
  	{
  		if ((curAngleToTarget > turnBack)  (curTurnAngle < maxTurn)) // turn, but don't go over the maximum turning angle
  			curTurnAngle += deltaSteer*Time.deltaTime;
  		if (curAngleToTarget < turnBack)  // turn back, but don't go past zero
  		{
  			curTurnAngle -= deltaSteer*Time.deltaTime;
  			if (curTurnAngle < 0)
  				curTurnAngle = 0;
  		}
   	}
  	if (curAngleToTarget < 0)  // turn left
  	{
  		if ((curAngleToTarget < -turnBack)  (curTurnAngle > -maxTurn))   // turn, but don't go over the maximum turning angle
			curTurnAngle -= deltaSteer*Time.deltaTime;
		if (curAngleToTarget > -turnBack)  // turn back, but don't go past zero
		{
			curTurnAngle += deltaSteer*Time.deltaTime;
			if (curTurnAngle > 0)
  				curTurnAngle = 0;
		}
  	}
  	
  	if (curAngleToTarget == 0)
  		curTurnAngle = 0;

Thanks for sharing…

kaaJ