Advertisement

LookAt function

Started by September 05, 2006 10:14 AM
20 comments, last by gorogoro 18 years, 2 months ago
first thing I notice:

what does

	if ( amountAux < 0.05 && amountAux > -0.05)		return true;

do?

Looks to me like if the output gets small, you cancel out of the function and don't do any rotation force
is that what it's doing?

because... thats bad, having a 'deadband' in the middle will certainly cause problems with the controller losing control at the critical moment...

try commenting that part out


There might also be issues with the way you input your angle stuff to the controller, but i havent looked at that part in detail yet, fix this obvious one first...
alternatly, since I think you probably wanted to keep the return value for some other purposes... change this:

	if ( amountAux < 0.05 && amountAux > -0.05)		return true;			SetDesirableRotateZSpeed(amountAux);	return false;


to this:
	SetDesirableRotateZSpeed(amountAux);	if ( amountAux < 0.05 && amountAux > -0.05)		return true;	return false;


Bascially, even though you are 'close enough' to target and return 'true' that youre pointed at it, still do apply the rotation force
that PD Controller needs to be operative even when you are 'close enough' so it can make a finely controlled stop, and keep you from occilating...
Advertisement
Tunning tunning! Can't stable this thing.

Ok! Some changes done. Even with low values I make the rotation now. And I've changed the way I calculate the error (PID input).

Now it is like this:

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;	if(actualAngle >= angle)		error = 0;	else if(actualAngle > 0)		error = angle - actualAngle;	else		error = -actualAngle + angle;	Vector3f c;	float amount = 1;	c.Cross(direction, dir);	if (upVector.Dot(c) < 0)		amount = -amount;	float amountAux = m_pidController.ControlDecision( -amount * (error));	std::string text("PIDController returned: ");	SharedTools::RealToString(amountAux, text);	FE_LOG(text);	SetDesirableRotateZSpeed(amountAux);	if ( amountAux < 0.05 && amountAux > -0.05)		return true;		return false;}


Since the angle is the cos(alpha).
The angle is calculated the same way, using the CalculateAngle function posted in the begging of the thread.
I would have set a target angle and simply rotated the agent according to an interpolated value between the start and target angles.
Quote: Original post by Eldritch
I would have set a target angle and simply rotated the agent according to an interpolated value between the start and target angles.


Depends if your agent motion is based on physics or if you just want graphical smoothness...

I use the method you describe for my camera, but PD Controllers with Newtonian physics for all in-game entities
Quote: Original post by Eldritch
I would have set a target angle and simply rotated the agent according to an interpolated value between the start and target angles.


I've tried that with no good results

Quote: Original post by Anonymous Poster
Depends if your agent motion is based on physics or if you just want graphical smoothness...

I use the method you describe for my camera, but PD Controllers with Newtonian physics for all in-game entities


The motion is based on physics. But I'm not getting there with the PD Controller either....

