Nous détaillerons bientôt le programme de la Coupe de France, mais faisons une introduction en douceur en présentant le programme de démo utilisé pour la Fête de la Science 2008.
Le robot évoluera sur un terrain différent : il aura des dimensions réduites (1,15 mètre sur 2,37 mètres) et ne comportera qu’un seul distributeur de balles situé au milieu du bord court.
Il n’y aura aucune balle de floorball sur le terrain et les balles de couleur rouge, blanche ou bleu récupérées dans le distributeur devront être envoyées dans des paniers de l’autre côté du terrain.
Nos démonstrations durent plusieurs journées sans interruption. Il est donc intéressant de supprimer l’arrêt automatique du robot pour qu’il soit autonome et effectue des cycles de démo toutes les minutes.
Préparation
Avant de commencer à coder, il faut réunir toutes les informations nécessaires :
– le référentiel utilisé : axes et angles
– les dimensions du robot
– la stratégie à implémenter
Référentiel géométrique
Comme d’habitude, nous choisirons un repère orthonormé direct. L’unité sera le millimètre (mm). L’axe des X suit le petit côté tandis que l’axe des Y suivra les grand côtés.
Le choix de l’origine est particulier. Ce ne sera pas comme d’habitude le centre du terrain (ce qui est intéressant pour les symétries)
Nous utilisons deux angles sur le robot : la direction du robot et l’angle de rotation à exécuter. Dans les deux cas, l’utilisation d’un repère orthonormé direct définit le signe des angles : positif dans le sens trigonométrique (de l’axe X vers l’axe Y ou encore anti-horaire ou CCW, counter-clock-wise).
Les dimensions du robot
Le robot est lui-même. Nous effectuerons des mesures permettant de définir la distance séparant chacun des bords du robot du centre de rotation. En effet, la position du robot sur le terrain est celle de son centre de rotation, ce qui permet de garder les mêmes coordonnées lorsque le robot tourne sur lui-même. Bien entendu ce n’est qu’une convention et il aurait été possible de définir un autre système de coordonnées (comme le centre de la pince ou celui du lanceur de balles).
La stratégie à implémenter
Notre démonstration va consister à faire des déplacements typiques d’un robot de Coupe :
- manipulation d’objets : prise d’une balle et lancement
- déplacements précis : "docking" (accostage d’un distributeur)
- recalage sur un mur
La stratégie consiste à montrer en un minimum de temps (suffisant pour pouvoir faire des explications à voix haute au public, ce qui expliquera la vitesse relative du robot... *rires*) toutes ses possibilités, en attrapant les balles du distributeur et les trier rouge, blanc et bleu dans les paniers, en effectuant une identification de la couleur, un déplacement jusqu’au panier et un tir balistique.
Le déroulement des opérations est donc le suivant :
- démarrer le robot
- avancer et se recaler sur un mur
- approcher le distributeur et accoster
- prendre une balle
- si une balle est là, en prendre une seconde
- si aucune balle n’a été attrapée, retenter
- si toujours aucune balle, revenir à la position de départ et attendre 1 minute
- si le robot a au moins une balle (pas de test de la seconde possible), parcourir le terrain vers les paniers
- analyser la couleur et s’orienter selon le panier à viser
- lancer la balle dans le bon panier
- revenir à la position de départ et attendre une minute
Il s’agit ici de ce qu’il faut faire, pas comment le faire. Chacune de ces opérations va donc être décomposée pour utiliser les véritables opérations du robot. On passe alors à la phase de réalisation. Mais avant, un rappel du fonctionnement de nos programmes pour robots.
++++
Principe de programmation
Une machine à état gère les différentes étapes de la stratégie à l’intérieur d’une boucle continue. C’est-à-dire qu’un certain nombre d’opérations sont exécutées très régulièrement (toutes les 50 ms) pour gérer l’acquisition des capteurs, la commande en vitesse des moteurs et la gestion des servomoteurs, et la boucle se termine par l’évaluation de l’état en cours dans la stratégie : déterminer l’action à exécuter et envisager de passer à l’état suivant.
Cette machine à état est totalement linéaire : lorsque la condition de fin d’état est réunie, un compteur est incrémenté et on passe à l’état/commande suivant.
Tout le déroulement du match est donc déterministe, ce qui rend le fonctionnement du robot très simpliste mais rudement efficace. C’est déjà rudement complexe à gérer et n’empêche pas de se creuser la tête.
Donc vous l’aurez deviné, l’implémentation de la stratégie va ressembler beaucoup à la liste d’opérations décrite ci-dessus, et notre travail va consister à une simple décomposition en états/commandes élémentaires.
Il y a trois possibilités d’action pour chaque commande, selon qu’on veut agir lorsqu’on entre dans l’état, pendant qu’on est dans l’état (l’action décrite va se répéter à chaque tour de boucle) ou quand la condition de sortie est atteinte.
Les commandes disponibles
Commande | Action initiale | Action en boucle | Condition de sortie | Action de sortie |
---|---|---|---|---|
START | rien | rien | interrupteur "jack" de départ retiré | mettre à 0 le chrono des secondes |
WAIT | armer un compteur, si demandé passer la vitesse à 0 | rien | temps d’attente atteint | rien |
END | couper les moteurs | rien | aucune | rien |
ENA_MOT | activer les moteurs | rien | tout de suite | rien |
DIS_MOT | couper les moteurs | rien | tout de suite | rien |
PINCE_O | ouvrir la pince | rien | tout de suite | rien |
PINCE_F | fermer la pince | rien | tout de suite | rien |
DOCK | positionner les consignes de vitesses | couper le moteur correspondant au côté atteint en premier | les deux interrupteurs sont en contact avec le mur | rien |
GOTO | faire passer l’index du tableau des commandes à l’index passé en consigne (avant ou après) | rien | tout de suite | rien |
MOVE_X | rien | appeler l’algorithme turn & go | la coordonnée passée en paramètre est atteinte | rien |
MOVE_Y | rien | appeler l’algorithme turn & go | la coordonnée passée en paramètre est atteinte | rien |
MOVE_CAP | rien | appeler l’algorithme turn & go | la coordonnée passée en paramètre est atteinte | rien |
MOVE_POS | rien | appeler l’algorithme de logique floue | la position X,Y,cap est atteinte | rien |
MOVE_SEC | positionner les consignes de vitesse et armer le chrono | rien | le compteur a atteint la consigne de temps d’attente | rien |
Comme vous le remarquez, il n’y a pas toujours d’attente, ce qui signifie qu’on va entamer la consigne suivante sans attendre que l’action soit terminée. C’est utile pour la pince (elle va s’ouvrir ou se fermer alors qu’on est déjà en mouvement) mais il faut bien l’avoir en tête et intercaler des WAIT quand on a besoin de temporiser suffisament pour laisser le temps à l’action précédente de se terminer.
Les modifications à apporter
Nous n’utiliserons pas le jack de départ, il ne faudra donc pas utiliser la commande START, mais pas besoin de la modifier. On utilisera une opération hors de la machine à état pour enregistrer les coordonnées du robot (ce point sera détaillé ultérieurement).
Il va falloir modifier la commande DOCK : en effet, le recalage sur le bord sert à remettre à niveau la coordonnnée correspondant à l’axe atteint. Comme l’origine choisie pour cette démo diffère de l’origine du terrain de la Coupe, la coordonnée à enregistrer lorsqu’on est au contact est différente.
Les suppléments à ajouter
Il faut créer de nouvelles actions pour l’utilisation de la turbine. L’ensemble "turbine + servo" est autonome : une électronique dédiée assure le pilotage du moteur de la turbine et l’asservissement en position du servomoteur qui permet de la faire pivoter. Le programme principal va donc échanger avec cette carte pour commander l’une des 4 positions possibles :
Commande | Description |
---|---|
TURB_OFF | turbine au repos |
TURB_ASPI | turbine en aspiration |
TURB_PRET | s’aligner avec l’entrée du lanceur |
TURB_LANCE | passage de la balle au lanceur |
De la même manière, le lanceur a une électronique de contrôle des moteurs CC qui utilise une communication très simple pour recevoir ses ordres
Commande | Description |
---|---|
LANCE_ON | allumer les moteurs |
LANCE_OFF | éteindre les moteurs |
Avant de pouvoir lancer une balle, il faut attendre une demi-seconde. On laissera ce choix à la stratégie, selon qu’on intercale un WAIT après le LANCE_ON ou bien qu’on utilise un déplacement (MOVE_...) pour gérer ce temps de mise en route.
Dans ces deux cas (turbine ou lanceur), le code à développer est simple. Concernant la machine à état, on reprendra l’exemple de la pince (une action au premier tour puis passage direct à l’état suivant). Pour la communication, des lignes de sortie sur les ports numériques de la carte principale sont reliées aux cartes électroniques dédiées. Il suffit donc de mettre à 1 ou à 0 les pattes correspondantes.
Exemple de code :
int main()
// initialisation des ports
// sbi = set bit = niveau haut = 1 sur la patte demandée
// DDR = Direction Data Register
// DDRB = registre DDR du port B
// 0 ou 1 signifie la patte 0 ou 1 de ce port
sbi(DDRB,0) ;
sbi(DDRB,1) ;
while (1)
...
// appels aux différentes commandes
// par exemple "turbine off"
cbi(PORTB,0) ;
cbi(PORTB,1) ;
...
// par exemple "turbine lance"
sbi(PORTB,0) ;
sbi(PORTB,1) ;
Une question subsiste : faut-il le faire en même temps (et l’Atmel le fait-il ainsi) ou bien peut-on faire suivre deux commandes cbi ou sbi ?