Apprentissage de la programmation en P_LOGO
Le temps d'en rire.

 

 

Retour au sommaire

Sans y connaître rien à la météo, le LOGO a quand même quelques notions sur le temps. Des primitives spécialement adaptées à la gestion de l'horloge de l'ordinateur permettent de programmer des événements, des attentes.

Un petit tour des possibilités offertes par LOGO s'impose.

Pour commencer, des primitives opérations simples sont disponibles, elles renvoient des informations sur l'horloge de l'ordinateur. Elles sont accessibles par exemple après une commande EC. DATE rend la date du jour sous forme d'une liste à trois éléments numérique, la date, le mois et l'année. HEURE rend l'heure courante (attention, c'est celle de l'ordinateur après une configuration de l'utilisateur). TEMPS rend le temps écoulé, en secondes, depuis le début de la session (depuis que P_LOGO a été ouvert). JOUR [j m a] rend le numéro du jour de la semaine.

Un petit exemple rapide :

POUR INFOTEMPS

TAPE PH PH PH PH [Nous sommes le ] ITEM JOUR DATE [lundi mardi mercredi jeudi vendredi samedi dimanche] SP SD DATE ITEM JOUR DATE [janvier février mars avril mai juin juillet août septembre octobre novembre décembre] DER DATE

EC ".

TAPE PH PH PH [Il est ] PREM HEURE "H SP SD HEURE

EC ".

FIN

Pas besoin d'explication, la manipulation des listes a été vue dans une précédente partie. Ce n'est pas très pratique, mais ça peut rendre service.

En si on faisait une petite horloge pour se dégourdir les doigts. Pour l'instant, on va la faire statique, elle devra juste indiquer l'heure, les minutes et les secondes à l'instant auquel on exécute la procédure.

POUR CADRAN

BC FCC 1 CERCLE 100 CERCLE 3

FCC 9 LC

REPETE 12 [AV 90 BC AV 8 LC RE 98 TD 30]

FIN

POUR TROTTEUSE1 :SECONDE

FCC 10

TD PROD 6 :SECONDE

LC AV 80 BC AV 10 LC RE 90

TG PROD 6 :SECONDE

FIN

POUR GRANDEAIGUILLE1 :MINUTE

FCC 12

TD PROD 6 :MINUTE

LC AV 35 BC AV 40 LC RE 75

TG PROD 6 :MINUTE

FIN

POUR PETITEAIGUILLE1 :HEURE

FCC 11

TD PROD 30 :HEURE

LC AV 5 BC AV 25 LC RE 30

TG PROD 30 :HEURE

FIN

POUR HORLOGE1

NETTOIE

CADRAN

PETITEAIGUILLE1 PREM HEURE

GRANDEAIGUILLE1 PREM SP HEURE

TROTTEUSE1 DER HEURE

FIN

Jusque-là, rien de sorcier. Lorsqu'on exécute HORLOGE, le cadran et les trois aiguilles apparaissent.

La récursivité n'a plus de secret pour vous, nous allons en user, pour que l'horloge devienne dynamique.

Première possibilité, si on a un ordinateur rapide, réafficher la totalité de l'horloge.

POUR DYNAHORLOGE1

HORLOGE1

DYNAHORLOGE1

FIN

VE CT DYNAHORLOGE1

Ca clignote beaucoup ! Pour remédier à cela, une première amélioration consiste à attendre une seconde entre chaque affichage ; effet, les aiguilles ne bougent au plus que toutes les secondes. Pour cela, on utilise la primitive ATTENDS n, qui suspend l'exécution pendant le nombre de secondes (les décimales sont autorisées) indiqué par le paramètre.

POUR DYNAHORLOGE2

HORLOGE1

ATTENDS 1

DYNAHORLOGE2

FIN

Ca fonctionne bien, mais ce n'est pas très rigoureux. En premier lieu, il n'est pas nécessaire d'afficher tout l'écran. Pour ne pas avoir à le faire, on va modifier les procédures pour pouvoir que les aiguilles s'effacent automatiquement, sans un VIDEECRAN ou un NETTOIE. En deuxième lieu, il n'est nécessaire non plus de retracer les trois aiguilles alors que la trotteuse ne change que toutes les secondes, la grande aiguille ne change que toutes les minutes, c'est encore plus rare pour la petite aiguille.

POUR TROTTEUSE2 :SECONDE

