Jump to content

Car moving on a turning road, following a waypoint (list)


Gertrude Babenco
 Share

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

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

Recommended Posts

Hello,

Please, excuse my bad english. Since nobody can answers me in my language, I'll try to request help here. I'm not a scripter, I can just try to adapt scripts I've found.

I would like to move a physical car. Using a script I have adapted, the cars moves correctly on a straight road. But I have issues when it has to turn.

My idea was:
1. First, the car detects the root position/rotation
2. Then it follows a waypoints calculated from the detected root position/rotation

On the picture, yellow prims represent these "virtual" points calculated from the  red root.

Here is my (stupid or foolish) code (which doesn't work anyway). I used 2 "lists", one for the successive positions, the other one for the successive rotations:

 

string   gsSensorTargetName            = "turning90";
float scandistance = 11.0;
float scanangle = 0.8; // Radians
integer direction = 0;
list p_data = ["B","C","D","E","F","G"];// list of successive positions
list r_data = ["rotB","rotC","rotD","rotE","rotF","rotG"];
list p_current= ["A","B","C","D","E","F"];
list r_current= ["rotA","rotB","rotC","rotD","rotE","rotF"];
integer A;

integer B;
integer C;
integer D;
integer E;
integer F;
integer G;
integer rotA;
integer rotB;
integer rotC;
integer rotD;
integer rotE;
integer rotF;
integer rotG;

vector waypoint;
rotation set_rot;
integer tau = 1;


Go()
{ llSensor(gsSensorTargetName, "", ACTIVE | PASSIVE, scandistance, scanangle);}




Action(vector waypoint, rotation set_rot)
{

vector A= llDetectedPos(0);
rotation rotA= llDetectedRot(0);
B= A+<0.1363,0.8127,0.0>;
C= B+<0.3611,0.892,0.0>;
D= C+<0.6719,0.8259,0.0>;
E= D+<0.8365,0.6200,0.0>;
F= E+<0.9889,0.3995,0.0>;
G= F+<0.9527,0.2249,0.0>;
rotB= rotA+<0.0,0.0,-12.0>;
rotC=rotB+<0.0,0.0,-14.0>;
rotD= rotC+<0.0,0.0,-30.0>;
rotE=rotD+<0.0,0.0,-19.0>;
rotF=rotE+<0.0,0.0,-12.0>;
rotG=rotF+<0.0,0.0,-13.0>;
integer listLength = llGetListLength(p_data);
waypoint=llList2Vector(p_data,p_current); set_rot=llList2Rot(r_data,r_current); ///target = next point on list
llMoveToTarget(waypoint, tau);///physical movement
llLookAt(waypoint,1,1); ///face direction of travel
llRotLookAt(set_rot,1,1); ///face preset rotation


}



default
{
state_entry()
{
llSay(0, "Hello, Avatar!");
}

touch_start(integer total_number)
{
Go();
}
sensor (integer total_number)
{ Action();
}}

Could anyone correct my script in order to obtain something? Thank you very much.

Lovre from Gertrude

 


 

Link to comment
Share on other sites

You are trying to make your script too complicated.  There are two ways to make a path follower.  One method is to store the positions of each waypoint in a list (perhaps hard-coded into the script, or perhaps read from a notecard), and then tell your car to go from one waypoint to the next.  The other method is to put a named prim at each waypoint and tell the car to use a sensor to find each prim and move to it. You don't need to combine both methods.

As an example, here is a very simple path following script that uses the second method.  All you need to do is put four prims, named "Target1," "Target2", "Target3", and "Target4" on the ground, drop this script into another prim that will be your car, and click on it.  The Car should move from one prim to the next easily.  Notice that I am only using llLookAt to aim the front of the car toward each waypoint prim.  The variable named "count" looks for the next target name in the list each time your car reaches a waypoint and triggers the at_target event.

 

integer target_id;
list targets = ["Target1","Target2","Target3","Target4"];
integer count;
default
{
    state_entry()
    {
        llSetStatus(STATUS_PHYSICS,FALSE);
        llSetRot(ZERO_ROTATION);
        count = 0;
    }

    touch_start(integer total_number)
    {
        llSetStatus(STATUS_PHYSICS,TRUE);
        llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y, FALSE);
        llSetBuoyancy(1.0);
        llSensor(llList2String(targets,count),"",ACTIVE | PASSIVE,20.0,PI);
    }
    
    sensor(integer num)
    {
        if(count == 4)
        {
            llStopMoveToTarget();
            llResetScript();
        }
        llLookAt(llDetectedPos(0),1.0,0.4);
        llMoveToTarget(llDetectedPos(0), 4.0);
        target_id = llTarget(llDetectedPos(0), 1.0);
    }
    
    at_target(integer tnum, vector targetpos, vector ourpos)
    {
        if (tnum == target_id)
        {
            ++count;
            llTargetRemove(target_id);
            llSensor(llList2String(targets,count),"",ACTIVE | PASSIVE,20.0,PI);
        }
    }
}

