Skip to content

TP3

Le but de la séance est de réaliser un Robot capable de suivre une ligne. La détection de la ligne et le contrôle associé se feront dans une tâche temps réel, libérant des ressources pour permettre au Robot de faire d'autres tâches (arrêt d'urgence, par exemple).

Exercice 1 : Suivi de ligne en boucle ouverte

À l'issue de ce premier exercice, votre robot pourra suivre la ligne.

Construction du robot

Construire un Robot mobile simple avec un moteur indépendant pour chaque roues. On peut s'inspirer du modèle proposé ici.

Il faudra remplacer le troisième moteur (inutile) par un système permettant de fixer le capteur de lignes. Voir le modèle déjà construit.

Fonctionnement du capteur de ligne

La classe NXTLineLeader permet de gérer le capteur de ligne. Malheureusement elle n'est pas inclus dans le .jar des classes standards fournies avec le projet LejosRT (basé sur une version ancienne de Lejos).

1- Télécharger le fichier source de la classe NXTLineLeader. Vous ne toucherez pas au contenu de ce fichier, gardez le simplement avec vos autres fichiers sources dans le même répertoire de travail.

2- Dans un fichier SimpleLineLeader.java ajouter une classe SimpleLineLeader avec une méthode main() qui instancie un objet NXTLineLeader : NXTLineLeader captLine = new NXTLineLeader(SensorPort.S1); (remplacez S1 par le numéro du port sur lequel vous avez branché le détecteur de ligne).

Le détecteur de ligne est composé de huit détecteurs photosensibles capables de distinguer deux couleurs. Ici nos couleurs seront blanc et noir. La méthode getResult() d'une instance de NXTLineLeader renvoie un entier dont les huit bits de poids fort codent l'état des huit capteurs. Pour le suivi de ligne on ne va s’intéresser qu'aux bits 2 à 5 (on laisse de coté les bits 0,1,6,8 pour se concentrer sur ceux qui sont au milieu du capteur).

Huit cas sont alors à considérer par rapport aux valeurs de ces quatre bits centraux :

  • seuls les deux de gauche sont a 1 : il faut accélérer du côté droit pour tourner à gauche
  • seul celui de droite est a 0 : idem
  • seul celui de gauche est a 1 : la ligne est en train de s'éloigner fortement du centre du capteur, il faut accélérer franchement à droite pour tourner franchement à gauche
  • les trois cas symétriques
  • tous les bits sont à 0 : on a perdu la ligne, il faut couper les moteurs
  • tous les autres cas : il faut continuer à appliquer la même consigne que précédemment sur les moteurs

3- Déterminez les valeurs en hexadécimal associées aux 7 premiers cas décrits ci dessus.

Pour isoler uniquement les 4 bits qui nous intéressent, on fera ce qu'on appelle un masque grâce à l'opération : value & 0x3C 0x3C étant la représentation héxadécimale d'un nombre dont les deux premiers bits sont à 0, puis les 4 suivant à 1 puis les autres à 0. On obtient alors un entier avec les bits 0 et 1 à 0, les bits 2,3,4,5 avec les valeurs renvoyées par le capteurs et les bits suivants à 0. Il nous reste encore à décaler les bits vers la droite de deux positions, avec l'opérateur >>>2

Ce qui nous donne le squelette de code :

int value = capteur.getResult();
switch( (value&0x3C) >>>2 ){
    case 0x?? : // 1100
    case 0x?? : // 1110
      ... //tourne à gauche
        break;
    case 0x?? : // 1000
      ... // tourne fort à gauche
        break;
    ... // cas symétriques
    case 0x00 : // 0000
      ... // stop !
    default :
      ... // va tout droit
}

Pour pouvoir écrire l'algorithme de contrôle, il ne reste plus qu'à déterminer les différentes vitesses. Ceci se fait par une étude physique du robot et l'application de vos futurs cours d'automatique. Ici on vous donne une manière empirique de les calculer, que vous pourrez ajuster au besoin :