FCC 0

TD PROD 6 :PRECEDENTESECONDE

LC AV 80 BC AV 10 LC RE 90

TG PROD 6 :PRECEDENTESECONDE

FCC 10

TD PROD 6 :SECONDE

LC AV 80 BC AV 10 LC RE 90

TG PROD 6 :SECONDE

DONNE "PRECEDENTESECONDE :SECONDE

FIN

On utilise la définition de variables pour mémoriser la dernière position de la trotteuse affichée (DONNE…) ; ceci pour pouvoir commencer par effacer l'ancienne (FCC 0…) avant d'afficher la nouvelle (FCC 10…). On fait de même pour les deux autres aiguilles.

POUR GRANDEAIGUILLE2 :MINUTE

FCC 0

TD PROD 6 :PRECEDENTEMINUTE

LC AV 35 BC AV 40 LC RE 75

TG PROD 6 :PRECEDENTEMINUTE

FCC 12

TD PROD 6 :MINUTE

LC AV 35 BC AV 40 LC RE 75

TG PROD 6 :MINUTE

DONNE "PRECEDENTEMINUTE :MINUTE

FIN

POUR PETITEAIGUILLE2 :HEURE

FCC 0

TD PROD 30 :PRECEDENTEHEURE

LC AV 5 BC AV 25 LC RE 30

TG PROD 30 :PRECEDENTEHEURE

FCC 11

TD PROD 30 :HEURE

LC AV 5 BC AV 25 LC RE 30

TG PROD 30 :HEURE

DONNE "PRECEDENTEHEURE :HEURE

FIN

POUR HORLOGE2

NETTOIE

CADRAN

DONNE "PRECEDENTESECONDE 0

DONNE "PRECEDENTEMINUTE 0

DONNE "PRECEDENTEHEURE 0

PETITEAIGUILLE2 PREM HEURE

GRANDEAIGUILLE2 PREM SP HEURE

TROTTEUSE2 DER HEURE

FIN

La procédure horloge comprend la déclaration des trois variables avant d'afficher les trois aiguilles.

POUR DYNAHORLOGE3

SI NEGALè :PRECEDENTESECONDE DER HEURE [CHANGESECONDE]

DYNAHORLOGE3

FIN

Là, il y a du changement. Une condition de test branche sur CHANGESECONDE si les secondes ont changé par rapport à la dernière information affichée.

POUR CHANGESECONDE

TROTTEUSE2 DER HEURE

SI NEGALè :PRECEDENTEMINUTE PREM SP HEURE [CHANGEMINUTE]

FIN

Si les secondes ont changé, on exécute TROTTEUSE2 et on test si l'aiguille des minutes doit être mise à jour. Idem pour les heures.

POUR CHANGEMINUTE

GRANDEAIGUILLE2 PREM SP HEURE

SI NEGALè :PRECEDENTEHEURE PREM HEURE [CHANGEHEURE]

FIN

POUR CHANGEHEURE

PETITEAIGUILLE2 PREM HEURE

FIN

Du coup, on a un affichage beaucoup plus fluide, le clignotement a disparu. Seul ce qui doit bouger disparaît et s'affiche de nouveau.

Et si on voulait faire un réveil… Enfin pas tout à fait.

La primitive DEBUTEMPS n déclenche un chronomètre, où le paramètre n, représente le nombre de seconde avant la fin du compte. A la fin du compte, le prédicat FINTEMPSè indique si le temps est écoulé ou non.

POUR DYNAHORLOGE

SI FINTEMPSè [REVEIL]

SI NEGALè :PRECEDENTESECONDE DER HEURE [CHANGESECONDE]

DYNAHORLOGE

FIN

On a simplement ajouté la ligne de test pour savoir si le temps est écoulé. Si c'est le cas, on branche sur la procédure REVEIL que voici :

POUR REVEIL

EC [Un temps de 90 secondes est dépassé.]

DEBUTEMPS 90

FIN

A la fin de REVEIL, on relance le chronomètre pour une durée de 90 secondes.

VE CT HORLOGE

DEBUTEMPS 90

DYNAHORLOGE

