Jump to content

Fun with Speed = llVecMag(llGetVel());, or how do I carry floats to states?


Royal Stewart
 Share

You are about to reply to a thread that has been inactive for 2185 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I'm trying to create a universal vehicle front wheel script. Everything works except getting the float Rate to work inside of separate states? If I enter a numerical Rate setting the wheel spins, stops, turns, and then  restarts as needed. Unfortunately all this takes place at a constant speed which will not really work for what I'm attempting. The Settext tells me I get Rate change with movement. the (float) Rate, is just not being picked up by the states (left,right and center)?

vector r_left = <0.00000, 0.00000, 99.99999>; // Rotations in degrees relative to root prim
vector r_center =<-0.00000, -0.00247, 90.00001>;
vector r_right = <0.00000, 0.00000, 80.00001>;
float       Speed;
float       Rate;
float       NewRate;





rotation LocalRot(rotation localrot)
{
    rotation LocRot = localrot / ( (ZERO_ROTATION / llGetLocalRot()) * llGetRot());
    return LocRot;
}

left()
{
   llTargetOmega(<0,0,0>, 0.0, 0.0);
    llSetPrimitiveParams([PRIM_ROTATION, LocalRot(llEuler2Rot(r_left* DEG_TO_RAD))]);
    llTargetOmega(<1,0,0> * llGetLocalRot(),(Rate), 1.0);
}
center()
{
   llTargetOmega(<0,0,0>, 0.0, 0.0);
    llSetPrimitiveParams([PRIM_ROTATION, LocalRot(llEuler2Rot(r_center * DEG_TO_RAD))]);
    llTargetOmega(<1,0,0> * llGetLocalRot(),(Rate), 1.0);
}

right()
{
   llTargetOmega(<0,0,0>, 0.0, 0.0);
    llSetPrimitiveParams([PRIM_ROTATION, LocalRot(llEuler2Rot(r_right * DEG_TO_RAD))]);
    llTargetOmega(<1,0,0> * llGetLocalRot(),(Rate), 1.0);
}

default 
{
    state_entry()
    {
            llSetTimerEvent(0.1);
            center();
        }
       
    
    
   
    
    link_message(integer send, integer num, string msg, key id)
    {
        if ( msg == "center" )
        {
            center();
        }
        else if ( msg == "left" )
        {
            left();
        }
         else if ( msg == "right" )
        {
            right();
        }
         else if ( msg == "forward" )
        {
           llTargetOmega(<1,0,0> * llGetLocalRot(),Rate, 1.0);
        }
        
         else if ( msg == "stop" )
        {
            llTargetOmega(<0,0,0>, 0.0, 0.0);
        }
}
     timer()
    {
       
        Speed = llVecMag(llGetVel());
        
        if(Speed < 0.3)
        {
             NewRate = 0.0;
             
            }
        else if((Speed >= 0.4) && (Speed < 6.0)) 
        {
        NewRate = 3.0;
        
    }
        else if((Speed >= 6.0) && (Speed < 12.0)) NewRate = 9.0;
        else if((Speed >= 12.0) && (Speed < 18.0)) NewRate = 15.0;
        else if((Speed >= 18.0) && (Speed < 24.0)) NewRate = 21.0;
        else NewRate = 27.0;
        if(Rate != NewRate)
        {
            Rate = NewRate;
           llSetText((string)NewRate, <1, 1, 1>, 1.0);
            // llWhisper(0, "working"); 
    }
   }
 }

 

Link to comment
Share on other sites

as written there is no reason why Rate is not being  surfaced in the angle procedures. Put a debug Say(Rate) in each procedure to assure yourself of this

when you are assured, then suggest you remove the first call to llTargetOmega as there is not a lot to be gained by stopping the omega and then restarting it in a 2nd call

suggest also that you slow down the timer. 0.1 seconds is faster than the LSL timer event can execute safely under all server load conditions. Try 0.2 or slower. 

Link to comment
Share on other sites

Thank you for your reply. I'll drop in some Debug says, and see what comes up. And as far as the llTargetomega stops. When using llTargetOmega to drive wheels You have to stop the rotation first, then turn the prim and then restart the rotation. Otherwise the wheel will wobble.  And yes the timer is way to fast for this application. It was set to 1.0, and I wondered if the rate change was to slow to show up. So I cranked it up to see, and forget to back it off before I posted here. Just being a really basic scripter I was beginning to think there was just some format issue the editor wasn't picking up. That has bit me in the butt more than once in the past.

Thanks for your time

Link to comment
Share on other sites

