[Wiki] Créer son robot

Répondre
Partager Rechercher
Ce message est en mode wiki. Tous les comptes de plus de 30 jours avec plus de 30 messages peuvent le modifier.
Ce wiki s'adresse à tous ceux qui ont le désir de comprendre quelques fondamentaux avant de se lancer ou pas dans l'aventure passionnante des robots.

Introduction


Pour déplacer un simple objet dans SL il existe plusieurs solutions de scripts ou d'instructions LSL, voici les principales:

Objet NON physique (masse = 0; gravité = 0):

llSetPos(vector_pos);
llSetPrimitiveParams( [POSITION,vector_position] );

Objet physique:

. LlMoveToTarget(vector_position,x,y)
. LlApplyImpulse
. LlPushObject

et utilisation des functions "Linden Vehicle"
llSetVehicleType
llSetVehicleFloatParam
llSetVehicleVectorParam
llSetVehicleRotationParam
llSetVehicleFlags etc...

Bouger un objet non physique est somme toute assez facile et pourrait être:

llSetPos( llGetPos() + < 0.0, 0.0, 2.0 >); // monter de 2 mètres

Quelques expériences...surprenantes!


Si vous n'avez jamais jouer réellement avec les prims physiques, ou que votre science n'est QUE théorique je vous conseille vivement de lire attentivement la suite quelque soit votre niveau en script...


Objet non physique



Réalisons un petit script dans une simple box.

Code PHP:

default
{
    
touch_start(integer total_number)
    {
         
float x 0.5;
         
float y 0.5;
         
float z 1.0;
         
llSetPosllGetPos() + < x,y,>);
    }

quand on clique dessus il se déplace de 0.5 m en x et y et de 1m en z.

Modifions le script pour qu'il enchaine 2 déplacements:
Code PHP:

default
{
    
touch_start(integer total_number)
    {
        
llSetStatus(STATUS_PHYSICSFALSE);
        
float x 1.0;
        
float y 1.0;
        
float z 1.0;
        
llSetPosllGetPos() + < x,y,>);
        
llSleep (3);
        
llSetPosllGetPos() + < x,y,>);
    }

Pas de problème particulier...

Objet physique



Maintenant rendons physique la box entre les 2 déplacements:

Code PHP:

default
{
    
touch_start(integer total_number)
    {
        
float x 1.0;
        
float y 1.0;
        
float z 1.0;
        
llSetPosllGetPos() + < x,y,>);
        
llSleep (3);
        
llSetStatus(STATUS_PHYSICSTRUE); // Mode physical actif
        
llSetPosllGetPos() + < x,y,>);
    }

La boite se déplace ... puis chute lourdement au bout de 3s. et refuse de se déplacer désormais ( en re-cliquant).

Citation :
Règle 1:
Les déplacements par llSetPos() (et llSetPrimitiveParams( [POSITION,vector_position] )) ne fonctionnent pas avec un objet physique.
Rendons un objet physique et déplaçons le de 3 mètres en hauteur...

Code PHP:

default
{
    
state_entry()
    {
        
llSetStatus(STATUS_PHYSICSTRUE); // Mode physical on   
    
}
    
touch_start(integer total_number)
    {
        
float x 0.0;
        
float y 0.0;
        
float z 3.0;

        
llMoveToTargetllGetPos() + < x,y,>,.3);
    }

La box s'élève de 3 mètres reste dans cette position.

Normal ou bof me direz vous... Erreur!! essayer de lancer un paquet de farine au dessus de votre tête pas sûr que vous le contempliez en lévitation!!!

Maintenant avec l'edit menu ramenez le au sol...pour recommencer cette expérience.

Un problème ?? Que constatez vous?

Oui la box se repositionne à sa place initiale!

Surprenant... et important à connaitre.


Maintenant ajoutons l'instruction llStopMoveToTarget();

Code PHP:

default
{
    
state_entry()
    {
        
llSetStatus(STATUS_PHYSICSTRUE); // Mode physical on   
    
}
    
touch_start(integer total_number)
    {
        
float x 0.0;
        
float y 0.0;
        
float z 3.0;

        
llMoveToTargetllGetPos() + < x,y,>,.3);
        
llStopMoveToTarget();
    }

