Cette page explique un changement important dans le passage de la version 1.3 à 1.4 de VPL : le traitement des événements. Dans VPL 1.3 certains événements (boutons, capteurs de proximité et de sol) sont déclenchés continuellement tant qu'ils sont vrais, dans VPL 1.4 ils sont déclenchés une fois, quand ils deviennent vrais.
Motivation
Le fait de déclencher un événement continuellement n'est pas très propre, pas cohérent avec les événements clap et tape, et souvent l'utilisateur ne se rend pas compte du vrai fonctionnement qui se cache derrière les événements. On peut s'en rendre compte avec un exemple simple, par le programme suivant :
Avec ce code en version 1.3, tant qu'on tient le bouton central pressé, on lance la musique. Ceci signifie que la musique est recommencée continuellement, jusqu'à que le bouton est lâché. L’événement bouton n'est donc pas un événement unique, mais une série d’événements qui apparaissent tant qu'on tient le bouton pressé. Seulement la dernière fois que la musique est lancée, juste avant de lâcher le bouton, elle est jouée entièrement.
Dans la version 1.4 le même code a un autre effet :
Ici on lance la musique quand le bouton devient pressé, avec l’événement qui est déclenché une seule fois.
Événements implicites et code explicite
Prenons un autre exemple dans lequel on pourrait penser que c'est pratique d'avoir les événements en continu :
Avec ce code, tant qu'on est posé au sol on avance et si l'on voit un obstacle on s'arrête. Si l'obstacle disparaît on repart, car tant que le Thymio est posé par terre, le premier événement est déclenché. Donc même s'il y a un obstacle, ce code dit d'avancer, puis dit de s'arrêter et c'est la dernière commande qui a le dernier mot. Ceci n'est souvent pas clair pour les utilisateurs, mais il est vrai que c'est confortable.
En VPL 1.4 ce même code :
…donne un comportement différent: au démarrage Thymio avance et s'il rencontre un obstacle il s'arrête, comme le code précédent. Mais si l'obstacle disparaît, il ne redémarre pas, car le premier événement n'est pas déclenché continuellement. Pour que le Thymio reparte il faut, par exemple, le lever et le reposer, ce qui déclenche le premier événement. D'ailleurs nulle part il est indiqué qu'il faut qu'il reparte si l'obstacle disparaît. Pour avoir un comportement similaire au code de la version 1.3 ci-dessus, il faut indiquer explicitement qu'il faut redémarrer lorsque l'obstacle disparaît :
Nouvelles possibilités offertes par 1.4
Ce traitement des événements en 1.4 permet des programmes impossibles en 1.3. L'exemple initial de la musique est un de ces cas. Voici quelques autres exemples :
Ce code en mode avancé semble logique : en pressant sur le bouton central on peut passer de la couleur rouge à la couleur verte et vice-versa, en utilisant l'état interne. Cette fonctionnalité ne peut pas être programmée dans la version 1.3, car les changements d'état se feraient continuellement tant qu'on presse le bouton.
Un autre exemple :
Ce code permet de lancer le robot avec le bouton "avant" et le faire arrêter à la deuxième ligne au sol qu'il rencontre. Pour implémenter cette fonctionnalité avec la version 1.3 il faut ajouter du code pour détecter le blanc entre les lignes et doubler le nombre d'états.
Un cas de passage de v1.3 à v1.4 : le suivi de ligne avec arrêt devant un obstacle
Si l'on commence à combiner des comportements, on voit des différences importantes entre v1.3 et v1.4. Prenons comme exemple un robot qui doit suivre une ligne et s'arrêter lorsqu'il rencontre un obstacle.
En v1.3 on peut écrire ce programme :
Ce programme fait tourner le robot vers la ligne noire au sol et si un objet se trouve devant lui il s'arrête. Lorsqu’il s'arrête, toutefois, les événements de suivi de ligne sont toujours actifs, mais leur action est annulée par la dernière ligne qui contrôle les obstacles et qui donne la dernière commande moteur. Donc dès que l'obstacle disparaît, le robot continue son suivi de ligne comme il l'avait arrêté.
Si l'on donne les mèmes ordres en v1.4, le robot ne va pas repartir lorsque l'obstacle disparaît. Il y a en effet aucun ordre qui lui dit de repartir. En v1.4 il faut donc faire repartir le robot avec un ordre spécifique :
Ce programme a un comportement différent de celui vu auparavant avec la v1.3 : quand on fait repartir le robot à la disparition de l'obstacle, on ne sait pas dans quel cas on était quand on a stoppé. On ne sait donc pas s'il faut repartir en allant en avant droit ou s'il faut tourner et dans quelle direction pour suivre la ligne. Le programme ci-dessus résout le problème de la façon suivante: si le robot, en suivant la ligne, se trouve à ne voir que du blanc, il se met à tourner vers la gauche pour retrouver une ligne. Lorsque l'obstacle disparaît, pour ré-initialiser le suivi, il fait la même chose, mais dans la direction opposée. Ceci va rapidement le ramener sur la ligne.
Si l'on veut que le robot reparte comme il s'est arrêté, il faut mémoriser la situation dans laquelle on se trouve quand on s'arrête et utiliser cette information quand il repart, par exemple de la façon suivante :
Toutefois ceci peut poser des problèmes délicats. On a pu observer par exemple le cas suivant, très délicat à comprendre: si le robot qui suit la ligne rencontre un obstacle, il s'arrête. L'arrêt ne se fait pas instantanément, mais il y a un bref moment de freinage. Si dans ce bref instant le robot croise une fin de ligne au sol, ceci va déclencher un des événements de suivi, et va repartir en ignorant l'obstacle. La présence de l'obstacle ne déclenchera plus de stop, car l'obstacle est présent en continu.
Un problème similaire peut se présenter si le robot, une fois arrêté devant l'obstacle, est poussé par un autre robot ou par une personne et dans ce mouvement il croise le bord de la ligne au sol. A ce moment il va repartir en ignorant l'obstacle en face de lui.
Ceci signifie que dans la version 1.4 il faut réfléchir plus attentivement à la séquence d’événements, ce qui est plus délicat que de réfléchir aux situations de la version 1.3. Certaines solutions sont donc plus propres que d'autres. Par exemple, le problème de suivi de ligne et stop devant l'obstacle peut se résoudre plus élégamment avec un programme comme celui-ci, qui prévoit également un ordre de start et stop:
Ce programme mémorise la présence de l'obstacle et bloque le suivi jusqu'à que l'obstacle disparaît, ou que l'utilisateur donne l'ordre d'avancer.
Tout cela ajoute de la complexité, mais permet d'être bien plus précis dans la définition du comportement. Par exemple, si lorsque l'obstacle disparaît on veut faire devenir rouge le robot une seconde tout en le faisant partir, ceci n'est pas possible dans la v1.3 sans utiliser les états internes, car il n'existe pas d’événement unique de disparition de l'obstacle, juste un état d'obstacle présent ou absent. Ainsi le code suivant ne marche pas, car l'action de déclencher la minuterie est faite en continu :
Le code en v1.4 qui reprend les mêmes éléments fonctionne bien comme voulu :