Soit une vitesse de base de 200 (par exemple) qu'on note vb :

  • vitesse en fonctionnement normal : vb pour les deux roues
  • vitesse de correction normale : vb x 2 pour le coté rapide et vb - vb/3 pour le coté lent
  • vitesse de correction plus forte : 4 x vb et vb - (4 x vb) / 5

4- Complétez votre méthode main dans votre classe SimpleLineLeader pour mettre en oeuvre le suivi de ligne en boucle ouverte.

C'est à dire que votre programme entre dans une boucle sans fin durant laquelle :

  • il récupère la valeur du capteur,
  • applique le masque pour ne tester que les quatre bits centraux,
  • détecte le cas et applique la bonne consigne aux deux moteurs
  • fait une pause de 100ms (Thread.sleep(100);, pour éviter de bloquer la brique NXT en envoyant trop de consignes aux moteurs).

On peut maintenant presque passer au test sur le circuit (paillasse "prof"). En effet, le détecteur de ligne nécessite d'être calibrer pour fonctionner correctement. Cela se fait avec un programme qui va lire le capteur lorsqu'il est au dessus d'une surface blanche, puis de nouveau lorsqu'il est au dessus d'une surface noire. Le programme sera à lancer sur le robot avant chaque test car les valeurs du capteur dépendent de la luminosité ambiante et d'autres facteurs qui changent avec le temps.

5- Téléchargez le fichier Calibrate.java, compilez-le et chargez le code sur le robot. Vous pouvez ensuite effectuer le test.

Exercice 2 : Utilisation de tâches périodiques temps réel

1- Sur la base du code précédant, faite une classe RTLineLeader sur le modèle ci-dessous qui hérite de RealtimeThread avec une méthode run() qui fait la boucle de contrôle mais avec un waitForNextPeriod() à la place du Thread.sleep().

public class MyRTClass extends RealtimeThread{

    public MyRTClass(int priority, long periodMillis)
    {
        super(
            new PriorityParameters(priority),
            new PeriodicParameters(new RelativeTime(periodMillis,0))
             );
    }

    private Motor leftM = Motor.C;
    private Motor rightM = Motor.A;
    // ... add any sensor you want to use

    @Override
    public void run(){

        // any oneshot computation needed at launch goes here
        // TODO

        while (true){

            waitForNextPeriod();

            // the code for the control goes here
            // TODO

        }// end while
    }// end run()
}// end class()

2- Écrivez un programme RTLauncher en faisant une classe avec une méthode main() qui crée une instance de RTLineLeader, la démarre (start()) et attends (join()).

public class RTLauncher{

    public static void main(String[] args){

// if needed
//      while (!RConsole.isOpen()){
//          RConsole.open();
//      }

        RTLineLeader rt_ll = new RTLineLeader(...);

        rt_ll.start();

        try{
            rt_ll.join();
        }catch(InterruptedException e){                 
            // RConsole.println("ie in launcher");              
        }

    }
}
Les priorités autorisées pour les threads temps réel sont de 11 à 28.

Exercice 3 : Ajout d'autres tâches

Ajouter sur votre robot un bouton capteur de touché. Ajouter une classe temps réel (sur le même modèle que RTLineLeader) nommée RTPullEvent. Cette classe modèlise une tâche qui teste périodiquement si le boutton est appuyé (méthode isPressed()). Si c'est le cas, elle arrète les moteur.

  1. Quelles priorités relatives donner aux deux tâches RTLineLeader et RTPullEvent pour empecher RTLineLeader de redémarrer les moteurs ?
  2. Complétez le lançeur et testez

Exercice 4 : Meilleure intéraction

Proposez une solution plus élégante en ajoutant un paramètre mode dans la classe RTLineLeader et les setter/getter associés. La tâche RTPullEvent se contentra d'appeller la méthode setMode() pour arreter le robot.