mardi 4 décembre 2007

Angles in SL, and the llAtan2 method

Working on the connection of a vehicle in Second Life and a robot ( a simple Lego NXT) to steer in Real Life, the absolute angle had to be found in Second Life.

For this the rotations, llGetRot() were not too appropriate. Not because these are quaternions, and not degrees, no, no:

The problem of rotations in general is that is goes from 0 – 360 and then in one jump back to 0. So adding two of these can give strange results! For instance 180 + 185 = 5! Adding is not a problem, but finding an average might be: the average of 180 and 185 is 2.5, haha!

*(180 + 185) / 2 = 182.5 in our world, but because of the jump in the degree world this becomes 2.5!

I needed the angle of steering for the robot, I had to subtract two angles, and was running into another difficulty: the rotations in SL give only angles from 0-180 degrees. So left and right was a bit difficult to get! Of course there are many solutions to this. (Even with the quaternions itself, but let's solve this without mister Hilbert!)

Two objects, say lying 1 meter apart have a different position. From this difference the angle can be calculated using simple math, normally the arctan, or the atan.

Same problem here: the atan returns angles between 0 and 180 or 0 and -180, so the backwards angles between 180 and 360 had to be found considering the configuration of the objects. Not too difficult but something extra to consider.

But then, for once the Linden script had a surprise to the positive side:
The
Linden function is llAtan2, and this 2 is puzzling, not to be explained in the wiki.
Some experimenting resulted in the nice behavior of this function: it returns the full angle, from 0 – 360 degrees. This makes life easy!!

So the configuration for the absolute angle in SL:
Two objects linked, one, sending its position to the root every half sec:

Script:

default

{
state_entry()
{
llSetTimerEvent(.5);
}

timer()
{
llMessageLinked(LINK_ROOT, 0, (string) llGetPos() , NULL_KEY);
}
}

and the root receiving the message and making an angle of this position and the position of his own:

default

{

state_entry()
{ }

link_message(integer sender_num, integer num, string str, key id)

{
vector myPos = llGetPos();
vector childPos = (vector) str;
vector diff = myPos - childPos;
float x = diff.x;
float y = diff.y;
angle = PI - llAtan2( x,y ) ;
llSay(0,(string)( angle/PI*180));
}
}

Ok, the PI in front of the function is extra, whatever you need on angle, which way etcetera, you have to decide for yourself….

And combining this recent angle, with the angle measured just before is what gives me the steering angle for the robot, to be sent to the server and the server is asked for this angle by a C# prog which is running on my laptop, this C# prog is also connected with Bluetooth to the NXT, and it steers! (Well all the connections take a bit of time, so the robot is bumping in a wall before you know it…no steering your own real car from Second Life J