Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

New Way to approach the problem...!

Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-10-2009 20:35
Yes, I expected it to be executed multiple times. As I said, when I tested this code (in a timer with smaller period than the constant 'TAU' I had in the code above) it worked okay for small deviations in orientation until the orientation was close to, "fixed," then it tended to get unstable and go crazy. Likewise, if the orientation was far off the desired, it tended to be pretty wild. It seemed that the code was trying to do the right thing (i.e. turn in the correct direction), but timing and such made the solution impractical. Maybe by playing with timing and the amplitude of the target omega and such you can get it to work.

The logic applies an impulse which SHOULDN'T mess with the heading, as the desired "target" rotation has the same heading as the one found at the beginning of execution. However, it does try to cancel any angular speed about the global z direction. I believe that could be changed though, by modifying the angular speed that is subtracted from the target omega to have no component about the z-axis.
Ryder Spearmann
Early Adopter
Join date: 1 May 2006
Posts: 216
06-14-2009 11:03
Hi Hewee...

When you applyrotationalimpulse... your code does not specify the local reference in the function, so I tried both... it appears the impulse is meant to be applied locally, so I set it to TRUE.

I sent you my Float Cube in game, and you can see how amazingly stable it is... it never overshoots.... but as I don't have my references sorted out... it has a 0 degree heading requirement.

Give it a try, see what you think!

Ryder
Ryder Spearmann
Early Adopter
Join date: 1 May 2006
Posts: 216
06-15-2009 14:28
From: Hewee Zetkin
... MAYBE with very careful timing you could get it to work all right, but you might unfortunately just have to go with llRotLookAt().


Hi Hewee... well, I honestly can't quite "get" what is happening in your code... but it seems to me that perhaps it could be simplified somewhat. I am wondering about the instability... and it seems to me that it could be coming from changes in apparent pitch when combinations of yaw and roll are added. For example, a 90 degree roll puts the pitch at 0 degrees (region axis) regardless of "true pitch". What this means, is that for any given pitch, there is a roll that will make attaining that pitch literally impossible. At lesser rolls, while perhaps not impossible, simply very hard. This, to my thinking, causes overly large impulses... so that when roll corrects, it changes the delta vector for the pitch. I think that if one were to redefine pitch, not against a regional axis, but rather off of a prim normal, that would be best.

Does that make sense?

above, you mention llRotLookAt... what is your thinking there?

That uses a target in a local rotation reference, right? How to isolate only one axis, and yet have the other two free to roam?

-rs-
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-16-2009 22:08
Well, the actual target orientation is calculated to have the same horizontal heading as the code originally finds the prim facing (BTW, make sure it is in the root prim). The impulse is designed to stop any current angular velocity and then create a new angular velocity that rotates the object toward that calculated target orientation with a speed proportional to the angle that needs to be subtended.

The target orientation is calculated correctly. You can tell by testing the following code (in a non-physical prim of course), which simply sets the prim to the target orientation once instead of constantly applying impulses to get it there eventually. I actually started with such code before switching over to the timed impulses, to make sure the logic was working correctly.

CODE

rotation currRot = llGetRot();
vector currFwd = llRot2Fwd(currRot);

rotation targetRotUnpitched = llRotBetween(<1.0, 0.0, 0.0>, llVecNorm(<currFwd.x, currFwd.y, 0.0>));
rotation pitchRot = llAxisAngle2Rot(<0.0, 1.0, 0.0>, -10*DEG_TO_RAD);
rotation targetRot = pitchRot*targetRotUnpitched;

llSetRot(targetRot);


P.S. - Oh, and I see what you mean about my leaving out that local parameter. Actually it should most definitely be FALSE. At least it should be if llApplyRotationalImpulse() were working correctly. See below.
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-16-2009 22:45
Okay. I've discovered something VERY WEIRD. Here is a script which, on the first touch (and every other touch thereafter), applies a random rotational impulse. On the second touch (and every other touch thereafter), it applies a rotational impulse equal to the negative of its current angular velocity.

This means when the object is touched, it should start rotating. When it is touched again, it should stop rotating. (Rinse and repeat.) And indeed it works. SOME OF THE TIME. The rest of the time it goes absolutely crazy, rotating the object even faster than it was at first when it should be stopping it. I believe this is the root cause of the instability of the first script, and I can only imagine that it is a serious bug in the physics engine and/or llApplyRotationalImpulse() API function.

CODE

