Travaux pratiques de l'option systèmes temps-réel
Programmation du robot LEGO Mindstorm(TM)


Isabelle PUAUT

 



Liens rapides


Introduction

Le LEGO Mindstorm Robotics Invention System (RIS 2.0) est constitué d'un ensemble de pièces LEGO et de l'unité RCX (unité de commande du robot, voir photo à gauche du texte). La brique RCX est un système programmable autonome bâti autour d'un micro-contrôleur Hitachi H8/3932. La brique RCX peut être utilisée pour contrôler des actionneurs (moteurs, générateur de sons) et lire des entrées en provenance de capteurs (capteur de lumière, détecteurs de contact). D'autres capteurs et actionneurs peuvent être ajoutés (capteurs de pression, de température, de rotation, etc.). La brique RCX possède également un petit écran LCD, utile pour afficher de l'information, et un émetteur - récepteur infrarouge, utile pour télécharger des programmes et communiquer avec les autres RCX. L'unité RCX est conçue pour pouvoir facilement être attachée à d'autres briques LEGO.

BrickOS (appelé précédemment LegOS) est un petit système d'exploitation pour la brique RCX. BrickOS est généré par compilation croisée sous Linux ou Windows 95/98/2000/XP. Les programmes BrickOS peuvent être développés en C ou C++ et compilés en code natif pour le micro-contrôleur Hitachi H8. BrickOS fournit un ordonnancement multitâche préemptif, de la gestion dynamique de la mémoire, des sémaphores POSIX ainsi que des accès aux capteurs, actionneurs, écran LCD, communication infrarouge. A noter que BrickOS n'est pas un système pour application temps-réel strict, mais offre des fonctionnalités similaires à de nombreux systèmes temps-réel embarqués du commerce.

La version de BrickOS utilisée lors des TPs est la version la plus récente de BrickOS à la date de création des TPs (septembre 2003), à savoir la version 0.2.6.10.


Installation et mise en route de BrickOS

Cette section présente les étapes d'installation de BrickOS (Version 0.2.6.10) nécessaires pour démarrer les TPs. Il a été testé dans un environnement Windows XP Édition Familiale, sous XP professionnel et sous Windows 2000. Il fonctionne pour un kit "Robotics Invention System 2.0", pour lequel la communication infrarouge est réalisée par USB.

Pour utiliser BrickOS, il faut disposer :

  1. d'une version de cygwin (a été testé avec les versions de compilateurs 3.2.2 et 3.3.1).
  2. d'un pilote pour la tour infrarouge, servant à télécharger les programmes sur le RCX.
  3. d'un compilateur croisé Hitachi H8.
  4. du .tgz de BrickOS.

