Advertisement

LookAt function

Started by September 05, 2006 10:14 AM
20 comments, last by gorogoro 18 years, 2 months ago
Hi! I'm having a lot of problems doing a LookAt function. The lookat function should rotate the agent so it faces some position, or direction. Here is the function:

bool Agent::LookAtDirection(Vector3f& dir, float angle, float speed /*=0*/)
{
	if(!speed)
		speed = GetMaxSpeed();

	dir.Normalize();

	Vector3f direction = GetWorldDirection();

	Vector3f upVector;
	GetWorldRotation().TransformVector(&upVector, Vector3f::k);

	float actualAngle = direction.Dot(dir);


	Vector3f c;
	float amount = 1;
	c.Cross(direction, dir);

	if (upVector.Dot(c) < 0)
		amount = -amount;
			
	if ( !((actualAngle >= angle)))
	{
            SetDesirableRotateZSpeed(-amount * speed);
		return false;
	}
}


As you notest I have a variable named amount this is used to determine to wich direction should the agent turn, to the left or to the rigth. But sometimes the agent passes the angle, and enters in the if, then the amount change the signal and agent turns to the other side. So the agent does'nt move and keeps shaking. The angle is the aperture angle so it is safe to say, ok you are aligned. The angle should vary accordingly with the distance. So as longer the distance the angle should be closer to 1, else it should be closer to 0.85 or something like that. For the angle I have this function:


float Agent::CalculateAngle(const Vector3f& pos)
{
	float sqrdist = GetWorldPosition().SquareDistance(pos);
	float alpha = sqrdist / (1600 + sqrdist);

	//alpha = cos(pi / 2 - atan(sqrdist));
	// alpha = sqrdist / sqrt( 500 + sqrdist * sqrdist );
	return ClampMinMax(alpha, 0.85f, 0.97f);
}


The comment code is some experience based on a post in this forum to. Basically I've tried to change the aperture of the angle, but or it is to much and the agent thinks that is in front of something and it isn't or else it starts shaking :p. I've tried to make some signal test, I mean when the variable amount changes its signal i return true. But it makes the same shake problem sometimes. I've also tried to slow down the rotation speed so it should not "jump" through the angle, without any positive result also. Now I'm running out of ideias. :p Have anyone passed through the same problem? Any more ideas?
Yes


use a PD-Controller and some dampening
works wonders

if you dont know that means, say so...
Advertisement
Quote: Original post by Anonymous Poster
Yes


use a PD-Controller and some dampening
works wonders

if you dont know that means, say so...


Help? :)
a PD Controller
or more generically a PID Controller

generates a control output (for example how fast to turn) based on P proportional, I integral, and D derivative inputs.


in your case 'P' would be the difference in degrees between current direction and target direction

'D' would be the deriviative of 'P' -how fast that angle difference changes over time

and 'I' we shall ignore - this is more useful for stuff like Air Conditioners


psuedocode PID Controller:


class PID{
float P,I,D;
void init(float p,float i,float d){P=p;D=d,I=i;}

float controldecision(float error){
static float deriv=0;
static float lasterror=0;
static float integral=0;

deriv=error-lasterror;
lasterror=error;
integral+=error;

return (P*error)+(I*integral)+(D*deriv);

}

}




That code uses Static variables, so you will need a new instance for each object being controlled.
the idea is that each gameloop (better have a fixed timestep) you will call controldecision(), and pass the signed difference in degrees between your direciton and target as an argument. it will return a float, which you will use as your rotation force.
The trick of course, is initializing the Controller with Good values for P,I,and D.
it needs to be 'tuned' to work with whatever you are trying to control.
In your case, i'd leave 'I' as 0.
Start out with P and D as something small, like .5 for now
experiment with them, which one is larger or smaller, etc, till it starts acting properly.
if it occilates too much (back and fourth motion) try increasing D
if it doesnt move fast enough, try increasing P
...
if it explodes, reduce both P and D by a factor of 10
Special note:
the angle input you pass to controldecision
Must be the Relative angle between your current direction, and your goal direction; from the character's reference frame. Do not use absolute coord system angles, since that will mess up....
and it should be signed so that for example left is - and right is + (or vice versa)
Advertisement
Quote: Original post by Anonymous Poster
Special note:
the angle input you pass to controldecision
Must be the Relative angle between your current direction, and your goal direction; from the character's reference frame. Do not use absolute coord system angles, since that will mess up....
and it should be signed so that for example left is - and right is + (or vice versa)


Thanks a lot for the help!
Never heard about that PID controller! Do you have any reference of interest? I've google it, but didn't find any really interesting!

By the way! If you my lookAt function returns a boolean telling if the agent is already at position or not. How can I now that with a PID controller? When the returning value its close to 0??

[Edited by - gorogoro on September 6, 2006 9:57:05 AM]
Yep,
I got into these myself when I was doing a similar problem to your's (spaceship rotation controls) and I heard vaguely that PID was a control method used in robotics...

Its kinda hard to find good tutorials or explanations that aren't math/engineering intensive, since thats apparently the field they come from, but this link helped me a lot
http://www.embedded.com/2000/0010/0010feat3.htm
has a lot of nice graphs of the resulting motions of a simple motor and stuff, so you can get an intuitive feel for how the adjustments work

the wikipedia entry actually looks pretty good too...
Get any introductory text book on Control Theory and it will cover, in depth, PID-based control. My personal recommendation is 'Automatic Control Systems' by Benjamin Kuo. Books such as this, aimed at 2nd and 3rd year engineering students, typically cover the mathematical preliminaries you need for understanding and analysis in their early chapters, so if you're coming from a non-engineering background, you shouldn't have too much trouble learning the material (particularly if you keep a basic calculus book beside you as your read it).

As to where PIDs are used, well, it's not just robotics. Indeed, around 95% of controllers used in commercial control applications (and here I mean everything from spacecraft and aircraft flight systems through to thermostats in your house) are PI or PD controllers (there are very few full PID controllers, since they are generally not needed).

If you want more specific information or need help understanding PIDs, just holler.

Cheers,

Timkin
Freaking out once again! :p

I've read the wiki tutorial and the paper you post, but didn't understand to much about the process. Have to read more times I guess :P

I've implemented the pidController just like yours.

But the behaviour is exactly the same :(. It never stops from oscilate, even if I increase the D value or the P value. I'm seek of trying to tunne this values without good results. Humpf.

I've levead the CalculateAngle function.

Here are the alterations I've done to the LookAt function:

bool Agent::LookAtDirection(Vector3f& dir, float angle, float speed /*=0*/){	if(!speed)		speed = GetMaxSpeed();	dir.Normalize();	Vector3f direction = GetLocalDirection();	Vector3f upVector;	GetWorldRotation().TransformVector(&upVector, Vector3f::k);	float actualAngle = direction.Dot(dir);	//float error = angle - actualAngle;	if(actualAngle >= angle)		actualAngle = 0;	else	      actualAngle = 1 - actualAngle;			//TODO: Think of a way to do this in 3D (plain behavior!!)	Vector3f c;	float amount = 1;	c.Cross(direction, dir);	if (upVector.Dot(c) < 0)		amount = -amount;	float amountAux = m_pidController.ControlDecision( -amount * (actualAngle));		std::string text("PIDController returned: ");	SharedTools::RealToString(amountAux, text);	FE_LOG(text);	if ( amountAux < 0.05 && amountAux > -0.05)		return true;			SetDesirableRotateZSpeed(amountAux);	return false;}



any more suggestions? I'm doing anything wrong?
[depressed]

This topic is closed to new replies.

Advertisement