Mise en garde : le prédicat FINTEMPSè rend vrai après l'exécution de la primitive ATTENDS, même si le chronomètre démarré avec DEBUTEMPS n'est pas terminé. (Il m'a fallu pas mal de temps pour dégotter ce Bug du P_LOGO.) Autrement dit, il faut choisir entre l'utilisation du chronomètre ou des suspensions.

L'intérêt de DEBUTEMPS et FINTEMPSè sur ATTENDS est que l'attente n'est pas bloquante, on peut exécuter d'autres choses pendant ce temps là.

Par exemple, on veut faire un programme qui fait avancer la tortue et toutes les 3 secondes changer de couleur. Mais si entre-temps, la tortue rencontre une ligne blanche, elle doit changer de direction.

POUR CHANGECOULEURTORTUE

FCC SI EGALè CC 14 [1] [SOMME CC 1]

DEBUTEMPS 3

FIN

POUR CHANGEDIRECTIONTORTUE

TD SOMME 160 HASARD 40

FIN

POUR BOUCLE

BC AV 1 LC AV 1

SI EGALè 15 CPOINT POS [RE 1 CHANGEDIRECTIONTORTUE] [RE 1]

SI FINTEMPSè [CHANGECOULEURTORTUE]

BOUCLE

FIN

POUR DEPART

VE LC FPOS [-30 -30] BC REPETE 4 [AV 60 TD 90] LC ORIGINE BC

FCC 1

DEBUTEMPS 3

BOUCLE

FIN

Cette structure (chronomètre en même temps que d'autres actions) est particulièrement bien adaptée au pilotage des robots avec des SuperMEC. En effet, il est fréquent de vouloir qu'un robot se déplace pendant un certain temps, mais pour autant, il doit adapter son action à d'éventuels obstacles. Une suspension (avec ATTENDS) ne permettrait pas la détection d'obstacles.

Plus fort encore, voici une proposition pour gérer plusieurs chronomètres en même temps. Il s'agit de créer une liste contenant des temps et des actions à produire lorsque les temps sont atteints.

Toutes les explications sont en commentaires dans le listing. Vous remarquerez qu'on utilise les listes de propriétés pour définir et gérer les événements.

; Programme permettant de multiples interruptions temporelles avec ou sans répétitions.

; --------------------------------------------------------------- Début

POUR AJOUTERCHRONO :NOMCHRONO :NBSECONDES :ACTION :REPETITION

; Permet d'ajouter la programmation d'un événement (chronomètre)

; :NOMCHRONO est un mot, le nom du chronomètre

; :NBSECONDES est un nombre, le nombre de secondes avant l'événement

; :ACTION est une liste, la liste des commandes LOGO à exécuter lors de l'événement

; :REPETITION est un prédicat, VRAI pour qu'il y ait une répétition, FAUX sinon.

EFFACECHRONO :NOMCHRONO ; si le chronomètre existait, on l'efface.

DONNE "LISTECHRONO MD :NOMCHRONO :LISTECHRONO ; on ajoute le chronomètre à la liste globale des chronomètre

DPROP DER :LISTECHRONO "FINTEMPS SOMME TEMPS :NBSECONDES ; on enregistre l'heure de la prochaine occurence de l'événement

DPROP DER :LISTECHRONO "ACTION :ACTION ; on enregistre la liste des actions à exécuter

DPROP DER :LISTECHRONO "REPETER SI :REPETITION [:NBSECONDES] [FAUX] ; s'il y a répétition, on enregistre l'intervale de temps entre les événements, sinon, on enregistre FAUX.

FIN

POUR EFFACECHRONO :NOMCHRONO

; Permet d'effacer la programmation d'un événement (chronomètre)

; :NOMCHRONO est un mot, le nom du chronomètre à effacer

SI NON MEMBREè :NOMCHRONO :LISTECHRONO [STOP] ; si le nom du chronomètre ne fait pas partie de la liste des chronomètre, on sort.

EFPROP :NOMCHRONO ; on efface toutes les propriétés du chronomètre

DONNE "LISTECHRONO SI EGALè :NOMCHRONO PREM :LISTECHRONO [SP :LISTECHRONO] [MD PREM :LISTECHRONO SP :LISTECHRONO]

; 1. si le premier chrono de la liste des chronos est celui qu'on veut effacer, on la retire de la liste

; 2. sinon, on met en dernier de la liste le premier chronomètre dela liste (rotation).

EFFACECHRONO :NOMCHRONO ; appel récursif avec le même mot, le chronomètre à effacer. La procédure s'arrête lorsque le chronomètre ne fait plus partie de la liste (dès qu'il a été effacé).

FIN

POUR TESTCHRONO

; Test si un événement a eu lieu parmi tous les chronomètres. S'il a eu lieu, on le traite.

TESTCHAQUECHRONO :LISTECHRONO

; La procédure sert juste à passer en paramètre la liste des chronomètres programmés.

FIN

POUR TESTCHAQUECHRONO :LISTEDESCHRONOS

; Réelle procédure de test de l'atteinte d'un événement de chque chronomètre.

; LISTEDESCHRONOMETRES est la liste des chronomètres dont il faut tester l'atteinte d'événement.

SI VIDEè :LISTEDESCHRONOS [STOP]

; Si la liste donnée en paramètre est vide, on termine la procédure.

SI PLPEè RPROP PREM :LISTEDESCHRONOS "FINTEMPS TEMPS [CHRONOATTEINT PREM :LISTEDESCHRONOS]

; Si l'heure de l'événement du premier chornomètre de la liste est atteinte ou dépassée, on exécute la procédure CHRONOATTEINT avec comme paramètre le nom du chronomètre en cause.

TESTCHAQUECHRONO SP :LISTEDESCHRONOS

; Appel récursif de la procédure avec une liste diminuée de son premier chronomètre.

FIN

POUR CHRONOATTEINT :CHRONO

; Procédure gérant l'atteinte d'un événement

; :CHRONO est un mot, il contient le nom du chronomètre qui a été atteint (voir TESTCHAQUECHRONO)

EXEC RPROP :CHRONO "ACTION

; on exécute la liste des commandes LOGO du chronomètre (voir AJOUTERCHRONO)

SI NOMBREè RPROP :CHRONO "REPETER [AJOUTERCHRONO :CHRONO RPROP :CHRONO "REPETER RPROP :CHRONO "ACTION VRAI] [EFFACECHRONO :CHRONO]

; Si le chronomètre est à répétition, on le reprogramme tel quel, sinon, on l'efface de la liste des chronomètre.

FIN

DONNE "LISTECHRONO []

; Initialisation de la liste des chronomètre.

EC [Nouvelles procédures pour le traitement des événements temporels multiples :]

EC [AJOUTERCHRONO :NOMCHRONO :NBSECONDES :ACTION :REPETITION]

EC [EFFACECHRONO :NOMCHRONO]

EC [TESTCHRONO]

; --------------------------------------------------------------- Fin

POUR DEPART

; Procédure d'exemple d'utilisation des événements multimples

DONNE "LISTECHRONO []

; Initialisation de la liste des chronomètre.

AJOUTERCHRONO "PAS 3 [AV 50] VRAI

; Programamtion d'un premier événement est à répétition, toutes les 3 secondes, la tortue avancera de 50 pas.

AJOUTERCHRONO "ANGLE 5 [TD HASARD 360] VRAI

; Programmation d'un deuxième événement, toutes les 5 secondes, la tortue changera de cap.

AJOUTERCHRONO "COULEUR 9 [FCC HASARD 16] VRAI

; Programmation d'un troisième événement, toutes les 9 secondes, la couleur du crayon sera changée.

TAPE [Le programme ]

; affichage d'un message sans retour à la ligne.

BOUCLE

; appel de la procédure BOUCLE

FIN

POUR BOUCLE

; procédure présentant le corps du programme

TESTCHRONO

; appel de la procédure qui vérifie et traite les événements programmés.

; ----- début du corps du programme indépendant des événements

ATTENDS 0.25

; attente d'un quart de seconde, c'est juste pour ne pas faire déborder la pile trop vite.

TAPE [tourne, ]

; écriture d'un message à l'écran pour démontrer que c'est bien le programme principal en cours d'exécution.

BOUCLE

; appel récursif de la procédure.

; ----- fin du corps du programme indépendant des événements

FIN

On peut, si l'on préfère n'exécuter la procédure TESTCHRONO que toutes les secondes (et ainsi ne pas perdre trop de temps d'exécution) remplacer la première ligne de la procédure BOUCLE par :

SI EVENTè [TESTCHRONO] ; EVENTè est vrai toutes les secondes.

Que c'est beau, le LOGO !

Chapître suivant


Webmaster : Sinclair ( philippe.lucidarme@wanadoo.fr ) dernière mise à jour : 1 aout1999.