La boite s'élève de 3m et ... retombe lourdement, comme le paquet de farine si vous avez réalisé le test

Définissons quelques règles

Citation :

Règle 2:
llMoveToTarget(Position ) ne fonctionne qu'avec un objet physique.

Règle 3:
llMoveToTarget( Position ) maintient l'objet dans cette position.[/U]

Règle 4:
llStopMoveToTarget( Position ) arrète le mouvement créé par llMoveToTarget( Position ).
Maintenant nous allons bouger la box de 3m en hauteur et... la ramener dans sa position initiale.

Le petit script qui va bien...

Code PHP:

vector Start_Pos;
default
{
    
state_entry()
    {
        
Start_Pos llGetPos();  
        
llSetStatus(STATUS_PHYSICSTRUE); // Mode physical on   
    
}
    
touch_start(integer total_number)
    {
        
float x 0.0;
        
float y 0.0;
        
float z 5.0;

        
llMoveToTargetllGetPos() + < x,y,>,.4);
        
llStopMoveToTarget();
        
llSleep(1);        
        
llMoveToTargetStart_Pos,.4);
        
llStopMoveToTarget();        
    }

La boite s'élève de 5m et se repositionne à son origine...

Normal? bof?....

Encore une fois soyez humble quand vous touchez au monde la physique

Démonstration par l'exemple...modifions le script pour qu'il reste 5s en hauteur avant de revenir...facile il y a juste un timer à modifier...

Code PHP:

vector Start_Pos;
default
{
    
state_entry()
    {
        
Start_Pos llGetPos();  
        
llSetStatus(STATUS_PHYSICSTRUE); // Mode physical on   
    
}
    
touch_start(integer total_number)
    {
        
float x 0.0;
        
float y 0.0;
        
float z 5.0;

        
llMoveToTargetllGetPos() + < x,y,>,.5);
        
llStopMoveToTarget();
        
llSleep(5);        
        
llMoveToTargetStart_Pos,.5);
        
llStopMoveToTarget();        
    }

Constatons la box s'élève à 5m et.... tombe immédiatement!!

Pourquoi??

Juste parce que la règle 4 s'est appliquée et a annulée la règle 3!

Corrigeons le script...


Code PHP:

vector Start_Pos;
default
{
    
state_entry()
    {
        
Start_Pos llGetPos();  
        
llSetStatus(STATUS_PHYSICSTRUE); // Mode physical on   
    
}
    
touch_start(integer total_number)
    {
        
float x 0.0;
        
float y 0.0;
        
float z 5.0;

        
llMoveToTargetllGetPos() + < x,y,>,.5);
        
llSleep(5);        
        
llMoveToTargetStart_Pos,.5);
        
llStopMoveToTarget();        
    }

La cette fois la box reste 5s à la hauteur de 5m ...
Normal ? bof?

Plus cette fois j'espère, rester humble!, car il y a ENCORE un erreur...

Je vous laisse la trouver

Refaite cette expérience et percuter votre boite avec vos pieds. Que se passe t'il?

votre boite se retrouve sans dessus dessous la pauvre à plusieurs mètres de son origine! Imaginez la tête de votre robot...

Pourquoi? toujours les règles 3 et 4 ! On a commit 2 erreurs en faisant le llStopMoveToTarget():
la première est d'avoir arrêté le mouvement de retour AVANT que la boite n'ait eu le temps de revenir!!
la seconde de ne pas "figer" la position de retour.

Corrigeons le script:

Code PHP:

vector Start_Pos;
default
{
    
state_entry()
    {
        
Start_Pos llGetPos();  
        
llSetStatus(STATUS_PHYSICSTRUE); // Mode physical on   
    
}
    
touch_start(integer total_number)
    {
        
float x 0.0;
        
float y 0.0;
        
float z 5.0;

        
llMoveToTargetllGetPos() + < x,y,>,.5);
        
llSleep(5);        
        
llMoveToTargetStart_Pos,.5);
    }

