Corrections des travaux pratiques sur le robot NXT

Chapitres traités   

Vous avez dans cette rubrique l'ensemble des corrections issues des travaux pratiques proposés dans l'étude précédente.

 

 

 

Choix du chapitreFaire avancer et faire tourner le robot

Le premier TP nous permet d'utiliser les deux moteurs du robot ainsi que les quatres boutons présents sur la brique. Nous allons commencer par quelques mouvements simples. Voici les fonctionnalités attendues une fois que le programme est en cours d'exécution :

  1. Un appui sur le bouton de validation : demande l'avance du robot droit devant lui à la vitesse par défaut.
  2. Un appui sur le bouton gauche : le robot continu à avancer en tournant sur la gauche de 30° environ.
  3. Un appui sur le bouton droite : le robot continu à avancer en tournant sur la droite de 30° environ.
  4. Un appui sur le bouton d'annulation : le programme s'arrête.
Pour élaborer ce projet, vous aller tenir compte d'un certain nombre de critères :
  1. La gestion des boutons doit se faire de façon événementielle.
  2. Vous allez mettre en oeuvre deux classes, Piloter la classe principale de l'application et la classe Robot qui représente les fonctionnalités du robot.
  3. La classe Robot possède deux moteurs, droite et gauche, peut avancer(), tournerADroite() et tournerAGauche().
Cas d'utilisation

Diagramme de classes

Diagramme de séquence

robot.Piloter.java
package robot;

import lejos.nxt.*;

public class Piloter implements ButtonListener {
    private Robot robot = new Robot();

    public Piloter() {
        Button.ENTER.addButtonListener(this);
        Button.LEFT.addButtonListener(this);
        Button.RIGHT.addButtonListener(this);
    }

    public static void main(String[] args) {
        new Piloter();
        Button.ESCAPE.waitForPressAndRelease();
    }

    public void buttonPressed(Button bouton) {
        if (bouton == Button.ENTER) robot.avancer();
        if (bouton == Button.RIGHT) robot.tournerADroite();
        if (bouton == Button.LEFT) robot.tournerAGauche();
    }

    public void buttonReleased(Button bouton) {  }
}
robot.Robot.java
package robot;

import lejos.nxt.*;

public class Robot {
    private Motor droite = Motor.A;
    private Motor gauche = Motor.C;

    void avancer() {
        droite.forward();
        gauche.forward();
    }

    void tournerADroite() {
        gauche.resetTachoCount();
        gauche.setSpeed(200);
        droite.setSpeed(400);
        while (gauche.getTachoCount() < 360);
        gauche.setSpeed(360);
        droite.setSpeed(360);
    }

    void tournerAGauche() {
        droite.resetTachoCount();
        droite.setSpeed(200);
        gauche.setSpeed(400);
        while (droite.getTachoCount() < 360);
        droite.setSpeed(360);
        gauche.setSpeed(360);
    }
}

 

Choix du chapitre Pouvoir arrêter le robot

Le deuxième TP est une variante du premier. Il serait intéressant de pouvoir arrêter les mouvements du robot sans pour cela quitter impérativement le programme. Je propose donc de nous reservir du bouton de validation pour arrêter le robot. Ainsi le bouton de validation devient l'équivalent d'une bascule :

  1. Si le robot est à l'arrêt, l'appui sur le bouton permet de le faire avancer.
  2. Un nouvel appui sur ce bouton le robot s'arrête.
Pour élaborer ce projet, vous aller tenir compte d'un certain nombre de critères :
  1. La gestion des boutons doit toujours se faire de façon événementielle.
  2. Vous allez conserver les deux classes, Piloter la classe principale de l'application et la classe Robot qui représente les fonctionnalités du robot.
  3. La classe Robot possède deux moteurs, droite et gauche, peut avancer(), arrêter(), tournerADroite() et tournerAGauche().
Cas d'utilisation

Diagramme de classes

Diagramme de séquence


robot.Piloter.java
package robot;

import lejos.nxt.*;

public class Piloter implements ButtonListener {
    private Robot robot = new Robot();
    private boolean bouge;

    public Piloter() {
        Button.ENTER.addButtonListener(this);
        Button.LEFT.addButtonListener(this);
        Button.RIGHT.addButtonListener(this);
    }

    public static void main(String[] args) {
        new Piloter();
        Button.ESCAPE.waitForPressAndRelease();
    }

    public void buttonPressed(Button bouton) {
        if (bouton == Button.ENTER) {
            bouge = !bouge;
            if (bouge) robot.avancer();
            else robot.arreter();
        }
        if (bouton == Button.RIGHT && bouge) robot.tournerADroite();
        if (bouton == Button.LEFT && bouge) robot.tournerAGauche();
    }