Any other suggestion?? This is suposed to be a simple problem, but I'm not getting there :'(

Damn!

[Edited by - gorogoro on September 11, 2006 9:15:03 AM]
Advertisement
Okay... lets look at your code line by line...

I'm going to repost your code, with Comments and Questions added
I suggest, that the best way for you to answer my questions, is to repost this, with even more comments of your own added

//tell me about dir and angle, what do they represent?//is one the target and one the current orientation? which is which?bool Agent::LookAtDirection(Vector3f& dir, float angle, float speed /*=0*/){	if(!speed)		speed = GetMaxSpeed();	dir.Normalize();	//is this returning the current direction your character faces?	Vector3f direction = GetLocalDirection();	Vector3f upVector;	GetWorldRotation().TransformVector(&upVector, Vector3f::k);	//here you seem to be finding the dot produce between direction and dir	//but I dont know exactly what each one means...	//if the angle between them is small... this should return near1	//if they are near perpendicualr, it shoudl return near 0	//obtuse angles are negative...	//it tells nothing about rotating left or right, just magnitude	//are you sure that dot product is what you wanted?	//it's not Exactly the same as the actual angle between them...	//BUG?	float actualAngle = direction.Dot(dir);	float error;	//as usual, what is 'angle'?	if(actualAngle >= angle)		error = 0;	else if(actualAngle > 0)//both of these branches are the same!!??		error = angle - actualAngle;	else		//-actualangle+angle is the same as angle-actualangle above		//this IF doesnt actually do anything		//BUG?		error = -actualAngle + angle;	//not sure where you're going with this part...	//complicated, can you explain?	Vector3f c;	float amount = 1;	c.Cross(direction, dir);	if (upVector.Dot(c) < 0)		amount = -amount;	float amountAux = m_pidController.ControlDecision( -amount * (error));	std::string text("PIDController returned: ");	SharedTools::RealToString(amountAux, text);	FE_LOG(text);	SetDesirableRotateZSpeed(amountAux);	if ( amountAux < 0.05 && amountAux > -0.05)		return true;		return false;}





Here's how I might do it (if debugging all my comments above doesnt work)
(its good to help think about it anyway)
a lot simpler anyhow

given:
vector goaldirection //aim here
vector currendirection //currently we face here
vector up //the world UP direction

...
vector rightside=cross(currendirection,up) //this might be backwards
float turnapprox= dot(goaldirection,rightside)
//turnapprox will return +1 when the direction to turn is near rightside
//-1 when direction to turn is opposite to rightside
//0 when nearly centered
//potential bug, it doesnt check if goal is in front or back of himself
//only left/right side comparision, this is OK for most cases, since we just turn...
float amountturn = m_pidController.ControlDecision( turnapprox);
P.S.
I notice you are in Portugal
I am in the USA
my morning is your afternoon
and my afternoon is your night

communication may be faster if you check this messageboard around 5-10 evenings your time, since then I will also be online and might respond faster




Also, to fix the 'check front/back' bug in my example code, all you have to do is do another dot product against the currentdirection vector(forward)
and increase the magnitude of error value if target is behind (just to make it respond faster)
..but save that for later.. keep simple first
Ok!

Let's do it.

//The angle is the acceptable angle so we can say: "Ok your are facing the //rigth direction!//It varys, so if the agent is far from the thing it wants to face the angle is //near 0.97 (near 1). Else if the agent is close then the acceptable angle is //near 0.70bool Agent::LookAtDirection(Vector3f& dir, float angle, float speed /*=0*/){	if(!speed)		speed = GetMaxSpeed();	dir.Normalize();	//is this returning the current direction your character faces?	//YES	Vector3f direction = GetLocalDirection();	Vector3f upVector;	GetWorldRotation().TransformVector(&upVector, Vector3f::k);	//here you seem to be finding the dot produce between direction and dir	//but I dont know exactly what each one means...	//Here I'm just finding the up vector of the agent. 	//this is used just to determine if the agent should turn to the right or to the left	//if the angle between them is small... this should return near1	//if they are near perpendicualr, it shoudl return near 0	//obtuse angles are negative...		//Exacly, thats the point	//it tells nothing about rotating left or right, just magnitude	//are you sure that dot product is what you wanted?	//it's not Exactly the same as the actual angle between them...	//BUG?		//the point here is to determine de cos(angle) of the agent and the 	//goal diretion it wants to face.	float actualAngle = direction.Dot(dir);	//Dot product from the agent orientation and the goaldirection	float error;	//if the Dot product from the agent orientation and the dir is longer than the angle then it is facing the goaldirection	if(actualAngle >= angle)		error = 0;	else if(actualAngle > 0)//both of these branches are the same!!??		error = angle - actualAngle;	else		//-actualangle+angle is the same as angle-actualangle above		//this IF doesnt actually do anything		//BUG?		//you are rigth. this is not a bug, but an useless code.		error = -actualAngle + angle;	//not sure where you're going with this part...	//complicated, can you explain?	//this is used to determine to wich side the agent turns (left or rigth)	Vector3f c;	float amount = 1;	c.Cross(direction, dir);	if (upVector.Dot(c) < 0)		amount = -amount;      //and is working fine :)	float amountAux = m_pidController.ControlDecision( -amount * (error));	//debug stuff	std::string text("PIDController returned: ");	SharedTools::RealToString(amountAux, text);	FE_LOG(text);	SetDesirableRotateZSpeed(amountAux);	if ( amountAux < 0.05 && amountAux > -0.05)		return true;		return false;}


I'm going to put a cleaner code now.

bool Agent::LookAtDirection(Vector3f& goalDirection, float acceptableAngle, float speed /*=0*/){	//Speed is deprecated 	if(!speed)		speed = GetMaxSpeed();	dir.Normalize();	//returning the current direction the character face		Vector3f agentDirection = GetLocalDirection();	//the point here is to determine de cos(angle) of the agent and the 	//goal diretion it wants to face.	float actualAngle = agentDirection.Dot(goalDirection);	//Dot product from the agent orientation and the goaldirection	//if the angle between them is small... this should return near 1	//if they are near perpendicualr, it shoudl return near 0	//obtuse angles are negative...	float error;	//if the Dot product from the agent orientation and the dir is longer than the angle then it is facing the goaldirection	if(actualAngle >= acceptableAngle)		error = 0;	else 		error = acceptableAngle - actualAngle;			//this is used to determine to wich side the agent turns (left or rigth)	//GetWorldRoation gives the world rotation of the agent	Vector3f upVector;	GetWorldRotation().TransformVector(&upVector, Vector3f::k);		Vector3f c;	float amount = 1;	c.Cross(agentDirection, goalDirection);	if (upVector.Dot(c) < 0)		amount = -amount;    	//and is working fine :)	//the pid controller	float amountAux = m_pidController.ControlDecision( -amount * (error));	//debug stuff	std::string text("PIDController returned: ");	SharedTools::RealToString(amountAux, text);	FE_LOG(text);	SetDesirableRotateZSpeed(amountAux);	if ( amountAux < 0.05 && amountAux > -0.05)		return true;		return false;}


Now I'm going to try something simpler as you suggested :)

[Edited by - gorogoro on September 12, 2006 6:54:07 AM]
Thanks a Lot for your help Anonymous Poster.

It is working fine now with no occilations (at least it seams like that). More testing to come, but I have to move on..

Here is my final code:

bool Agent::LookAtDirection(Vector3f& goalDirection, float angle, float speed /*=0*/){      //speed deprecated	if(!speed)		speed = GetMaxSpeed();	goalDirection.Normalize();	Vector3f up;	GetWorldRotation().TransformVector(&up, Vector3f::k);	Vector3f rightside; 	rightside.Cross(GetLocalDirection(), up); //this might be backwards	float turnapprox = goalDirection.Dot(rightside);	float wtf = GetLocalDirection().Dot(goalDirection);	float amountturn = m_pidController.ControlDecision( turnapprox );	std::string text("PIDController returned: ");	SharedTools::RealToString(amountturn, text);	FE_LOG(text);	SetDesirableRotateZSpeed(amountturn);	if ( amountturn < 0.05 && amountturn > -0.05)		return true;	return false;}


[Edited by - gorogoro on September 12, 2006 9:02:51 AM]

This topic is closed to new replies.

Advertisement