default
{
state_entry()
{
vector pos = llGetPos();
llSetStatus(STATUS_PHYSICS, TRUE);
llSetBuoyancy(1.0);
llMoveToTarget(pos, 0.1);
}

touch_start(integer nDetected)
{
state rotating;
}
}

state rotating
{
state_entry()
{
llApplyRotationalImpulse(<llFrand(1.0), llFrand(1.0), llFrand(1.0)>, FALSE);
}

touch_start(integer nDetected)
{
state still;
}
}

state still
{
state_entry()
{
llApplyRotationalImpulse(-llGetOmega(), FALSE);
}

touch_start(integer nDetected)
{
state rotating;
}
}
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
06-16-2009 22:56
From: Hewee Zetkin
I can only imagine that it is a serious bug in the physics engine and/or llApplyRotationalImpulse() API function.

I ran into this about a month back trying to get a smotoher rotation for a physics driven camshaft... I THINK it might be in the way the physics enging is applying (or reading back) the rotational impulse... it seems to do so in snapshots, which similar to the visual effect of counter rotation means the sim believes it's moving contrary to it's current motion.... I had no luck slowing it down enough to counter this and gave it up as a lost cause. it's almost as if the sim decides based on the current facing at the time of the snapshot of it's motion if it's traveling in one direction or the other at the relevant speeds... I gave it up as a lost cause.
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-16-2009 22:58
From: Ryder Spearmann
above, you mention llRotLookAt... what is your thinking there?

That uses a target in a local rotation reference, right? How to isolate only one axis, and yet have the other two free to roam?

Yeah. See, the problem with using llRotLookAt() is that it will constrain the rotation completely to the one specified. If there were a hard enough impulse, torque, or whatever to spin the heading away from its current direction and keep it there until the logic ran again, then the heading could change. Perhaps llRotLookAt() could be used for brief moments and then turned off between impulses used for control input.

Or perhaps you could go down to a lower level of logic and calculate the heading you want manually using careful timing and incremental control inputs. I've done that before, though it is a pain and has to be done carefully. For example, have an 'omega' (about the global z-axis to change heading only) global that you change over time and as a result of left and right inputs. Also each time the timer fires or you get new input, calculate the amount the heading should have changed based on the current value of 'omega' and the amount of time that has passed since the last calculation. Then use llSetRot() or llRotLookAt() like in the test code I gave above, instead of using llApplyRotationalImpulse(). Of course, if you go this route, you might be stuck dealing with all your other movement and control inputs in a similar way.
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-16-2009 23:36
Here you go:

http://jira.secondlife.com/browse/SVC-4399 ("llGetOmega() and/or llApplyRotationalImpulse() work incorrectly about half the time";)
Ryder Spearmann
Early Adopter
Join date: 1 May 2006
Posts: 216
06-17-2009 00:01
Hey Hewee,

I played with your test code in a cube...

Here is what I found. It never worked, no matter how many times I clicked. Many dozens.

It did, however, disappear, shot off some direction... :)

If you move the cube slightly (grabbed with left MB click), that appears to stop rotation, overriding the impulse... which gives the appearance that the rotation stopped.

I believe I discovered something critical...

Try this in a standard cube:


integer mode = 0;
default
{
state_entry()
{
llSetStatus(STATUS_PHYSICS, FALSE);
llSetRot(ZERO_ROTATION);
vector pos = llGetPos();
llSetStatus(STATUS_PHYSICS, TRUE);
llSetBuoyancy(1.0);
//llMoveToTarget(pos, 0.1);
}


touch_start(integer nDetected)
{
if (mode==0)
{
llApplyRotationalImpulse(<llFrand(0.05), llFrand(0.05), llFrand(0.05)>, FALSE);
mode = 1;
}
else
{
llApplyRotationalImpulse(-llGetOmega()*.0525, FALSE);
mode=0;
}
}

}



You can see that I have reduced the magnitude of the counter force to scaled to .0525 of the radians rotational rate ... I also slowed the random forces so that the effects can be seen a little better.

I believe that the impulse physics are not scaled to the return of llGetOmega. Different scales?

It may be related to the object's mass... or as you say... just a bug.

Your code now seems to work, with scaled forces.


Ryder

Edit:
Indeed, it is related to the size (mass) of the cube. Enlarging the cube (and the impulse force to act on it) resulted in the scaled/llGetOmega Impulses failing.

The impulse needs to be scaled to the radians velocity returned by llGetOmega... but the relationship is not linear. One is a RATE, while the other seems to be close to a true unit force... less effective on larger objects. One would have hoped that the impulse would have been tied to the mass and rotational velocity... but apparently that is not the case.