I've seen that code before. It's not very good. This approach is better:

    timer()                                                 // frequently when running
    {
        //  Compute speed in forward direction. Can be positive or negative.
        vector vehdir = <1.0,0.0,0.0>*llGetRootRotation();  // global direction of vehicle
        float speed = vehdir*llGetVel();                    // speed in fwd direction
        //  Convert to wheel rotation rate in radians/sec
        float rate = speed / (WheelDiameter*PI);
        if (abs(rate) < 0.01) rate = 0.0;                   // close enough to stopped
        if (rate > MaxRate) rate = MaxRate;                 // bound
        if (rate < -MaxRate) rate = -MaxRate;
        //  Update only if significant change or stopping
        float err = abs(gLastRate - rate);                  // error
        if ((abs(gLastRate - rate) > MinAdjust*rate) || (gLastRate != 0.0 && rate == 0.0))
        {   llTargetOmega(axis, rate, 1.0);                 // spin wheel visually
            gLastRate = rate;                               // save for next time
        }
    }
}

This goes in each wheel. Steering the wheel is separate; this just rotates it. It works in local coordinates, so whatever you're doing for steering won't affect this. Rotation is client side.

This is an incomplete snippet. You need to define some global variables and constants for this to work. It shows the correct math. It's close to what we use in our vehicles.

vehdir is the direction the vehicle root is facing. That's a vector, obtained by multiplying <1,0,0> by the direction the root is facing. This assumes that +X is the forward direction of the vehicle.

speed is the vehicle speed in the direction the vehicle is pointed. This is a signed value; it will go negative in reverse, and the wheel will rotate backwards when you are backing up.

rate is the desired wheel rotation rate. This is simply π times the wheel diameter.

If rate is very small, set it to 0. If it is too big, clamp it, because you can't see the wheel rotate if it's too fast. 10.0 is a good MaxRate

Do an update only if the rate changes by more than MinAdjust, which is a fraction. 0.2 is good; that means a 20% change in wheel speed causes an update. Calling llTargetOmega with a new value sends a message to the viewer, and there's no need to overdo that. If the rate is going to 0, always update, because it looks silly to have the wheel creep.

Call this about 3 times a second. Turn off the timer when the vehicle is stopped. Parked vehicles should not have timers running; this wastes script time. So you need link messages to tell link objects when to turn off and turn on.

 

Link to comment
Share on other sites

@animats "This goes in each wheel." Why is that? Why can you not have each wheel handled by a single script?

1. Extra scripts are a major liability for sim crossings (and total script time in general), if you must have multiple there needs to be a way bigger reason than visual changes.

2. Wheels turn together, not individually. Multiple scripts means that when one lags, the other wheel still turns and it looks wonky to anyone looking, which might not be many anyway so the reason for multiple scripts is even smaller.

3. It's just easy to mirror the axis of rotation for both sides. 

Link to comment
Share on other sites

1 hour ago, Wulfie Reanimator said:

@animats "This goes in each wheel." Why is that? Why can you not have each wheel handled by a single script?

I do it that way mostly to avoid cluttering up the main script. I haven't seen a significant load for per-wheel scripts, and I've run tests in a sandbox. But then I'm doing motorcycles, with 2 wheels. If you're doing an 18-wheeler, central wheel control may be justified. I only do wheel update at about a third the rate the steering is updated. It's not important enough to  do at 10Hz.

If you want to see this in action, rez one of our demo bikes at http://maps.secondlife.com/secondlife/Vallone/223/8/36. Watch it from the side as you move the bike back and forth. That rotation happens client side, by the way; it's purely a visual effect. But it is a geometry rotation. If your wheel is a simple prim where texture rotation is sufficient, you can just do a texture animation, which is cheaper. These wheels are mesh objects.

Tried a few vehicles I have in inventory. The transit bus didn't rotate its wheels at all. The Shelby Cobra rotated them a bit too fast. The old superbike rotated them forwards even in reverse. Murasaki's dune buggy was almost perfect; he even simulates a suspension. Mine is almost as good as Murasaki's. If you want to see vehicles done with attention to detail, visit Murasaki's shop in Burns and try his demos.

Link to comment
Share on other sites

52 minutes ago, animats said:

I do it that way mostly to avoid cluttering up the main script. I haven't seen a significant load for per-wheel scripts, and I've run tests in a sandbox. But then I'm doing motorcycles, with 2 wheels. If you're doing an 18-wheeler, central wheel control may be justified.

