Enseignant: |
Jérôme Collin, responsable (local M-4013, poste 5060) |
|
Support technique supplémentaire: | Laurent Tremblay (local M-4011, poste 7181) | |
Chargés de laboratoire: | Section 1: |
Kais Fallouh (Lundi AM) Romain Lebbadi-Breteau (Mercredi PM) |
Section 2: |
Tristan Rioux (Mardi PM) Gaëtan Florio (Jeudi AM) |
|
Section 3: |
Luciano Garin-Iriarte (Lundi PM) Ely-Cheikh Abass (Jeudi PM) |
|
Section 4: |
Dorine Dantrun (Mardi AM) Meriam Ben Rabia (Vendredi AM) |
|
Section 5: |
Amélie Simard (Mercredi AM) Abdul-Wahab Chaarani (Vendredi PM) |
|
Section 6: |
Marc-Antoine Manningham (Mardi soir) Laurent Bourgon (Jeudi soir) |
INF1900
Projet initial de système embarqué
Travail pratique No. 9
Trajectoire préprogrammée
Objectif: Faire effectuer automatiquement des déplacements au robot
Durée: Une semaine exactement
Travail préparatoire: travail pratique no. 5 sur le RS-232 et la mémoire externe
Documents à remettre: |
Le travail pratique est matière à une entrevue de laboratoire à partir du mardi 25 mars durant les périodes de laboratoire. Un horaire est établi pour les entrevues. L'entrevue se fera par équipe de 4 (5 ou 6) étudiants avec un responsable de la partie technique. Durant l'entrevue, le robot devra effectuer une démonstration de son bon comportement devant l'évaluateur. Le code est aussi à placer sous Git avant l'entrevue. Une première évaluation par les pairs est également à rendre quelques jours avant. |
Présentation en classe: présentation PowerPoint.
«I am a very bottom-up thinker. If you give me the right kind of Tinker Toys, I can imagine the building. I can sit there and see primitives and recognize their power to build structures a half mile high, if only I had just one more to make it functionally complete. I can see those kinds of things» |
|
- |
Ken Thompson, un des développeurs du système d'exploitation Unix et du langage C. |
Introduction
Depuis le début de la session, la très grande majorité des exercices ont porté sur des aspects de la carte mère et du microcontrôleur. Le robot lui-même a peu bougé. Il est temps de passer à l'action! On le fera se déplacer pour qu'il suive une trajectoire préprogrammée inscrite en mémoire externe. De plus, ce laboratoire permettra de mettre à profit les notions introduites lors des travaux pratiques précédents.
Une bonne façon de revoir les concepts vus dans les semaines précédentes est de les utiliser de nouveau, mais dans un contexte plus général. Ce qui est proposé comme travail ressemble un peu à un interpréteur de commandes. Les instructions d'un interpréteur de commande sont directement exécutées. Des exemples connus d'interpréteurs de commandes sont Bash (Linux, Mac), PowerShell (Windows) et aussi... Python!
Ici, nous procéderons un peu différemment. Les instructions seront plutôt compilées sur le PC pour produire un pseudo-code binaire (bytecode en anglais). Il s'agit d'octets qui ne peuvent pas être exécutés directement par un processeur, mais qui sont dans un format qui permet une interprétation plus facile puisque les analyses lexicale et syntaxique (parsing) du fichier source sont déjà réalisées. Généralement, ce format est indépendant du matériel et est sous une forme qui est difficile à lire pour l'être humain. Un programme en langage Java passe par un pseudo-code binaire lors de son exécution. Le résultat plus compact d'un pseudo-code binaire par rapport au code source d'origine a cependant des avantages en vitesse à l'exécution, pour le web par exemple avec le JavaScript.
Notre pseudo-code binaire sera inscrit dans la mémoire I2C externe du robot. Le ATmega324PA devra le lire et comprendre la signification des octets pour arriver à faire bouger le robot selon ce qui y est inscrit. Le robot ne fait donc pas l'interprétation directe des instructions d'un fichier source ou d'un interpréteur de commandes, mais d'une liste d'octets encodés ayant une signification équivalente.
Passer par un langage spécialisé pour programmer un robot est assez courant. La société FANUC a opté pour cette approche avec le langage Karel un peu différent de l'original. Cette approche permet le contrôle du robot, mais aussi la simulation et la vérification des opérations prévues pour le robot.
Lors du travail pratique 5, des données ont été lues mémoire. La mémoire contenait alors des données. Elle devra maintenant contenir des instructions à exécuter. Les procédures d'accès à la mémoire seront réutilisées ici, mais dans un contexte un peu différent puisqu'elles auront un effet direct sur les mouvements du robot.
Les paragraphes suivants décrivent les instructions et leur équivalent en pseudo-code binaire. Quelques détails sur la façon de les compiler sur le PC sont aussi fournis.
Instructions
Les commandes forment un langage très simple qui ressemble un peu à un assembleur. Les différentes commandes que vous aurez à considérer sont présentées sous la forme d'instructions binaires au tableau 1.
Instruction binaire |
mnémonique |
Description |
---|---|---|
0000 0001 |
dbt |
début |
0000 0010 |
att |
attendre |
0100 0100 |
dal |
allumer la DEL |
0100 0101 |
det |
éteindre la DEL |
0100 1000 |
sgo |
jouer une sonorité |
0000 1001 |
sar |
arrêter de jouer la sonorité |
0110 0000 |
mar |
arrêter les moteurs |
0110 0001 |
mar |
arrêter les moteurs |
0110 0010 |
mav |
avancer |
0110 0011 |
mre |
reculer |
0110 0100 |
trd |
tourner à droite |
0110 0101 |
trg |
tourner à gauche |
1100 0000 |
dbc |
début de boucle |
1100 0001 |
fbc |
fin de boucle |
1111 1111 |
fin |
fin |
Tableau 1: Jeu d'instructions du robot
On peut prendre un éditeur pour écrire un programme dans ce langage tout comme on le fait pour un programme en C/C++. Vous pouvez appeler le compilateur «progmem» sur votre machine Linux pour le compiler de la façon suivante pour produire un fichier de sortie contenant le pseudo-code binaire:
% progmem [-v] -o «fichierDeSortie» «fichierDentree»
Comme en C/C++, les instructions doivent être terminées par un point-virgule. Une instruction doit être écrite soit entièrement en minuscule, soit entièrement en majuscule, mais sans combinaison des deux. Un opérande ayant une valeur entre 0 et 255 peut suivre le terme mnémonique si l'instruction le prévoit. Les symboles %, # et // permettent d'introduire un commentaire sur la ligne. Voici un fichier qui donne un exemple de programme. Ce fichier contient des erreurs. Quand il y a des erreurs, le fichier de sortie n'est pas produit. Un bon exercice pourrait être d'enlever les lignes provoquant les erreurs pour voir comment faire une première compilation et de comprendre les instructions dont les détails sont donnés à la section suivante. L'option -v du programme progmem vous donne plus de détails sur l'opération de production du pseudo-code binaire (très utile).
Pseudo-code binaire (bytecode)
Le pseudo-code binaire sera organisé selon un format uniforme afin de faciliter sa lecture en mémoire. Une instruction est sous forme binaire et comprend 8 bits. Une instruction est toujours suivie d'un opérande de 8 bits. Cet opérande n'est pas significatif si l'instruction n'en prévoit pas. Néanmoins, le fait de le placer dans un format binaire rend l'organisation des octets plus uniforme. Autrement dit, les instructions sont aux adresses paires en mémoire alors que les opérandes (significatifs ou non) sont aux adresses impaires.
Instruction (obligatoire) (8 bits) |
Opérande (obligatoire) (8 bits) |
Tableau 2: Format des instructions du pseudo-code binaire
La seule exception à cette organisation est pour les deux premiers octets qui forment une donnée de 16 bits. Cette valeur donne le nombre d'octets total du pseudo-code binaire. Par exemple, s'il y a 8 instructions de code source, le fichier binaire aura une taille de 18 octets au total et la lecture des deux premiers octets permet d'obtenir cette information.
Il est toujours possible de consulter les octets du fichier de sortie en pseudo-code binaire avec la commande Linux suivante:
% od -v -t x1 «fichierDeSortie»
Description des instructions
Voici une description complète des instructions illustrées à l'aide d'exemples.
Début
Mnémonique: dbt
Code binaire: 0x01
Description: Indique le début du code. Le programme commence ici (et pas avant).
Opérande: non
Exemple:
att 25 ;# ne sera pas exécuté
dal 2 ;% ne sera pas exécuté
dbt ;# début de l'exécution
att 10 ;# attendre 250 ms
Attendre
Mnémonique: att
Code binaire: 0x02
Description: attendre 25 ms fois la valeur de l'opérande
Opérande: oui
Exemple:
att 25 ;# ne sera pas exécuté
dal 2 ;% ne sera pas exécuté
dbt ;# début
att 10 ;// attendre 250 ms (instruction exécutée)
Allumer les DEL
Mnémonique: dal
Code binaire: 0x44
Description: allumer les DEL en vert ou en rouge selon la valeur de l’opérande (1 pour le vert, 2 pour le rouge. Si l’opérande est autre que 1 ou 2, l'opérande est ignoré et rien ne change.
Opérande: oui
Exemple:
dal 1 ;# allumer la DEL en vert
dal 2 ;# allumer la DEL en rouge
dal 2 ;// ne fera rien puisque la DEL est déjà en rouge
dal 0 ;# ne fera rien, peu importe la situation
Éteindre les DEL
Mnémonique: det
Code binaire: 0x45
Description: éteindre la DEL directement.
Opérande: non
Exemple:
dal 1 ;# DEL en vert
det ;// éteindre la DEL
det ;# instruction sans effet puisque rien n’est allumé
Jouer une sonorité
Mnémonique: sgo
Code binaire: 0x48
Description: jouer une sonorité du tableau 3. Il faut activer une sortie en mode PWM avec la fréquence donnée dans le tableau. Si la valeur n'est pas dans le tableau, la commande est ignorée.
Opérande: oui
Exemple:
sgo 69 ;# émettre un son à 440 Hz
sgo 200 ;# instruction ignorée
sgo 45 ;// émettre un son à 110 Hz
Arrêter de jouer la sonorité
Mnémonique: sar
Code binaire: 0x09
Description: arrêter de jouer la sonorité en cours (s'il y en a une qui joue).
Opérande: non
Exemple:
sgo 54 ;% jouer un son à 180 Hz
sar ;# arrêter de jouer un son
sar ;# instruction sans effet
Arrêter les moteurs
Mnémonique: mar
Code binaire: 0x60 ou 0x61
Description: arrêter les deux moteurs
Opérande: non
Exemple:
...
mar ;# Arrêter
mar ;// instruction sans effet
...
Avancer
Mnémonique: mav
Code binaire: 0x62
Description: avancer en ligne droite à une vitesse donnée par (opérande / 255 * 100%)
Opérande: oui
Exemple:
mar ;# Le robot est immobile
mav 0 ;% Le robot reste immobile
mav 255 ;# vitesse de 100%
mav 128 ;# vitesse de 50% (50% du PWM)
Reculer
Mnémonique: mre
Code binaire: 0x63
Description: reculer en ligne droite à la vitesse (opérande / 255 * 100%)
Opérande: oui
Exemple:
mar ;# moteurs ne tournent pas
mre 0 ;// robot reste immobile
mre 255 ;# vitesse maximale vers l'arrière
mre 64 ;# vitesse de 25% vers l'arrière (25% du PWM)
Tourner à droite
Mnémonique: trd
Code binaire: 0x64
Description: virage du robot de 90 degrés à droite
Opérande: non
Tourner à gauche
Mnémonique: trg
Code binaire: 0x65
Description: virage du robot de 90 degrés à gauche
Opérande: non
Début de boucle
Mnémonique: dbc
Code binaire: 0xC0
Description: emmagasiner l'adresse du présent point d'exécution du code dans une variable pour pouvoir y revenir. De plus, créer une variable qui conservera l'état du compteur de boucle. La boucle s'exécutera une fois de plus que la valeur précisée par l'opérande. Donc, si l'opérande est zéro, le code ne s'exécutera qu'une seule fois. Il ne peut y avoir deux boucles imbriquées (actives au même moment).
Opérande: oui
Exemple: voir l'instruction «fin de boucle» pour un exemple
Fin de boucle
Mnémonique: fbc
Code binaire: 0xC1
Description: si le compteur n'est pas égal à 0, retourner à l'adresse de début de boucle et décrémenter le compteur de boucle. Sinon, ne rien faire.
Opérande: non
Exemple:
...
dbc 100 ;// la boucle s'exécutera 101 fois
dal 1 ;# allumer la DEL en vert
att 1 ;# attendre 25 ms
det ;// éteindre la DEL
att 1 ;# attendre 25 ms
fbc ;# boucler à l'instruction dbc précédente
...
dbc 0 ;# faire le code suivant une fois
dal 2 ;% allumer la DEL en rouge
att 1 ;# attendre 25 ms
det 1 ;% éteindre la DEL
att 1 ;# attendre 25 ms
fbc ;// boucler à l'instruction dbc précédente
...
Fin
Mnémonique: fin
Code binaire: 0xFF
Description: fin de l'exécution du code. Le code qui suit cette instruction sera ignoré. Aucun son ne sera émis après cette instruction et le robot s'arrêtera également.
Opérande: non
Exemple:
att 25 ;# attendre 625 ms
fin ;% fin du programme et robot immobile
att 25 ;# instruction qui ne sera même pas lue
Fréquences des notes MIDI
Si vous êtes musicien, vous pouvez relier la fréquence d'un signal PWM et les notes d'une chanson pour rendre le comportement de votre robot plus agréable. Si vos connaissances en musique sont plus limitées, votre robot devra se contenter d'émettre des sons quelconques. Cette remarque n'a aucune conséquence sur quelque forme d'évaluation que ce soit. Par contre, il est toujours bon de connaître la relation entre la fréquence d'un signal et les notes de musique. Plus d'informations sont disponibles sur Wikipédia pour l'interface MIDI, et le cycle des notes. Voici un tableau des notes MIDI et des fréquences correspondantes.
Note (donnée) |
Fréquence (en Hz) |
Période (en ms) |
Temps actif (en ms) |
---|---|---|---|
45 |
110 |
9.09 |
4.545 |
46 |
116.54 |
8.58 |
4.290 |
47 |
123.47 |
8.10 |
4.050 |
48 |
130.81 |
7.64 |
3.822 |
49 |
138.59 |
7.22 |
3.608 |
50 |
146.83 |
6.81 |
3.405 |
51 |
155.56 |
6.43 |
3.214 |
52 |
164.81 |
6.07 |
3.034 |
53 |
174.61 |
5.73 |
2.863 |
54 |
185.00 |
5.41 |
2.703 |
55 |
196.00 |
5.10 |
2.551 |
56 |
207.65 |
4.82 |
2.408 |
57 |
220 |
4.55 |
2.273 |
58 |
233.08 |
4.29 |
2.145 |
59 |
246.94 |
4.06 |
2.025 |
60 |
261.63 |
3.82 |
1.911 |
61 |
277.18 |
3.61 |
1.804 |
62 |
293.66 |
3.41 |
1.703 |
63 |
311.13 |
3.21 |
1.607 |
64 |
329.63 |
3.03 |
1.517 |
65 |
349.23 |
2.86 |
1.432 |
66 |
369.99 |
2.70 |
1.351 |
67 |
392.00 |
2.55 |
1.276 |
68 |
415.30 |
2.41 |
1.204 |
69 |
440 |
2.27 |
1.136 |
70 |
466.16 |
2.15 |
1.073 |
71 |
493.88 |
2.02 |
1.012 |
72 |
523.25 |
1.91 |
0.956 |
73 |
554.37 |
1.80 |
0.902 |
74 |
587.33 |
1.70 |
0.851 |
75 |
622.25 |
1.61 |
0.804 |
76 |
659.26 |
1.52 |
0.758 |
77 |
698.46 |
1.43 |
0.716 |
78 |
739.99 |
1.35 |
0.676 |
79 |
783.99 |
1.28 |
0.638 |
80 |
830.61 |
1.20 |
0.602 |
81 |
880 |
1.14 |
0.568 |
source: https://www.inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies
Tableau 3: fréquences des notes MIDI
Travail à effectuer
Le travail à faire est en deux parties. Il faut d'abord écrire le code qui permet au robot de lire le bytecode en mémoire externe et de l'interpréter correctement, instruction par instruction. Le problème se découpe bien et le travail peut être réparti de façon à ce que chacun des membres de l'équipe puisse contribuer à l'architecture du code autant qu'à la programmation.
Nous vous suggérons quelques trucs pour la mise au point des systèmes logiciels et matériels. Ces conseils vous seront fort utiles puisque la quantité de code à écrire augmentera d'ici la fin de la session.
Avant d'effectuer l'interprétation proprement dite, il serait souhaitable que le robot effectue une petite séquence de démarrage. Ce peut être, par exemple, de faire clignoter la DEL 2 fois rouge et 2 fois vert au départ. De cette façon, on sait que le robot a démarré et qu'il est dans une phase connue très rapidement. Quand les piles sont faibles ou qu'il y a un problème sérieux, on peut le réaliser tout de suite si le robot ne traverse même pas sa séquence de démarrage.
Une deuxième partie consiste à écrire des instructions dans le langage présenté plus haut, de les compiler avec progmem sur le PC, et de les charger en mémoire externe sur la carte mère. Vous êtes libre d'écrire les instructions que vous désirez. Par contre, chaque instruction doit être utilisée au moins une fois. Essayez d'écrire un ensemble d'instructions qui donne une belle chorégraphie à votre robot!
Il vous faudra utiliser l'interface RS-232 pour écrire votre bytecode en mémoire en écrivant un petit programme utilitaire pour effectuer cette tâche. Ce programme d'écriture est donc différent de celui qui ira lire les octets en mémoire. Il faudra peut-être ajuster quelque peu le code inscrit pour le problème 3 de la semaine 5 pour supporter le transfert des octets à charger en mémoire du PC vers la carte. Normalement, ce travail devrait se faire facilement en rajoutant une routine de transfert. Vous n'aurez qu'à ajuster la configuration du périphérique interne de l'AVR pour permettre la réception. Le programme serieViaUSB peut être appelé pour transmettre le bytecode vers la carte par RS-232 via le câble USB avec la commande suivante:
% serieViaUSB -e -f «fichierDeSortie»
Il peut être utile d’invoquer également la commande serieViaUSB avec l’option -h pour découvrir d’autres options possibles avec cette commande. C’est d’ailleurs une bonne habitude à prendre avec bien des commandes Linux puisque la majorité d’entre elles offrent une description de son fonctionnement et diverses options possibles pour modifier son exécution.
Il faudra charger le fichier de sortie complet en mémoire externe (les instructions utilisées autant que celles inutilisées et les deux premiers octets qui donnent la dimension du programme). Une fois le fichier de sortie inscrit en mémoire externe sur la carte, il faudra charger le programme de lecture et d'interprétation des octets en mémoire. Il faudra peut-être osciller quelques fois entre ces deux programmes à charger dans le ATmega324PA lors de la mise au point. Il s'agit d'un inconvénient qui peut être un peu gênant. Par contre, les combiner en un seul programme n'est pas évident (bien que possible) mais est proscrit pour cet exercice. Il faut donc écrire deux programmes différents.
Les derniers détails concernent les sonorités à jouer. Il faudra brancher une sortie PWM au fil rouge du piézoélectrique de votre robot. Le fil noir devra être connecté à une broche adjacente qu'il faudra configurer en sortie à la valeur constante de zéro volt. C'est une façon d’obtenir une mise à la masse sur ce fil. Il est à noter que les fils rouge et noir pourraient être inversés. Le piézoélectrique n'a pas réellement de polarité. Cependant, puisque la carte mère sera bientôt passablement garnie de fils, il est souhaitable de conserver un peu d'ordre dans les couleurs. Autre petit détail important. Il est vrai qu'il faut un signal ayant une forme PWM pour générer un son en sortie. Par contre, le mode CTC d'une minuterie peut être utilisé pour générer cette onde. Ce mode d'opération est différent de celui utilisé pour faire fonctionner les moteurs qui était (et est toujours) le mode PWM. On notera aussi qu'il devrait être possible de jouer une sonorité pendant que le robot se déplace. Il devrait être possible dans la documentation de Atmel de trouver une relation liant la fréquence de PWM à générer et les paramètres à ajuster dans la minuterie, dont la valeur de comparaison maximale à atteindre (TOP).
Aussi, comme vous avez progressé significativement dans le cours corequis INF1015, on vous demande d’avoir quelques classes pour ce travail pratique. Il n’est pas obligatoire d’avoir tout en orienté objet, mais il serait intéressant pour vous de regrouper quelques fonctions-membres avec des données sur lesquelles elles opèrent pour former quelques classes simples et tirer avantage de ce paradigme de programmation dans le code plus long à écrire pour ce travail pratique. Ceci devrait aussi faciliter la répartition du code en quelques fichiers et permettre une meilleure répartition du travail à effectuer entre les membres de l’équipe. Deux ou trois classes peuvent amplement suffirent.
Enfin, il est tout fait naturel d’utiliser la librairie développée au travail pratique 7 et aussi d’utiliser le mécanisme de débogage mis en place au travail pratique 8 pour continuer à améliorer ses pratiques de développement logiciel. Si vous ne voulez pas toucher au code du répertoire du travail pratique 7 qui a été soumis pour correction, vous pouvez le recopier dans le répertoire pour le travail pratique 9. Vous pourrez aussi continuer d’ajouter un peu de code au besoin à votre librairie ici tout en ayant la paix d’esprit de savoir que ces modifications n’auront pas d’impact sur la correction du travail pratique 7.
Dans SimulIDE
Certaines parties du code peuvent être développées dans SimulIDE pour ce travail pratique, mais les limites avec la mémoire externe mentionnées au travail pratique 5 restent présentes. De plus, le chargement d’octets vers le EEPROM interne du ATmega324 est quelque peu compliqué avec l’interface graphique avec le RS232 de SimulIDE. On peut contourner ce problème en utilisant l’interface RS232 vers un vrai port du PC de SimulIDE, mais il faut utiliser des commandes Linux un peu exotiques pour y parvenir. On perd aussi un peu le sens du travail à réaliser. Aussi, comme le robot bouge et s’anime en fonction du peudo-code binaire, il est vraiment plus agréable de travailler avec le vrai robot pour le travail pratique. Cette remarque restera tout aussi vraie pour le projet final d’ailleurs.
Qualité du code
Vous vous rendrez compte que le code à écrire nécessite des boucles et des tests en tout genre. La règle 54 sur les instructions break et continue est à regarder. Celles sur les instructions conditionnelles de 56 à 59 également. Assez naturellement, pour mieux respecter les règles précédentes, revoir l’usage des espaces blancs (règles de 77 à 82) pour augmenter la lisibilité s’impose.
Suivi et remise (IMPORTANT)
Pour la semaine prochaine, avant l'entrevue de laboratoire:
Avoir un robot fonctionnel pour l'entrevue de laboratoire avec piles et totalement autonome.
Avoir rempli le formulaire d'évaluation par les pairs si ce n'est pas déjà fait. La date limite est le vendredi 21 mars, 23:59 sur Moodle pour donner un temps au correcteur de les revoir avant l’entrevue.
Avoir envoyé un nom de robot par courriel au responsable du cours.
Votre code placé sous Git dans le répertoire https://githost.gi.polymtl.ca/git/inf1900-WXYZ/tp/tp9/
Par principe d'équité, il ne sera plus possible de déposer une nouvelle version du code dans l'entrepôt Git après le début des entrevues. L'heure de l'entrevue de la première équipe (toutes sections confondues) dans l'horaire fixe l'heure limite du dernier dépôt dans l'entrepôt pour toutes les équipes du cours. Donc, le mardi 25 mars 8h00 AM maximum.