From the wiki on the related function llApplyImpulse():
"Instantaneous impulse. llSetForce has continuous push. "Instantaneous" seems to mean a one second impulse, as an application of a force (in newtons) equal to the object's mass (in kg) for one second will accelerate it to a velocity of 1 (in meters per second), which appears to be what happens with this function."

I wish that the rotational version of this had clear math associated with it in the Wiki.
Ryder Spearmann
Early Adopter
Join date: 1 May 2006
Posts: 216
06-17-2009 00:11
From: Hewee Zetkin
Here you go:

http://jira.secondlife.com/browse/SVC-4399 ("llGetOmega() and/or llApplyRotationalImpulse() work incorrectly about half the time";)


Hrm, I doubt this somewhat... (intermittant functionality)

I delivered a fully stable cube to you in game, using those same functions... all I did was scale the force used.

rs
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-17-2009 09:45
It may well be that this bug was introduced when Havok 4 was added to SL. It may have a developed notion of moment of inertia, while Havok 1 did not. Certainly llApplyRotationalImpulse() (and llSetTorque() if the same applies there) is next to useless unless you know the amount by which to scale the input for a particular outcome.
Ryder Spearmann
Early Adopter
Join date: 1 May 2006
Posts: 216
06-17-2009 19:30
From: Hewee Zetkin
It may well be that this bug was introduced when Havok 4 was added to SL. It may have a developed notion of moment of inertia, while Havok 1 did not. Certainly llApplyRotationalImpulse() (and llSetTorque() if the same applies there) is next to useless unless you know the amount by which to scale the input for a particular outcome.



I have not be able to get the perfect math to scale the force to... but it is something along the lines of:

impulse = -llGetOmega: radians per second * (0.003 * mass^2 + 0.666 * mass - 11.3)

I have no idea what this might be pointing at...
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-17-2009 20:42
Well, if Havok 4 has more realistic moments of inertia, I think we're going to either need a function for retrieving it along a given axis, some kind of formula from the Lindens that we can use to calculate it manually given the object's geometry (i.e. know how all the prim parameters affect it; twist, path cuts, yuck!), or have them factor it into the llApplyRotationalImpulse(), llSetTorque(), etc. functions automatically (essentially giving us unitary moments of inertia or some such). And that might not work in a completely general way, but it can at least instantaneously (for impulses) and for local torques.
Ryder Spearmann
Early Adopter
Join date: 1 May 2006
Posts: 216
06-18-2009 00:26
From: Hewee Zetkin
Well, if Havok 4 has more realistic moments of inertia, I think we're going to either need a function for retrieving it along a given axis, some kind of formula from the Lindens that we can use to calculate it manually given the object's geometry (i.e. know how all the prim parameters affect it; twist, path cuts, yuck!), or have them factor it into the llApplyRotationalImpulse(), llSetTorque(), etc. functions automatically (essentially giving us unitary moments of inertia or some such). And that might not work in a completely general way, but it can at least instantaneously (for impulses) and for local torques.


it seems to me that code can be used to calculate it... based on a simple routine...

One could apply a force on one axis, and then have getomega report. one could then apply an impulse based on the rate of rotation, and recheck getomega. in a sort of washing machine, back and forth motion, one would increment the scaling of the rate, and apply to the impulse, until the impulse fully reverses the rate. This multiplier/2 should be the appropriate number for the prim system being used.

Is this more complex than is needed?

-rs-
Ryder Spearmann
Early Adopter
Join date: 1 May 2006
Posts: 216
06-18-2009 09:03
From: Hewee Zetkin
Well, if Havok 4 has more realistic moments of inertia, I think we're going to either need a function for retrieving it along a given axis, some kind of formula from the Lindens that we can use to calculate it manually given the object's geometry (i.e. know how all the prim parameters affect it; twist, path cuts, yuck!), or have them factor it into the llApplyRotationalImpulse(), llSetTorque(), etc. functions automatically (essentially giving us unitary moments of inertia or some such). And that might not work in a completely general way, but it can at least instantaneously (for impulses) and for local torques.



Also, while the challenge is perhaps daunting, for any given object, we can do some good things via experimentation.

I just sent you something very fun... using all of the troublesome functions we have been discussing.

Wear the HUD.
Rez the platform, sit on it. (a flat location is best)
Wear the hopper.

Press ENG IGN

Have fun! :)

And thanks.

-rs-
1 2