    public void buttonReleased(Button bouton) {  }
}
robot.Robot.java
package robot;

import lejos.nxt.*;

public class Robot {
    private Motor droite = Motor.A;
    private Motor gauche = Motor.C;

    void avancer() {
        droite.forward();
        gauche.forward();
    }

    void arreter() {
        droite.stop();
        gauche.stop();
    }

    void tournerADroite() {
        gauche.resetTachoCount();
        gauche.setSpeed(200);
        droite.setSpeed(400);
        while (gauche.getTachoCount() < 360);
        gauche.setSpeed(360);
        droite.setSpeed(360);
    }

    void tournerAGauche() {
        droite.resetTachoCount();
        droite.setSpeed(200);
        gauche.setSpeed(400);
        while (droite.getTachoCount() < 360);
        droite.setSpeed(360);
        gauche.setSpeed(360);
    }
}

 

Choix du chapitre Détection d'un obstacle

Lorsque le robot s'approche d'un obstacle comme le mur de la salle par exemple, il serait souhaitable de le faire ralentir dans un premier temps et de l'arrêter ensuite au contact du mur. Il pourrait alors reculer légèrement pour le dégager du mur.

Pour tester cette fonctionnalité, je vous propose dans un premier temps de ne plus vous préoccuper de faire tourner le robot à droite ou à gauche ou même de faire la demande de l'arrêt. Tenez-vous en uniquement à l'avance du robot avec précausion. Voici d'ailleurs la procédure à suivre :

  1. Un appui sur le bouton de validation : demande l'avance du robot droit devant lui à la vitesse par défaut et affichage de la distance sur l'écran LCD.
  2. Lorsque le robot arrive à 40 cm de l'obstacle : demande de ralentir avec une vitesse de 200.
  3. Le robot atteint l'obstacle : le robot s'arrête et fait une marche arrière d'un tour de roue.
Pour élaborer ce projet, vous aller tenir compte d'un certain nombre de critères :
  1. La gestion du bouton de validation se fait de façon événementielle.
  2. La classe Robot possède deux attributs supplémentaires qui correspondent aux deux capteurs ultrason et finDeCourse. Nous rajoutons également des méthodes qui vont correspondre au fonctionnement attendu savoir, une nouvelle méthode avancer(vitesse), avec aussi les méthodes avancerPrudemment() et reculerLegerement().
Cas d'utilisation

Diagramme de classes

Diagramme de séquence

robot.Piloter.java
package robot;

import lejos.nxt.*;

public class Piloter implements ButtonListener {
    private Robot robot = new Robot();

    public Piloter() {
        Button.ENTER.addButtonListener(this);
    }

    public static void main(String[] args) {
        new Piloter();
        Button.ESCAPE.waitForPressAndRelease();
    }

    public void buttonPressed(Button bouton) {
        robot.avancerPrudemment();
        robot.reculerLegerement();
    }

    public void buttonReleased(Button bouton) {  }
}
robot.Robot.java
package robot;

import lejos.nxt.*;

public class Robot {
    private Motor droite = Motor.A;
    private Motor gauche = Motor.C;
    private UltrasonicSensor ultraSon = new UltrasonicSensor(SensorPort.S1);
    private TouchSensor finDeCourse = new TouchSensor(SensorPort.S3);

    void avancer() {
        droite.forward();
        gauche.forward();
    }

    void avancer(int vitesse) {
        droite.setSpeed(vitesse);
        gauche.setSpeed(vitesse);
        if (!droite.isMoving()) avancer();
    }

    void avancerPrudemment() {
       avancer(); 
       while (!finDeCourse.isPressed()) {
            int distance = ultraSon.getDistance();
            LCD.drawInt(distance, 5, 0, 0);
            if (distance <= 40) avancer(200);
        }
        arreter();
    }
    
    void reculerLegerement() {
        droite.rotate(-360, true);
        gauche.rotate(-360);
    }

    void arreter() {
        droite.stop();
        gauche.stop();
    }

    void tournerADroite() {
        gauche.resetTachoCount();
        gauche.setSpeed(200);
        droite.setSpeed(400);
        while (gauche.getTachoCount() < 360);
        gauche.setSpeed(360);
        droite.setSpeed(360);
    }

    void tournerAGauche() {
        droite.resetTachoCount();
        droite.setSpeed(200);
        gauche.setSpeed(400);
        while (droite.getTachoCount() < 360);
        droite.setSpeed(360);
        gauche.setSpeed(360);
    }
}

 