Surprise!! le retour se fait maintenant en douceur... et avec vos petits pieds vous de pouvez plus déplacer la position de la box. J'ai bien dis position car si vous pouvez bouger sa rotation.

L'introduction que j'aurais pu faire concernant les prims physiques aurait pu être celle ci:

Vous savez scrypté?, vous disposez de bonnes connaissances SL? très bien....oubliez tout!


Maintenant une autre expérience nous allons nous déplacer de x = 1m y=2m et z= 3m (hauteur) et revenir à la position initiale.

Nous colorions en bleu la face supérieure de la box


Le script:

Code PHP:

vector      Start_Pos;

default
{
    
state_entry()
    {
        
Start_Pos llGetPos();  
        
llSetStatus(STATUS_PHYSICSFALSE); // Mode physical off   
        
llSetRot(ZERO_ROTATION);
        
llSetStatus(STATUS_PHYSICSTRUE); 

    }
    
touch_start(integer total_number)
    {
        
float x 1.0;
        
float y 2.0;
        
float z 5.0;
        
llMoveToTargetllGetPos() + < x,y,>,.1);
        
llSleep(1);
        
llMoveToTargetStart_Pos,.1);
    }

Cliquons ...

La prim part en vrille à chaque clic!

Les scripteurs vont de suite réagir ... en disant: normal! on doit appliquer la rotation sur la position! pfff élémentaire!!

On connait comment marche le llSetPos patati patata...

Vérifions...

Code PHP:

vector      Start_Pos;
rotation    Start_Rot;

default
{
    
state_entry()
    {
        
Start_Pos llGetPos();  
        
llSetStatus(STATUS_PHYSICSFALSE); // Mode physical off   
        
Start_Rot=ZERO_ROTATION;
        
llSetRot(Start_Rot);
        
llSetStatus(STATUS_PHYSICSTRUE); 

    }
    
touch_start(integer total_number)
    {
        
float x 1.0;
        
float y 2.0;
        
float z 5.0;
        
llMoveToTargetStart_Pos + < x,y,>*Start_Rot,.1);
        
llSleep(2);
        
llMoveToTargetStart_Pos,.1);
    }

Même punition!

Nous pouvons édifier une règle et TOUJOURS s'en souvenir...

Citation :
Règle 5:
Quand on déplace un prim normale on change uniquement sa position, quand on déplace une prim physique on lui applique un mouvement.
Pour résoudre le problème définitivement utilisons une instruction spécifique

Code PHP:

vector      Start_Pos;
rotation    Start_Rot;

default
{
    
state_entry()
    {
        
Start_Pos llGetPos();  
        
llSetStatus(STATUS_PHYSICSFALSE); // Mode physical off   
        
Start_Rot=ZERO_ROTATION;
        
llSetRot(Start_Rot);
        
llSetStatus(STATUS_PHYSICSTRUE); 

    }
    
touch_start(integer total_number)
    {
        
float x 1.0;
        
float y 2.0;
        
float z 5.0;
        
llMoveToTargetStart_Pos + < x,y,>*Start_Rot,.1);
        
llRotLookAt(ZERO_ROTATION,0.4,0.6);
        
llSleep(2);
        
llMoveToTargetStart_Pos,.1);
    }

Voila nous imposons une rotation physique à l'objet...

Il existe 2 autres instructions
• llLookAt
• llStopLookAt
je vous laisse lire le wiki, votre ami.


Édifions la dernière règle.


Citation :
Règle 6:
Les rotations des prims physiques lors de mouvements se gèrent par les instructions: llRotLookAt et llLookAt
Voilà vous connaissez les bases des mouvements physiques.

Mon premier robot follower


Follower veut dire suiveur.

Le code suivant malgé sa simplicité sera votre base de travail dans...99% des cas!

Créez une box, coloriez la face du dessus en bleu et insérez le script ci dessous.

Script:

Code PHP:

key         KeyOwner;
list          
Pos_Rot;
vector     Pos;
rotation   Rot;

Init()
{
    
KeyOwner llGetOwner();
    
llSetStatus STATUS_PHYSICS,TRUE);
    