I can understand not wanting to clutter your script (even if I don't agree that having to be an issue), but even then, putting a script in each wheel is not justified. It's just bad practice using duplicate code in multiple places. No matter if it's 1 or 18 wheels, a single script should be all you'll ever need.

Testing in a sandbox probably doesn't cover sim crossings either. 

Link to comment
Share on other sites

On 5/24/2018 at 9:43 AM, Royal Stewart said:

... llTargetOmega ... have to stop the rotation first ... Otherwise the wheel will wobble.

ah! ok

as the topic has opened up a bit then another way to calculate the rate is with a little bit of arithmetic. Example using the posted script parameters

timer()
{
  float m = llVecMag(llGetVel());
  
  if (m < 0.3)
     m = 0.0;
  else if (m >= 24.0)
     m = 27.0;
  else
     m = (float)((integer)m / 6 * 6 + 3);
   
  // logic method
  // m = (m * (float)(m <= 24.0)) + (24.0 * (float)(m > 24.0));
  // m = (float)((integer)(m >= 0.3) * ((integer)m / 6 * 6 + 3));
  
  NewRate = m;
}

 

Link to comment
Share on other sites

All these scripts are totally wrong .

 

You make a mess with linear velocity and angular velocity  who are two different things . radians per seconfs  ( set by lltargetOmegain in this script with the variable Rate) are not equal to meters per seconds ( get by llGetVel  into the variable newrate)

So Rate and Newrate can t be compared like this

Edited by Miranda Umino
Link to comment
Share on other sites

16 hours ago, Miranda Umino said:

... Rate and Newrate can t be compared like this

Rate and NewRate are comparative, as the same calculation is used for both.

this calculation is of the multiplicative problem class. Where the left operand is a variable and the right operand is a constant.

the OP design as posted is to use llVecMag(llGetVel()) as the left operand.

whether this choice is ideal for a universal wheel is a design consideration and not a coding issue per se. However if we are going to use this choice in our design then it remains, how might we alternatively write code that more efficiently conforms to the design parameters as given.

design - as animats has explored, design parameters for a universal wheel that can also be considered are things like: wheel diameter and direction amongst others. We could also raise things like gearboxes also in such a design discussion.  And as you raise, is llVecMag(llGetVel()) an ideal design choice as input to an operand ?

if we decide that it isn't, changing the input to the left operand doesn't change the problem class or how the class can be coded given that the right operand is a constant. Example:

timer()
{
  float m = llFrand(30.0);
  
  if (m < 0.3)
     m = 0.0;
  else if (m >= 24.0)
     m = 27.0;
  else
     m = (float)((integer)m / 6 * 6 + 3);
   
  // logic method
  // m = (m * (float)(m <= 24.0)) + (24.0 * (float)(m > 24.0));
  // m = (float)((integer)(m >= 0.3) * ((integer)m / 6 * 6 + 3));
  
  NewRate = m;
}

 

Link to comment
Share on other sites

3 hours ago, ellestones said:

whether this choice is ideal for a universal wheel is a design consideration and not a coding issue per se.

Oh , yes . It s a design issue .

 

Someone can t claim  "a universal vehicle front wheel script" if  this design of the script running the wheel is not consistant .

In addition llGetVel is not in the same frame than  llTargetOmega 

Running 10 meters in a flat land is not the same that running 10 meters in an hill land . There is the slope

 

 

About the script , it s curious to have chosen no delay for the forward message , and to have chosen  a delay for the "right" and "left" message .

It s because the scripter ( the OP)  has chosen , in the case of "right" and "left" message to  stop the wheel repositions the wheel , sleeps 0.2 seconds  because of llsetprimitiveparams , and after these 0.2 seconds and this stop of rotation , starts to rotate 

Will the wheel wobble if the OP has chosen llsetlinkprimitiveparamsfast ?

 

Edited by Miranda Umino
Link to comment
Share on other sites

39 minutes ago, Miranda Umino said:

Someone can t claim  "a universal vehicle front wheel script" if  this design of the script running the wheel is not consistant .

yes

we have to remember  though that OP is by their own posted example relatively new to scripting these kinda things. At this stage in their scripting experience by "universal" I take this to mean they are wanting a general purpose something they can drop into vehicles of their own making.

more basically something that will spin the wheels based on their current understanding of how wheels in general work.

what OP will come to understand by observation is that once they get their first vehicle working there is more to this than might be expected at first glance

like velocity in itself is not the only factor. As animats suggested diameter has a bearing. Like when a vehicle has  different size wheels, a drag racer for example. Little wheels on the front, big wheels on the rear. The little wheels spin faster than the big wheels.

as you mention terrain, elevation, etc also has a bearing on how wheels works.

other things are a vehicle which has wheels of the same diameter yet the wheels can spin at different rates. A motor bike doing a wheelie. Burning rubber. Vehicles doing donuts, drifting, etc

OP will come to learn all this in time as they gain more experience in building vehicles. My understanding is that OP at this moment just want something that goes to get started with. Which I would encourage them to do, get something going. And as their understanding grows then they will like everyone else apply this growth to further their work.

  • Like 1
Link to comment
Share on other sites

There is too the mess and the confusion between the Wheel and the Vehicle .

 

In a physic object , llGetVel and llGetOmega  returns values from the vehicle .

 

The angular velocity ( speed of the rotation ) if the vehicle is not the same that the rotation of the wheel ( neither the same axis , neither the same amplitude )

The velocity of the vehicle is not the same that the velocity of the wheel  ( neither the same axis , neither the same amplitude ) 

 

 

Probaby , when i read the original script , the OP wanted to compare the rotation of the wheel with the velocity of the vehicle

 

For physic objects ,  llGetVel and llGetOmega  returns values from the center of mass

There are some ways , sometimes in some buildings , where the builder adjusts the build with the center of mass .

But i don see this possible to rapproach a wheel with the center of mass of the vehicle


 

For non physic objets, it may return values from the root prim . But a root prim is unique . If the faked "pseudo-vehicle" has several "wheels" , there will be a problem

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2185 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...