Choix du chapitre Ralentir progressivement

Nous allons reprendre toutes les fonctionnalités précédentes en rajoutant juste un ralentissement progressif au lieu de proposer une vitesse de ralentissement unique à l'approche de l'obstacle. Nous en profiterons également pour prévoir un demi-tour complet du robot après qu'il ait reculé de l'obstacle.

  1. Un appui sur le bouton de validation : demande l'avance du robot droit devant lui à la vitesse par défaut et affichage de la distance sur l'écran LCD.
  2. Lorsque le robot arrive à 60 cm de l'obstacle : demande de ralentir progressivement suivant la distance parcourue.
  3. Lorsque le robot arrive à 30 cm de l'obstacle : maintenir une vitesse d'avance de 120.
  4. Le robot atteint l'obstacle : le robot s'arrête, fait une marche arrière d'un tour de roue et effectue ensuite un demi-tour complet pour être prêt à repartir dans le sens inverse.
Pour élaborer ce projet, vous aller tenir compte d'un certain nombre de critères :
  1. La gestion du bouton de validation se fait de façon événementielle.
  2. Vous devez changer le comportement de la méthode avancerPrudemment() de la classe Robot afin de correspondre aux nouvelles fonctionnalités. Par ailleurs, vous devez implémenter une nouvelle méthode qui se nomme demiTour().
Cas d'utilisation

Diagramme de classes

Diagramme de séquence

robot.Piloter.java
package robot;

import lejos.nxt.*;

public class Piloter implements ButtonListener {
    private Robot robot = new Robot();

    public Piloter() {
        Button.ENTER.addButtonListener(this);
    }

    public static void main(String[] args) {
        new Piloter();
        Button.ESCAPE.waitForPressAndRelease();
    }

    public void buttonPressed(Button bouton) {
        robot.avancerPrudemment();
        robot.reculerLegerement();
        robot.demiTour();
    }

    public void buttonReleased(Button bouton) {  }
}
robot.Robot.java
package robot;

import lejos.nxt.*;

public class Robot {
    private Motor droite = Motor.A;
    private Motor gauche = Motor.C;
    private UltrasonicSensor ultraSon = new UltrasonicSensor(SensorPort.S1);
    private TouchSensor finDeCourse = new TouchSensor(SensorPort.S3);

    void avancer() {
        droite.forward();
        gauche.forward();
    }

    void avancer(int vitesse) {
        droite.setSpeed(vitesse);
        gauche.setSpeed(vitesse);
        if (!droite.isMoving()) avancer();
    }

    void avancerPrudemment() {
        avancer();
        while (!finDeCourse.isPressed()) {
            int distance = ultraSon.getDistance();
            LCD.drawInt(distance, 5, 0, 0);
            if (distance >= 60) avancer(360);
            if (distance < 60 && distance > 30) avancer(4*distance);
            if (distance <= 30) avancer(120);
        }
        arreter();
    }
    
    void reculerLegerement() {
        droite.rotate(-360, true);
        gauche.rotate(-360);
    }

    void demiTour() {
        droite.rotate(1000, true);
        gauche.rotate(-1000);
    }

    void arreter() {
        droite.stop();
        gauche.stop();
    }

    void tournerADroite() {
        gauche.resetTachoCount();
        gauche.setSpeed(200);
        droite.setSpeed(400);
        while (gauche.getTachoCount() < 360);
        gauche.setSpeed(360);
        droite.setSpeed(360);
    }

    void tournerAGauche() {
        droite.resetTachoCount();
        droite.setSpeed(200);
        gauche.setSpeed(400);
        while (droite.getTachoCount() < 360);
        droite.setSpeed(360);
        gauche.setSpeed(360);
    }
}

 

Choix du chapitre Tous les mouvements avec détection d'obstacle

Nous allons faire une fusion de tous les TPs précédents. Nous désirons ainsi que notre robot puisse avancer, tourner à gauche et à droite, s'arrêter. Toutefois, lorsque le robot en en mouvement, il faudrait "en même temps" qu'il soit capable de détecter les obstacles et de réagir en conséquence, c'est-à-dire de ralentir progressivement, faire demi-tour en cas de contact et de repartir comme si de rien n'était.

  1. Un appui sur le bouton de validation : demande l'avance du robot droit devant lui avec une vitesse compatible avec les obstacles éventuels.
  2. Un appui sur le bouton gauche : le robot continu à avancer en tournant sur la gauche de 30° environ.
  3. Un appui sur le bouton droite : le robot continu à avancer en tournant sur la droite de 30° environ.
  4. Un appui sur le bouton d'annulation : le programme s'arrête.
  5. Lorsque Le robot atteint l'obstacle : le robot s'arrête, fait une marche arrière d'un tour de roue et effectue ensuite un demi-tour complet pour être prêt à repartir dans le sens inverse.
  6. Lorsque le demi-tour est accompli : le robot continu d'avancer à une vitesse compatible avec les obstacles éventuels.