Edit: I modified the original posted script to reset it at the final waypoint and disable physics until touched. Might as well save some stress on the sim's physics engine when it's not being used. :smileywink:

 

Link to comment
Share on other sites

Hello Rolig and Void,

Thank you very much for your help.

I've just tested your script, Rolig, and it works OK.

Why would I need a more complex system, using the both methods you described in your first message? Because, since the pieces of the road (it could be train tracks) would have the same size, it would be less fastidious (you don't have to fit correctly several prims-targets) and would coast less prims.

I mean Target2, 3, 4, etc. would be "virtual" and calculated from the position of the position and rotation of the Target1, set as the (invisible) root of the "turning piece of road".

 

But I don't know how to code it in my "list".

Thanks again.

 

 

Link to comment
Share on other sites

 


Gertrude Babenco wrote:

Why would I need a more complex system, using the both methods you described in your first message? Because, since the pieces of the road (it could be train tracks) would have the same size, it would be less fastidious (you don't have to fit correctly several prims-targets) and would coast less prims.

I mean Target2, 3, 4, etc. would be "virtual" and calculated from the position of the position and rotation of the Target1, set as the (invisible) root of the "turning piece of road".

 

That's correct, Gertrude. You do not need to use both methods.  That was my point. My script illustrates one method, but you could just as easily write a script that uses waypoints that are coded internally (or on a notecard).  If you do that, you do not need to use a sensor.  After all, the script already knows where the waypoints are, if they are in a list. 

If you want to use that other method, then you need to put the positions (vectors) of the waypoints into a global list instead of the names of the waypoints.  You do not need to calculate anything from the first target  -- just enter the positions in the list as vectors. Then, instead of triggering a sensor, you simply use llMoveToTarget( (vector)llList2String(waypoints,count), 5.0) at each step. To keep the car pointed toward the next waypoint, use llRotLookAt(llRotBetween(<1.0,0.0,0.0,>, (vector)llList2String(waypoints,count), 1.0,0.4) . (I am fairly confident about that last statement, but I cannot get in world to test it right now. :smileywink: )  The rest of my example script is essentially the same.

Link to comment
Share on other sites

Ah, OK.. I was close.  Yes, I can see that it would have to be llVecNorm(next_pos-llGetPos()) .  After all, you want the destination vector to be figured relative to your current position, not relative to regional <0.0,0.0,0.0>.  It's a PRIM_POS_LOCAL, if that existed.  Thanks, Void.

Link to comment
Share on other sites

"If you want to use that other method, then you need to put the positions (vectors) of the waypoints into a global list instead of the names of the waypoints.  You do not need to calculate anything from the first target  -- just enter the positions in the list as vectors."

 

Sure, but if you need to change your waypoint or set it on another land, you have to change all the data in your script. If your car movement is determinated by a segment of the road, it would be easier and faster. I don't understand why it would be so complex to code it (for someone who can manipulate scripts like you, not for me, lol), using points calculated relatively to a beginning point/root: maybe because positions will depend on world axis?

I guess this code would be useful for a train system too.

Anyway, thank you so much for your several answers: I really really appreciate the time and the attention you give to me :)

Link to comment
Share on other sites

Oh, I think I see why you want to do it that way.  If you move your car to another sim, you want it to follow exactly the same path that it would have followed on the old sim, relative to its starting point.  Yes, you can certainly do that.  In fact, that's only a minor variation of what I suggested in my last post to you.  Remember that I was suggesting that you create a list that contains all of the target locations.  That list could instead be a list of offset vectors.  In that case, you begin the path with

// First position

llSetRot(ZERO_VECTOR);

vector new_target = llGetPos() + (vector)llList2String(offsets,0) ;

llMoveToTarget(new_target, 5.0);

llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4);

// Second position

new_target += llGetPos() + (vector)llList2String(offsets,1); //This replaces the first target with a new one

llMoveToTarget(new_target, 5.0);

llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4);