Tous les élements sauf 4 sont déjà installés sur les machines du réseau étudiant (voir ici pour une documentation complète d'installation).

Décompression et compilation de BrickOS

  1. Ouvrez un shell Cygwin
  2. Placez vous à la racine de votre répertoire personnel
    cd H:
  3. Récupérer BrickOS ici et le dé-tarer
    gunzip brickos-0.2.6.10.tgz
    tar xf brickos-0.2.6.10.tar
    Vous obtenez alors un répertoire /brickos-0.2.6.10/
  4. Rendez vous dans ce répertoire: cd brickos-0.2.6.10
  5. Tapez ./configure, de manière à localiser le compilateur croisé et à configurer la compilation de BrickOS.
  6. Tapez make realclean
  7. Tapez make, pour obtenir votre système BrickOS, vos démos prêtes à l'emploi, et vos utilitaires de téléchargement vers le robot.

NB : le fichier configure, présent à la racine des sources BrickOS, recherche le compilateur croisé à partir du répertoire racine cygwin. Si le compilateur croisé a été installé ailleurs qu'à cet emplacement, le fichier configure devra être modifié en conséquence.

Décontraction


TP 1 : Prise en main du robot

Montage du robot

Développement d'un petit programme

Remarques


TP2 : Ordonnancement par plans statiques cycliques

L'objectif de ce TP est de mettre en place un séquenceur au dessus de BrickOS. Le séquenceur "joue" un plan de manière cyclique, une table étant générée statiquement pour décrire les dates et durées d'exécution des fonctions à exécuter dans le plan. Lorsque la construction d'un tel plan est faisable, il n'y a alors pas besoin de multitâche. Une seule tâche (le séquenceur) exécute les calculs en appelant les fonctions prévues dans le plan. Les fonctions devront nécessairement se terminer en un temps borné.

Développement du séquenceur

On utilisera par exemple les déclarations C suivantes pour décrire un plan statique :

#define TIME_UNIT 10 // Unité de temps (ms) servant à exprimer les durées et dates de démarrage

typedef struct {

time_t date_debut; // Date de démarrage de la tâche dans le cycle (en TIME_UNIT)

time_t WCET; // Durée d'exécution au pire-cas de la tâche (en TIME_UNIT)

void (*fonction)(void); // Fonction à exécuter

} schedule_elt_t;

typedef struct {

int nb_elt; // Nombre d'éléments par cycle

schedule_elt_t *schedule; // Tableau des tâches à exécuter dans un cycle

time_t t_cycle; // Durée du cycle (en TIME_UNIT)

} schedule_t;

Il est conseillé de ne pas définir de valeurs de TIME_UNIT inférieures à 10, à cause de l'activité système générée par BrickOS.

Écrire le code du séquenceur. Ce dernier sera composé d'une boucle infinie attendant la date prévue de démarrage de chaque fonction, puis l'appelant. On se servira de l'appel BrickOS get_system_up_time() pour récupérer le temps système (en ms) depuis le démarrage de BrickOS. Le séquenceur devra fonctionner quelle que soit la valeur de TIME_UNIT.

On pourra tester le séquenceur en lui faisant effectuer une action simple toutes les secondes (par exemple émettre un son).

Développement d'un programme de navigation (aléatoire)

Développer un programme réalisant quatre fonctions différentes, qui seront chacune codée dans une fonction C différente :

Les trois dernières fonctions communiquent leurs commandes de pilotage à la fonction contrôle_moteur en utilisant une variable partagée commande_pilotage. On utilisera par exemple le code C donné ci-dessous :

// Directions possibles du véhicule, à compléter si besoin

typedef enum dir_t {tourner_gauche, tourner_droite, avancer, reculer, arreter, inactif};

// Structure de donnée globale pour commander le véhicule */

struct commande_pilotage {

int privilege; // Privilège pour générer une commande de pilotage (voir ci-dessous)

dir_t direction; // Direction demandée pour le véhicule

int speed; // Vitesse demandée

time_t duree; // Durée (en TIME_UNIT) pendant laquelle on veut appliquer la commande

}

Pour éviter que les fonctions génèrent des commandes de pilotages contradictoires, on instaure un système de privilège entre les différentes fonctions pour la génération des commandes. La fonction ayant le plus de privilège pour générer une commande de pilotage sera eviter_obstacle, suivie de changer_direction puis avancer. Pour vérifier si l'on peut changer la structure de donnée globale, on pourra écrire une fonction changer_commande(int privilege, t_dir dir, int speed, time_t duree), qui changera la structure de donnée globale uniquement quand il n'existe pas de commande plus privilégiée en cours d'exploitation.

La fonction de contrôle moteur, à chacune de ses exécutions, modifiera la valeur du champ duree dans la commande de pilotage. Une fois ce champ nul, les moteurs seront arrêtés, le privilège de la commande sera positionnée à une valeur plancher, et la direction sera positionnée à inactif. Ainsi, les autres fonctions pourront générer de nouvelles commandes de pilotage.

Établir un plan statique cyclique non préemptif pour l'exécution des 4 fonctions. La fonction contrôle_moteur s'exécutera plusieurs fois par cycle.

Questions

Détection des dépassements d'échéance

Ajouter au programme précédent un test de dépassement d'échéances (l'échéance d'une fonction sera ici simplement la date de début de la fonction suivante dans le plan). On utilisera deux moyens complémentaires :


TP 3 : Ordonnancement préemptif à priorités

Une alternative à l'utilisation de plans statiques cycliques est d'utiliser un ordonnancement préemptif à priorités. Chacune des fonctions est alors une tâche, l'ordonnanceur de BrickOS se chargeant de leur attribuer le processeur (ordonnancement à priorité, avec partage de temps par time-slicing à priorité égale).

  1. Réimplanter le système du TP 2 en utilisant maintenant un ordonnancement préemptif à priorités. On utilisera la fonction execi pour la création de tâche, et on ne se souciera pas du dépassement d'échéance. A noter que les priorités des tâches dans BrickOS sont assignées à la création des tâches et ne peuvent pas être modifiées.
  2. Ajouter au système une tâche apériodique forçant le robot de suivre une ligne noire tracée au sol. Pour autoriser des changements de direction du robot, la ligne comportera de nombreux virages et croisements.

Questions


TP 4 : Le challenge

L'objectif de ce dernier TP est de réussir à relever un défi (voir ci-dessous). Vous pouvez proposer d'autres défis, sous réserve que :

Sauf objection, les épreuves seront ouvertes au public.

Mai 2004 (INSA, option STR) : Course de robots

On a une piste (créée par le prof) dont on donne les caractéristiques (largeur de la piste, rayon de courbure minimal des virages, nombre de croisements maximal). L'objectif est de faire deux tours de la piste le plus rapidement possible, et dans tous les cas en temps limité. Pour les sorties de piste, on mesurera la distance parcourue depuis le départ. Cette idée a été exploitée à l'INSA en 2004, voir quelques photos.

Avril 2006 (IFSIC, option STR) : Robot ménager

L'objectif est de "faire le ménage" dans une zone délimitée par un trait noir. Cinq objets, disposés aléatoirement dans la zone, devront être sortis de la zone par le robot, le plus rapidement possible. Un objet sera considéré comme sorti de la zone quand il n'aura aucune surface de contact avec la ligne qui délimite le territoire.

Descriptif de la zone et des objets

Contraintes sur le robot

Règles du jeu et appréciation des performances


Logistique


Liens utiles


Foire aux questions


Isabelle Puaut, dernière mise à jour en juillet 2004 (puaut@irisa.fr)