Pour élaborer ce projet, vous aller tenir compte d'un certain nombre de critères :
  1. La gestion des trois boutons se fait de façon événementielle.
  2. Vous allez conserver les deux classes, Piloter la classe principale de l'application et la classe Robot qui représente les fonctionnalités du robot.
  3. Vous pouvez vous servir des attributs et des méthodes que vous avez mis en oeuvre dans les TPs précédents. Pour les méthodes, il faudra peut-être en modifier le contenu.
  4. En tout cas, l'avance du robot doit se réaliser dans une tâche concurrente pour prendre en compte toutes les actions souhaitées par l'utilisateur.
Cas d'utilisation

Diagramme de classes

Diagramme de séquence complet

robot.Piloter.java
package robot;

import lejos.nxt.*;

public class Piloter implements ButtonListener {
    private Robot robot = new Robot();
    private boolean bouge;

    public Piloter() {
        Button.ENTER.addButtonListener(this);
        Button.LEFT.addButtonListener(this);
        Button.RIGHT.addButtonListener(this);
    }

    public static void main(String[] args) {
        new Piloter();
        Button.ESCAPE.waitForPressAndRelease();
    }

    public void buttonPressed(Button bouton) {
        if (bouton == Button.ENTER) {
            bouge = !bouge;
            if (bouge) robot.avancer();
            else robot.arreter();
        }
        if (bouton == Button.RIGHT && bouge) robot.tournerADroite();
        if (bouton == Button.LEFT && bouge) robot.tournerAGauche();
    }

    public void buttonReleased(Button bouton) {  }
}
robot.Robot.java
package robot;

import lejos.nxt.*;

public class Robot {
    private Motor droite = Motor.A;
    private Motor gauche = Motor.C;
    private UltrasonicSensor ultraSon = new UltrasonicSensor(SensorPort.S1);
    private TouchSensor finDeCourse = new TouchSensor(SensorPort.S3);
    private boolean faireAvancer;

    void demarrer() {
        droite.forward();
        gauche.forward();
    }
    
    void avancer() {
        faireAvancer = true;
        new Thread(new Runnable() {
            public void run() {
               demarrer();
               avancerPrudemment();
            }
        }).start();
    }

    void avancer(int vitesse) {
        droite.setSpeed(vitesse);
        gauche.setSpeed(vitesse);
    }

    void avancerPrudemment() {
        while (faireAvancer) {
            while (!finDeCourse.isPressed() && faireAvancer) {
                int distance = ultraSon.getDistance();
                LCD.drawInt(distance, 5, 0, 0);
                if (distance >= 60) avancer(360);
                if (distance < 60 && distance > 30) avancer(4*distance);
                if (distance <= 30) avancer(120);
            }
            if (faireAvancer) {
                arreter();
                reculerLegerement();
                demiTour();
                demarrer();
            }
        }
    }
    
    void reculerLegerement() {
        droite.rotate(-360, true);
        gauche.rotate(-360);
    }

    void demiTour() {
        droite.rotate(1000, true);
        gauche.rotate(-1000);
    }

    void arreter() {
        droite.stop();
        gauche.stop();
    }

    void tournerADroite() {
        faireAvancer = false;
        gauche.stop();
        droite.rotate(360);
        avancer();
    }

    void tournerAGauche() {
        faireAvancer = false;
        droite.stop();
        gauche.rotate(360);
        avancer();
    }
}

 

Choix du chapitre Pilotage du robot à distance

 

Nous finissons notre étude en reprenant exactement les fonctionnalités précédentes, mais le robot cette fois-ci sera piloté à distance et non plus par les boutons de la brique.

  1. Un appui sur le bouton Avancer : demande l'avance du robot droit devant lui avec une vitesse compatible avec les obstacles éventuels.
  2. Un appui sur le bouton Gauche : le robot continu à avancer en tournant sur la gauche de 30° environ.
  3. Un appui sur le bouton Droite : le robot continu à avancer en tournant sur la droite de 30° environ.
  4. Un appui sur le bouton Arreter : le robot s'arrête.
  5. Unappui sur le bouton Quitter : la connexion avec le robot s'interromp.