// Third position

new_target += llGetPos() + (vector)llList2String(offsets,2); //This replaces it again

llMoveToTarget(new_target, 5.0);

llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4);

and so forth........  Each position is calculated from the last one, plus an offset.

Link to comment
Share on other sites

Well, I tried to obtain something during the all day and, feeling to be "as dumb as I look" ^^, I didn't dare communicate my mistaken script...

Well I have an issue with llRotLookAt (error: function call mismatches...) and maybe the script I made is full of others errors. Here it is:

 

integer target_id;string   SensorTargetName = "turning90";float    scandistance                  = 11.0;float    scanangle                     = 0.8; // Radianslist offsets = [<0.0,0.0,0.0>,<0.1363,0.8127,0.0>,<0.3611,0.8920,0.0>,<0.6719,0.8259,0.0>, <0.8365,0.620,0.0>,<0.9889,0.3995,0.0>, <0.9527,0.2249,0.0> ];integer count;move() {  //llSetRot(ZERO_VECTOR);vector new_target = llGetPos() + (vector)llList2String(offsets,0) ;llMoveToTarget(new_target, 5.0);llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4));// Second positionnew_target += llGetPos() + (vector)llList2String(offsets,1); //This replaces the first target with a new onellMoveToTarget(new_target, 5.0);llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4));// Third positionnew_target += llGetPos() + (vector)llList2String(offsets,2); //This replaces it againllMoveToTarget(new_target, 5.0);llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4)); // 4th positionnew_target += llGetPos() + (vector)llList2String(offsets,3); //This replaces it againllMoveToTarget(new_target, 5.0); llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4));  // 5th positionnew_target += llGetPos() + (vector)llList2String(offsets,4); //This replaces it againllMoveToTarget(new_target, 5.0);  llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4));// 6th positionnew_target += llGetPos() + (vector)llList2String(offsets,5); //This replaces it againllMoveToTarget(new_target, 5.0);llRotLookAt(llRotBetween(<1.0,0.0,0.0>, llVecNorm(new_target - llGetPos()), 1.0, 0.4));}default{    state_entry()    {        llSetStatus(STATUS_PHYSICS,FALSE);        llSetRot(ZERO_ROTATION);        count = 0;    }    touch_start(integer total_number)    {        llSetStatus(STATUS_PHYSICS,TRUE);             llSetBuoyancy(1.0);        llSensor(SensorTargetName,"",ACTIVE | PASSIVE,20.0,PI);    }        sensor(integer num)    {     move();        // First position}}

 

If I could resolve the error-call-mismatches, should I indicate the Z-rotations (example: 9°) in the

llRotBetween(<1.0,0.0,9.0>

for each "postitions"?

Well, I'm very embarrassed to ask your help again. Conscious of the time you've already spent for me, well, thanks a lot anyway.

 

Link to comment
Share on other sites

Sorry.  I was less than pefectly clear.  In order to move from one waypoint to the next, you need some way to tell that the car has arrived.  That's what the at_target event does, and that's where you need to update the variable new_target , change the car's rotation, and issue the command to move again.  When I wrote that set of schematic steps in my last post, I meant you to put them into an at_target event.

I have put those actions into a user-defined function (move()), which gets called at the start of each leg on the journey, including the very first one.  Notice the logic...... The first thing that happens in the move() function is that new_target updates, calling a new offset from the offsets list.  Which value?  The one whose index in the list is equal to the current value of count.  Once new_target is calculated, the rest is straightforward and the car moves to that new waypoint.  When it arrives, the at_target event is triggered, count increases by +1, and move() is called again. The loop repeats itself over and over until count is >= the number of elements in the offsets list.  Then everything stops and the script resets. 

The only caution is that I have not been able to get in world to test this script.  It compiles, so there should be no LSL errors, but I can't guarantee that it will work perfectly.  (I'm keeping my fingers crossed.)

 