llSetTimerEvent(1);
}

FollowMe()
{
    
Pos_Rot     llGetObjectDetails(KeyOwner, [ OBJECT_POSOBJECT_ROT]); 
    
    
Pos llList2Vector (Pos_Rot,0);    
    
Rot llList2Rot (Pos_Rot,1);       
    
    
Pos Pos + <1.01.00.4>*Rot
           
    
llMoveToTarget(Pos0.4);              
    
    
llLookAtPos - <1.01.0, -0.4>*Rot 0.40.4); 
}

default
{
    
on_rezinteger start_param)
    {
        
Init();
    }
    
state_entry()
    {
        
Init();
    }
    
    
timer()
    {
        
FollowMe();   
    }


Explications:

Le robot va donc vous suivre et se positionner à votre droite et vous regarder.

Principe:

On met la prim en mode physique et on lance un timer de 1s (cadenceur) qui lance la fonction FollowMe.

Code PHP:

FollowMe()
{
    
Pos_Rot     llGetObjectDetails(KeyOwner, [ OBJECT_POSOBJECT_ROT]); 
    
    
Pos llList2Vector (Pos_Rot,0);    
    
Rot llList2Rot (Pos_Rot,1);       
    
    
Pos Pos + <1.01.00.4>*Rot
           
    
llMoveToTarget(Pos0.4);              
    
    
llLookAtPos - <1.01.0, -0.4>*Rot 0.40.4); 

La fonction llGetObjectDetails nous permet de récupérer la position et la rotation de l'owner du robot ( uniquement dans la région) sous forme de liste.

La position du robot sera décalé de celle du owner de x +1.0, y+ 1.0, z +0.4 en tenant compte de sa rotation

Le facing sera effectuée par la fonction llLookAt( Pos - <1.0, 1.0, -0.4>*Rot , 0.4, 0.4). On regarde le owner au dessus de la moitié de la hauteur + .4m.

Les impératifs à prendre en compte


Le principal problème à propos des robots est de ne pas les perdre! Passons en revue quelques cas.

Le Owner quitte le jeu ou la région


La façon la plus sûre et la plus rapide de savoir si un agent est présent sur une région est la fonction llGetAgentSize qui retournera un vecteur à zéro si l'agent n'est pas présent sur région.

Dans le script du follower cela pourrait être implanté de la façon suivante:

Code PHP:

    if (size == ZERO_VECTOR // Owner n'est plus présent
    
{
        
llSetTimerEvent(30); // on regarde toutes les 30 secondes
        
return;      
    }
    else
        
llSetTimerEvent(1); // si le owner est  de nouveau présent on le suit. 

Le robot ne peut pas entrer sur une parcelle


Certainement un des premiers gros problèmes concernant le déplacement des robots.

Que je passe t'il quand un objet physique rencontre une frontière interdite?

Il reste coincé, les instructions llMoveToTarget imposées par le status physique de l'objet restent stériles quelques soient la destination choisie...Le piège s'est refermé.

La première étape est de détecter que le robot est "coincé". Pour ce faire on peut définir deux critères interressants

La distance entre l'agent et le robot
La vélocité de l'objet.

et établir une équation qui devrait nous alerter.

Si la distance > 1m et que le robot reste immobile on peut dire qu'il est coincé.

Scriptons la sous forme de fonction:

Code PHP:

integer Check_Trap() // Test si le robot peut bouger...
{
    return (
llVecMag(Pos llGetPos()) > && llVecMag(llGetVel()) == 0.0 );

Retournera TRUE si le robot est coincé.

Pour sortir le robot de cette mauvaise posture il faut réaliser 2 choses:

Repasser l'objet en mode non physique

Et utiliser le llSetPrimitiveParams [POSITION]qui est la seule instruction capable de déplacer l'objet.

Cette fonction a une limite bien connue, celle de ne pas pouvoir déplacer un objet de plus de 10m.

Ce qui dans notre cas est plus que problématique. En effet le owner peut sortir du terrain à un endroit et revenir à un autre distant de plus de 10m du robot. Heureusement une faille dans la fonction a permit de mettre au point la fameuse warPos capable de déplacer un objet à plus de 1000m.


http://wiki.secondlife.com/wiki/WarpPos



Le code pourrait ressembler à cela:

Code PHP:

     if (Check_Trap()) 
    { 
// le robot est piégé
        
llSetTimerEventDelay_Trapped ); //diminuer le delai
        
llSetStatus STATUS_PHYSICS,FALSE); // pour le  warpPos 
        
if (WarpPosM(Pos))
            
llSetTimerEventDelay_Follow);  // si pas/plus coincé ...          
        