Pour élaborer ce projet, vous aller tenir compte d'un certain nombre de critères :
  1. Cette fois-ci, nous avons deux composants logiciels, un côté PC et un autre sur l'informatique embarquée du robot.
  2. Côté robot, pour quitter le programme définitivement, une gestion événementielle est prévue avec le bouton d'annulation.
  3. Toujours côté robot, vous allez conserver les deux classes, Piloter la classe principale de l'application et la classe Robot qui représente les fonctionnalités du robot.
  4. Aucune modification n'ait à apporter sur cette denière classe Robot.
  5. Par contre, côté PC, vous devez implémenter la classe Distante qui permettra, au travers d'une IHM succinte, de commander le robot par Bluetooth.
Cas d'utilisation

Diagramme de composants

Diagramme de classes

Diagramme de séquence

robot.Distance.java
package robot;

import java.awt.event.ActionEvent;
import java.io.*;
import javax.swing.*;
import lejos.pc.comm.*;

public class Distante extends JFrame {
    private JToolBar outils = new JToolBar();
    private NXTConnector  connexion;
    private DataOutputStream requete;
    private int commande;
    private final int QUITTER = 0;
    private final int AVANCER = 1;
    private final int GAUCHE = 2;
    private final int DROITE = 3;
    private final int ARRETER = 4;      
   
    public Distante() {
        super("Pilotage du robot");
        seConnecter();
        add(outils);
        outils.add(new AbstractAction("Quitter") {
            public void actionPerformed(ActionEvent e) {
                try {
                    requete.writeInt(QUITTER);
                    requete.flush();
                }
                catch (IOException ex) { setTitle("Problème de communication");   }
            }
        });
        outils.add(new AbstractAction("Avancer") {
            public void actionPerformed(ActionEvent e) {
                try {
                    requete.writeInt(AVANCER);
                    requete.flush();
                }
                catch (IOException ex) { setTitle("Problème de communication");   }
            }
        });
        outils.add(new AbstractAction("Gauche") {
            public void actionPerformed(ActionEvent e) {
                try {
                    requete.writeInt(GAUCHE);
                    requete.flush();
                }
                catch (IOException ex) { setTitle("Problème de communication");   }
            }
        });
        outils.add(new AbstractAction("Droite") {
            public void actionPerformed(ActionEvent e) {
                try {
                    requete.writeInt(DROITE);
                    requete.flush();
                }
                catch (IOException ex) { setTitle("Problème de communication");   }
            }
        });
        outils.add(new AbstractAction("Arreter") {
            public void actionPerformed(ActionEvent e) {
                try {
                    requete.writeInt(ARRETER);
                    requete.flush();
                }
                catch (IOException ex) { setTitle("Problème de communication");   }
            }
        });
        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }
   
    private void seConnecter() {
       connexion = new NXTConnector();
       if (connexion.connectTo(1234)) requete = connexion.getDataOut();
       else System.err.println("Aucune connexion Bluetooth...");
    }
    
    public static void main(String[] args) {  new Distante(); }
}
robot.Piloter.java
package robot;

import java.io.*;
import lejos.nxt.*;
import lejos.nxt.comm.*;

public class Piloter implements ButtonListener {
    private Robot robot = new Robot();
    private NXTConnection connexion;
    private DataInputStream requete;
    private int commande;
    private final int QUITTER = 0;
    private final int AVANCER = 1;
    private final int GAUCHE = 2;
    private final int DROITE = 3;
    private final int ARRETER = 4;

    public Piloter() {
       Button.ESCAPE.addButtonListener(this);
       LCD.drawString("Attente...", 0, 1);
       connexion = Bluetooth.waitForConnection();
       requete = connexion.openDataInputStream();
       LCD.drawString("Connexion", 0, 1);
       commander();
    }

    public static void main(String[] args) {
        new Piloter();
    }

    private void commander() {
        try {
            do {
                commande = requete.readInt();
                LCD.drawInt(commande, 3, 0, 2);  
                switch (commande) {
                    case AVANCER : robot.avancer(); break;
                    case GAUCHE  : robot.tournerAGauche(); break;
                    case DROITE   : robot.tournerADroite(); break;
                    case ARRETER : robot.arreter(); break;
                }
            }
            while (commande!=QUITTER);
            requete.close();
            connexion.close();
            LCD.drawString("Deconnexion", 0, 1);
        } 
        catch (IOException ex) {
            LCD.drawString("Probleme", 0, 1);
        }        
    }
    
    public void buttonPressed(Button bouton) {
        System.exit(0);
    }

    public void buttonReleased(Button bouton) {  }
}