integer target_id;string   SensorTargetName = "turning90";float    scandistance                  = 11.0;float    scanangle                     = 0.8; // Radianslist offsets = ["<0.0,0.0,0.0>","<0.1363,0.8127,0.0>","<0.3611,0.8920,0.0>","<0.6719,0.8259,0.0>", "<0.8365,0.620,0.0>","<0.9889,0.3995,0.0>", "<0.9527,0.2249,0.0>" ];integer count;move(){    vector new_target = llGetPos() + (vector)llList2String(offsets,count);    llRotLookAt(llRotBetween(<1.0,0.0,0.0>,llVecNorm(new_target-llGetPos())),1.0,0.4);    llMoveToTarget(new_target, 4.0);    target_id = llTarget(new_target, 1.0);}default{    state_entry()    {        llSetStatus(STATUS_PHYSICS,FALSE);        llSetRot(ZERO_ROTATION);        count = 0;    }    touch_start(integer total_number)    {        llSetStatus(STATUS_PHYSICS,TRUE);        llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y, FALSE);        llSetBuoyancy(1.0);        llSensor(SensorTargetName,"",ACTIVE | PASSIVE,scandistance,scanangle);    }        sensor(integer num)    {        move();    }        at_target(integer tnum, vector targetpos, vector ourpos)    {        if (tnum == target_id)        {            ++count;            llTargetRemove(target_id);            if (count >= llGetListLength(offsets))            {                llStopMoveToTarget();                llResetScript();            }            else            {                move();            }        }    }}

 BTW, the reason you had an execution error was that your offsets list was full of vectors, but we were telling the script to look for a string variable. ( I never trust llList2Vector.)  Just be sure that you put " " marks around the elements in offsets and it should work fine.

As an afterthought .... The script really should have a no_sensor event that does nothing more than say an error message and reset the script if the sensor can't find its starting point. I didn't put that in, but it should be there to keep the car from stalling.  Also, I'd suggest using a scan angle of PI instead of 0.8 radians.  You're more likely to find the target that way.

ETA:  I don't know how I missed looking carefully at your offset list.  The very first element is <0.0,0.0,0.0>, which ,means that the offset for the first leg of the journey will be ZERO.  The car will not move.  You should start instead with the second element, <0.1363, 0.8127,0.0>.  (Those are very small offsets, BTW.  :smileytongue:)

 

  • Like 1
Link to comment
Share on other sites

Well, changing the scan angle, as you suggested me, the car moves. Strangely, but it moves.

Strangely because: 1°) I need to touch the car for moving to each point.

2°) It follows a line which is not the determinated points (I guess I made a mistake calculating the X and Y virtual positions).

3°) The car turns 90° on itself before moving and at the end of the movement.

 

I looked at your SL profile this afternoon and saw that you sometimes accept to work on scripts. Maybe, I could wait for your come back in SL (when you'll be able to "babysit" your avatar again^^) and show you the situation. Obviously, I would pay you: I feel ashamed to have made you spent so much  time for me.

Why a sensor? because the car would detect the nature (= name) of the piece of road: if it detects a straight line, it would activate the straight scenario and if it detects a turning piece, it would turn.

 

Thank you again.

 

 

 

Link to comment
Share on other sites

It turns 90 degrees at the start and end because of the llSetRot(ZERO_ROTATION) function in the state_entry event.  That's just there to give it a default rotation to start with.  If you don't want it, remove it.

It should only need to be touched once, at the start.  The problem may be that your offset vectors ar VERY small (less than a meter of movement at each step).  I'll be able to test it in world soon and will try to contact you later.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 4915 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...