llSetStatus STATUS_PHYSICS,TRUE); 
    } 

Parcel no_script


Peut être contourné facilement par l'utilisation de llRequestPermissions.

http://wiki.secondlife.com/wiki/LlRequestPermissions

If a script has taken controls, it and other scripts in the same prim will not be stopped if the Agent enters a No-Script Area. This is done to keep vehicle control alive and AOs functional. This is an intentional feature.

le script devra donc contenir :

Code PHP:

            llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); 





Le script final

Code PHP:

// ____ Robot Engine v1.0 _______
//
// Ecrit par Sebastien Pfalz
// pour JOL. Octobre 2009
//
// Libre de droits 
// en conservant cette entête ;-)
// ______________________________

key         KeyOwner;
list        
Pos_Rot;
vector      Pos;
rotation    Rot;
float       Delay_Follow .5;
float       Delay_Owner_Off 15;
float       Delay_Trapped 3;

Init()
{
    
KeyOwner llGetOwner();
    
llSetStatus STATUS_PHYSICS,TRUE);
    
llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); // Pour utilisation dans zone no_script
    
llSetTimerEvent(Delay_Follow);
}

integer Check_Trap() // Test si le robot peut bouger...
{
    return (
llVecMag(Pos llGetPos()) > && llVecMag(llGetVel()) == 0.0 );
}

integer WarpPosM(vector target)
// grand deplacement    
    
integer jumps = (integer) (llVecDist(targetllGetPos()) / 10.0) + 1;
    if (
jumps 411)
        
jumps 411;
    list 
rules =[PRIM_POSITIONtarget];    //The start for the rules list
    
integer count 1;
    while ((
count count << 1) < jumps)
        
rules += rules;
    
llSetPrimitiveParams(rules llList2List(rules, (count jumps) << 1count));
    
    if ( 
target == llGetPos() )
        return  
TRUE;
    else
        return  
FALSE;
}


FollowMe()
{
    
vector size llGetAgentSize(KeyOwner); // taille de l'Owner
    
    
if (size == ZERO_VECTOR // l'Owner n'est pas/plus dans la région
    
{
        
llSetTimerEvent(Delay_Owner_Off); // scanné raisonablement 
        
return;      
    }
    else
        
llSetTimerEvent(Delay_Follow);

// On récupère la position et la rotation de l'owner                  
    
Pos_Rot llGetObjectDetails(KeyOwner, [ OBJECT_POSOBJECT_ROT]); 
    
Pos llList2Vector (Pos_Rot,0);    
    
Rot llList2Rot (Pos_Rot,1);       

// on lui ajouter un offset de décalage  pour ne pas pousser le owner!       
    
Pos Pos + <1.01.00.4 > * Rot

// on suit le owner et on le regarde                 
    
llMoveToTarget(Pos0.4);              
    
llLookAtPos - <1.01.0, -0.4 > * Rot0.50.2);

// on controle si le robot bouge    
    
if (Check_Trap()) 
    { 
// le robot est piégé
        
llSetTimerEventDelay_Trapped ); //diminuer le delai
        
llSetStatus STATUS_PHYSICS,FALSE); // pour le  warpPos 
        
if (WarpPosM(Pos))
            
llSetTimerEventDelay_Follow);  // si pas/plus coincé ...          
        
llSetStatus STATUS_PHYSICS,TRUE); 
    }
}

default
{
    
on_rezinteger start_param)
    {
        
Init();
    }
    
state_entry()
    {
        
Init();
    }
// Pour permettre de bypassé les zones no script
    
run_time_permissions(integer perms)
    { 
        if (
perms PERMISSION_TAKE_CONTROLS
            
llTakeControls(CONTROL_FWD,TRUE,TRUE); 
        else
        { 
// on redemande en expliquant
            
llOwnerSay "Vous devez accepter  <Act on your control inputs>', autrement le robot ne pourra pas fonctionner correctement. Merci");
            
llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS);   
        }         
    }   
 
    
timer()
    {
        
FollowMe();   // explicite ;)
    
}

Une shape, ce script et bon début...


Conclusions


Suggestions

Vous devez prendre le temps d'ajuster, d'améliorer, d'ajouter des fonctions dans le script Motor Engine V1.0 mais son dénaturer sa fonction première: vous suivre.

Quelques pistes:

Le robot dans ses déplacements va heurter des objets et quelques fois se bloquer lui même contre un objet quelconque (mur par exemple) vous devez prévoir cette situation.

Vous devez tester les frontières world off sous peine de perdre votre robot.

Allez vite est une chose...allez intelligemment aussi

Imaginez l'improbable, l'impossible ...

Tester et faite tester votre robot dans différents lieux ou situations.

Prévoyez des procédures d'urgence.

Mettez un balise de détresse dans le robot.

Prévoyez un mode RHM ( relation homme/machine ) menu / chat etc...

Un robot doit être doté d'un minimum d'IA ( intelligence artificielle) pour le rendre plus autonome et apporter un plus.

Un exemple de robot doté de quelques fonctions utiles :

https://www.xstreetsl.com/modules.ph...9&random=49839

Conseil sur l'architecture


1 Fonction = 1 Script

Faite le distinguo entre une fonction vitale de votre robot et un module de confort.

Exemple:

Le script qui écouterait les ordres du owner est une fonction vitale.

Un script qui ferait dire bonjour au robot est un module de confort

Mettez une racine différente.

Robot_engine
Robot_Listen

module_talk
module_dance


Un "bon" robot contient une bonne dizaine de scripts tous les scripts qui sont pas utiles dans certaines situations sont à "stopper"

llSetScriptState ( "module_dance",FALSE);

Faire un robot vous permettra d'employer 100 % des instructions LSL et 3/4 de ses fonctions... c'est une chance...mais aussi quelques nuits blanches



Espérant vous avoir donné l'envie de créer votre robot personnel


Seb,
Dernières modifications :
(Voir) 07/10/2009 08:08:31 : Seb_01 (Conclusions)
(Voir) (Comparer)07/10/2009 07:55:48 : Seb_01 (creation)
(Voir) (Comparer)07/10/2009 07:04:20 : Seb_01 (creation)
bonjour,

J'aimerai utiliser ce follower mais au cas où le robot est coincé quelque part qu'il s'autodétruise automatiquement, par exemple si l'owner n'est plus à proximité pendant 10 mn ?
est-ce possible et comment ?
merci
Citation :
Publié par Lundrah
Malheureusement Seb ne pourra jamais te répondre car il nous a quitté quelques jours après avoir fini ce WIKI...
Et ce qui est formidable avec un forum c'est que d'autres gens peuvent répondre

Citation :
J'aimerai utiliser ce follower mais au cas où le robot est coincé quelque part qu'il s'autodétruise automatiquement, par exemple si l'owner n'est plus à proximité pendant 10 mn ?
est-ce possible et comment ?
Si par coincé tu entends :
- seul sur la sim : oui tu peux en vérifiant régulièrement la présence sur la sim du owner via par exemple l'utilisation d'un timer couplé avec llGetAgentSize qui renvoie ZERO_VECTOR si le owner n'est pas sur la sim. Si pas présent alors déclencher un état d'attente qui va vérifier s'il est revenu pendant le labs de temps qu'on s'autorise avant de disparaitre.
- sur une frontière de terrain : alors tu peux utiliser un status supplémentaire pour ton objet qui est STATUS_DIE_AT_EDGE ou STATUS_RETURN_AT_EDGE.
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés