IMA4 2017/2018 P66 : Différence entre versions

De Wiki de Projets IMA
(Vue d'ensemble du FPGA)
(Semaine 7)
Ligne 868 : Ligne 868 :
  
 
'''TODO Exporter Communication.xml en PDF et le convertir en SVG'''
 
'''TODO Exporter Communication.xml en PDF et le convertir en SVG'''
 +
 +
==Semaine 8==
 +
 +
===Carte de puissance 24V===
 +
 +
Nous avons pu tester notre composant de puissance 24V, nous avons ainsi pu noter que :
 +
le composant est capable de délivrer un 24V continu on note un décrochage à 8,5V et une tension d'accrochage à 9V.
 +
Certaines fonctionnalités des pins Sense et du ON/OFF ont été vérifiée à l'aide d'un potentiomètre mais nous n'en aurons pas l'usage. Cependant pour respecter le choix du client nous garderons toutes les pins disponibles pour assurer la modularité du composant à long terme.
 +
Plusieurs modifications doivent donc être ajoutées au design du PCB.
  
 
=Documents Rendus=
 
=Documents Rendus=

Version du 12 mars 2018 à 17:32

Sommaire


Présentation générale

IMA4-1718-P68-illu.png

Description

La coupe de France de robotique est un événement où des équipes doivent créer un robot autonome afin de réaliser un maximum de tâches données au préalable dans un cahier des charges. Pour ce projet, nous nous concentrerons sur la réalisation de sa base mobile lui permettant de se déplacer ainsi que son “cerveau” qui lui permettra de le contrôler.

Objectifs

Analyse du projet

Positionnement par rapport à l'existant

On se limitera pour cette comparaison aux robots qui visent le même but que le nôtre (à terme) : marquer des points pour les matchs de la coupe de France de robotique. En effet, la robotique est omniprésente dans nos vies maintenant, et il y a un nombre incalculable de bases mobiles existantes, avec différentes caractéristiques : avec des moteurs pas à pas, asservies, rapides, puissantes, capables de se déplacer sur différents terrains… Et ne parlons pas des systèmes de contrôles.

Il y a approximativement 200 participants à l'événement, et donc presque autant de systèmes similaires au notre développés ou en train d’être développés. Cependant leur détails de conceptions sont jalousement gardés par les équipes. On fera donc notre études sur les robots de l’année dernière. On prendra le robot fait par Robotech Lille et celui fait par une autre équipe finaliste, Robotech Legends.

Analyse du premier concurrent

Le robot de l'année dernière en situation

Pour progresser il faut apprendre de ses erreurs. C’est pourquoi regarder en quoi le robot de l’année dernière n’a pas été un franc succès nous paraît judicieux pour pouvoir faire quelques chose de plus performant cette année.

L’erreur qui nous avait été fatale l’année dernière était le manque de qualité du contrôleur moteur. Réalisé avec la graveuse numérique de Polytech et non verni, son ancienneté aura eu raison de lui. De plus, on peut constater quelques défauts d’optimisation : le driver L298 sur la carte peut supporter le contrôle de deux moteurs mais n’en contrôle qu’un seul à la fois. La fonction de freinage est rendue inaccessible par le design de la carte. La solution que nous proposons est simple : créer une nouvelle carte, qui sera vernie pour pouvoir tenir plusieurs coupes.

La carte de puissance avait été réalisée de la même façon, et était beaucoup plus grande que nécessaire. Elle risque de d’avoir le même sort que son congénère. La solution que nous proposons est la même que précédemment, refaire une nouvelle carte plus optimisée et vernie.

L’asservissement en position du robot était aussi dérisoire (heureusement, nous n’avions pas eu à l’utiliser). Seule un encodeur sur deux était utilisé, et seule une des deux sorties de l’encodeur était considérée. De plus le fonctionnement de l’Arduino récupérant les données pouvait parfois faire en sorte qu’un front pouvait être négligé. Pour pallier à ça, on utilisera un FPGA, qui permettra de faire tourner autant de processus en simultané que l’on désire sans qu’ils n’interfèrent entre eux.

De plus, l’utilisation seule des encodeurs n’autorise pas les dérapages (même légers). Pour pallier à ça, on utilisera une centrale inertielle comme seconde source pour récupérer la position du robot.

Enfin, un souci assez récurrent que l’on a rencontré est la difficulté à modifier un programme dans un des processeurs du robot. Il fallait pour cela rapprocher son ordinateur du robot, déplacer la carte de son logement, et la brancher (en prenant le risque de déloger un autre composant au passage). Pour améliorer le processus, on fera en sorte que le Raspberry Pi puisse être mis à jour via une communication sans fil et puisse mettre à jour les autres cartes (Arduino, FPGA) à son tour. Cela permettra d’éviter de perdre du temps à rebrancher des composants.

On remarquera que le choix du matériel n’étais pas tellement un problème l’année dernière, ce dernier se situant plutôt de la manière dont il a été utilisé. C’est pourquoi on peut se permettre d’améliorer sans pour autant trop changer ce qui nous est disponible au départ.

Analyse du second concurrent

Regardons désormais ce qui se fait chez le voisin. Nous avons choisi cette équipe parce qu’elle nous a parlé des méthodes qu’elle a utilisé tout en faisant un bon score.

Cette équipe utilisait un moteur pas à pas afin d’éviter d’avoir à utiliser des encodeurs. Cependant, le caractère discret de la rotation du moteur rajoute un phénomène de glissement, qu’il est difficilement possible de calculer. Pour réduire ce phénomène, nous utilisons des moteurs à courant continu, et nous récupérons leur rotation à l’aide d’encodeurs. Un régulateur PID permet alors de réduire les variations de vitesse trop brusques.

Ils avaient un système de LEDs pour pouvoir savoir où en était le robot dans son programme, et ainsi faciliter le débogage des programmes. Pour reprendre ce principe et l’améliorer, on enregistrera toutes les informations que le système puisse obtenir, et on les transmet par liaison sans fil pour un débogage encore plus simple.

Enfin, ils utilisaient des microcontrôleurs STMicroelectronics pour tout le contrôle du robot. Bien que ces cartes soient très puissantes, elles embarquent un système d’exploitation multi-tâches. Cela simplifie énormément l’étape de programmation, cependant le multi-tâche rajoute de la latence pour les entrées sorties, et perd donc en précision. À la place, nous utiliserons trois puces (deux micro-contrôleurs et un FPGA) plus ou moins complexes parfaitement adaptées à leur tâche. On pourra aussi se vanter d’avoir un robot totalement open-source. Ces puces seront chargées avec le strict minimum pour répondre aux contraintes du cahier des charges, ni plus, ni moins.

Certes, certaines de ces “améliorations” ne sont pas nécessaires pour l’accomplissement du cahier des charges et/ou du défi. Les autres méthodes que nous n’utilisons pas peuvent être “suffisantes”, preuve en est, cette équipe est arrivée en finale alors que d’autres équipes avec des techniques similaires aux nôtres sont arrivées bien plus bas. Mais où est le challenge si on se contente du fait que ça fonctionne ?

Scénario d'usage du produit ou du concept envisagé

Notre robot (vue d'artiste)

Le scénario d’usage voulu serait de jouer et de remporter un match de la coupe de robotique. Cependant, cela ne pourra être atteint sans un travail hors contexte de ce projet, donc voici un scénario type utilisant toutes les éléments que nous aurons eu à réaliser pour ce projet.

Lorsque l’on appuie sur un bouton du robot, il doit se déplacer en suivant un trajet prédéfini ou aléatoire sur un terrain plat. Ce terrain peut être composé de différentes matières. Il possède des mur et des obstacles, si ces derniers se trouvent sur le trajet du robot, ce dernier émet un signal (sonore ou lumineux) et change de trajectoire. Il doit à terme revenir à sa position exacte de départ, avec une faible dérive même en étant passé sur sur des surfaces différentes. Des robots utilisant des capteurs similaires à ceux utilisés par le robot peuvent être disposés sur le parcours, ils doivent être évités mais ne pas faire de faux positifs liés aux interférences. L’utilisateur peut alors se connecter au robot via une communication sans fil et récupérer les journaux de fonctionnement du robot pendant son parcours.

Réponse à la question difficile

Nous n'avons pas eu de questions difficiles lors de la séance de présentation.

Préparation du projet

Cahier des charges

Le robot (du moins la partie du robot sur laquelle nous travaillons) devra répondre aux contraintes suivantes :

  • Se déplace en suivant un parcours. Sur une piste de 2m×3m en PVC (type bâche adhésive décorative pour sol).
  • Est capable de savoir où il est. On s'autorise une dérive de 1mm pour 5m de déplacements. Ces 5 mètres correspondent à la distance que parcourra le robot durant un match. Une précision de 1mm est nécessaire pour réaliser les actions.
  • Évite les obstacles à l’avant et à l’arrière. Le parcours à réaliser est statique, cependant une protection basique contre les imprévus (autres robots) est nécessaire.
  • Résiste aux interférences causées par d’autres capteurs de distance de même type. Il y aura d’autres robots présents sur la piste, et certains d’entre eux pourront utiliser les mêmes capteurs que nous utilisons. Il faudra donc faire en sorte que les interférences ne perturbent en rien le bon fonctionnement de notre robot.
  • Est facilement débugguable. Après la réalisation du robot dans le cadre du projet, il passera dans une longue phase de test pour s'assurer du bon fonctionnement des actions qu'il est censé réaliser. Afin de faciliter et accélerer cette phase, on aimerait plusieurs choses du système de contrôle du robot. Il devra démarrer rapidement, utiliser le minimum de ressources nécessaires, et pouvoir être mis à jour et débuggué via une communication sans fil.
  • Pouvoir interagir avec l'utilisateur. Une fois sur le chemin de compétition, le robot n'aura plus l'aide d'un ordinateur pour pouvoir communiquer avec l'utilisateur. L'utilisateur doit toutefois pouvoir effectuer des tâches simples (saisir la zone de départ, l'équipe, la stratégie...) et contrôler l'état du robot (batterie, calibrage...).
  • Est conforme au cahier des charges de la Coupe de France de Robotique 2018 en tant que robot principal. Disponible ici, il fixe entre autres des conditions sur les dimensions du robot et sur le type de matériel qu'il peut embarquer.
  • Réutilise le matériel disponible. La création depuis zéro d’un tel robot est largement hors-budget pour un projet IMA4. On utilisera au maximum le matériel mis à disposition par Robotech pour minimiser les dépenses.
  • Dispose une alimentation 9 V. Sera utilisé pour les actions du robot hors projet.

Choix techniques : matériel et logiciel

Matériel

Alimentation

  • Batterie Lipo 4S. Dans son sac inifugé.
  • Carte de puissance. Dimensionnée en fonction des éléments et imprimée à Polytech.

Déplacement

  • Support mécanique & Roues. Utilisées pour l'édition de l'année précédente.
  • 2 × Faulhaber MOTOR 3557K024CS. Moteur à courant continu.
  • Contrôleur moteur. Dimensionnée pour nos besoins et imprimée à Polytech.

Connaissance de l'environnement

  • 2 × HEDS-5500 C06. Encodeur rotatif pour l'asservissemnt.
  • Capteur MinIMU-9 v3. Centrale intertielle utilisée en complément pour l'asservissement.
  • X × Capteurs ultrasons / infrarouges. Pour détecter les robots environnants.

Contrôle

La commande et le controle du robot sera géré par 3 puces différentes :

  • MicroNova Mercury FPGA Development Board. Ce FPGA sera utilisé pour les tâches nécessitant une faible puissance de calcul mais un parrallélisme un une très grande réactivité. Entre autre, il récupèrera les valeurs des codeuses des moteurs et s'occupera des l'asservissement des roues à l'aide d'un régulateur PID.
  • Arduino MEGA 2560. Utilisé pour les tâches nécessitant une bonne réactivité mais une puissance de calcul un peu plus élevés. Il s'occupera de s'assurer du bon déroulement de l'action en cours (avancer, pivoter...). Il gèrera notamment les différents capteurs d'obstacles.
  • Raspberry Pi 3. Utilisé pour les tâches n'ayant pas besoin d'une grande réactivité mais d'une grande puissance puissance de calcul. Il s'occupera de garder l'état du robot dans sa mission et de décider de ses prochaines actions. Il sera aussi utilisé pour toutes les actions de débug, sauvegarde et mise à jour des autres puces.

Interface humain-machine

  • Écran LCD SPI. Pour afficher des informations à l'utilisateur.
  • X × Boutons. Pour laisser l'utilisateur choisir des paramètres.

Logiciel

Systèmes d'exploitation

  • Buildroot. Système d'exploitation à configurer et compiler pour le Raspberry Pi. Complètement customisable et permet donc une grande legerté et flexibilité pour les tâches requises.
  • FreeRTOS. Système d'exploitation temps réel pour l'Arduino Mega 2560. Choisi pour simplifier les choses étant donné qu'on l'a déjà vu en TP de temps-réel.

Asservissement

  • Régulateur PID. Asservissement encodeur → moteur à courant continu (direct).
  • Filtre de Kalman / Fusion de données. Asservissement encodeur + IMU → informations sur l'emplacement du robot sur le terrain.


Conception cartes électroniques

  • Eagle
  • Altium

Liste des tâches à effectuer

Optionnel

  • Filtre de Kalman Arduino (Geoffrey)
  • Enlever le flag -D de avrdude Arduino (Geoffrey)
  • Concevoir contrôleur moteur avec transistor de puissance Electronique (Amaury)
  • ⇑Buildroot 2018.02 Raspberry Pi (Geoffrey)
  • Buildroot en AArch64 Raspberry Pi (Geoffrey)
  • Couche niveau 3 pour correction d'erreur Arduino Raspberry Pi FPGA (Geoffrey)
  • Multi-ADC FPGA Capteurs (Geoffrey)
  • Alléger noyau Linux (encore) Raspberry Pi (Geoffrey)
  • Wi-Fi direct ? Raspberry Pi (Geoffrey)
  • Faire les calculs en point fixe / entiers Arduino (Geoffrey)
  • Retrograder la priorité de l'UART0 Arduino (Geoffrey)
  • pilotage en courant des moteurs : recherches bibliographiques Wiki Electronique (Amaury)

À faire

  • concevoir schematic LMt18200T Electronique (Amaury)
  • commande composant complément pour 5206 Electronique (Amaury)
  • router controleur moteur avec Lm 18200t sur eagle Electronique (Amaury)
  • tester contrôleur moteur TLE 5206-2 e Electronique FPGA Arduino (Geoffrey, Amaury)
  • tester contrôleur moteur LM 18200T Electronique Arduino FPGA (Geoffrey, Amaury)
  • PID Arduino Arduino (Geoffrey)
  • PID polaire Arduino (Geoffrey)
  • Analyse interference capteurs Arduino Capteurs (Amaury)
  • Afficheur & Boutons Raspberry Pi
  • faire mail Mr Flamen pour composants complémentaires Electronique (Amaury)
  • IMU sous free RTOS Arduino Capteurs (Amaury)
  • Gérer les signaux Raspberry Pi (Geoffrey)
  • Calibration en position Raspberry Pi Arduino (Geoffrey)
  • re vérifier datasheet puissance Electronique (Geoffrey)
  • Analyser comportement HCSR04 quand pas d'echo Capteurs
  • PWM sans IDE Arduino Arduino (Geoffrey)

En cours

  • Expliquer Geoffrey IMU Capteurs (Amaury)
  • commande matériel électronique de puissance Electronique (Amaury)
  • acheter composant carte de puissance Electronique (Amaury)
  • Programme chef Raspberry Pi (Geoffrey)
  • analyse interférence capteurs : recherche bibliographiques Wiki Capteurs (Amaury)

À rédiger

  • IMU sur FPGA: voir si c'est judicieux FPGA Arduino Capteurs (Geoffrey, Amaury)
  • Repenser la récupération des données des codeuses FPGA Arduino Capteurs (Geoffrey)
  • Mettre en place la liaison série Arduino ↔ FPGA FPGA Arduino (Geoffrey)
  • Filtre capteurs FPGA Capteurs (Geoffrey)
  • Améliorer le module communication FPGA (Geoffrey)

Terminé

  • Liste de matériel Wiki (Geoffrey, Amaury)
  • Rattrapage session Arduino Raspberry Pi Arduino (Geoffrey)
  • rédaction correction V2 Mr Flamen Electronique Wiki (Amaury)
  • Mettre en place la liaison série Arduino ↔ Raspberry Pi Raspberry Pi Arduino (Geoffrey)
  • Différencier stop/brake Raspberry Pi Arduino (Geoffrey)
  • Upload Pi → FPGA Raspberry Pi FPGA (Geoffrey)
  • Établir protocole communication entre appareils Wiki FPGA Raspberry Pi Arduino (Geoffrey)
  • Dépot git FPGA Arduino Raspberry Pi (Geoffrey)
  • concevoir composants carte de puissance - V0 Electronique (Amaury)
  • concevoir schematic carte de puissance Electronique (Amaury)
  • concevoir carte de puissance Electronique (Amaury)
  • Upload Pi → Arduino Raspberry Pi Arduino (Geoffrey)
  • dimensionner tout les besoin carte de puissance Electronique (Amaury)
  • modification V2-> V3 tle5206 Electronique (Amaury)
  • vérifier typon capa 100uF --> dimension étrange Electronique (Amaury)
  • Choix techniques Wiki (Geoffrey)
  • changer bornier 5206 Electronique (Amaury)
  • Tester l'IMU Capteurs (Geoffrey, Amaury)
  • concevoir V0 contrôleur moteur avec TLE 5206-2 Electronique (Amaury)
  • IMU test faisabilite sur IDE arduino Arduino Capteurs (Amaury)
  • IMU documentation Wiki Electronique Arduino (Amaury)
  • Script pour générer la feuille d'heure Wiki (Geoffrey)
  • Codeuses FPGA Capteurs (Geoffrey)
  • Faire fonctionner la liaison série Raspberry Pi (Geoffrey)
  • Tenter sauvetage module Wi-Fi Raspberry Pi Raspberry Pi Electronique (Amaury)
  • Rajouter des illustrations Wiki (Geoffrey)
  • Tester FPGA Robotech FPGA (Geoffrey)
  • tester moteur pour propulsion des balles --> caractérisation technique indispensable pour la carte de puissance Electronique (Amaury)
  • Rectifier le modèle de FPGA Wiki (Geoffrey)
  • Faire fonctionner Wi-Fi Raspberry Pi (Geoffrey)
  • commande matériel contrôleur moteur Electronique Arduino (Amaury)
  • Base freeRTOS Arduino (Geoffrey)
  • prendre en compte recommandations Mr Flamen sur V0 Electronique (Amaury)
  • Travail prologue à documenter Wiki (Geoffrey)
  • OS Raspberry Pi Raspberry Pi (Geoffrey)

Calendrier prévisionnel

Difficile d'établir un calendrier prévisionnel quand notre méthode de travail se résume à « prendre un élément dans la liste des tâches à faire qui nous plaît, le faire, répéter ». Heureusement, notre client n'est pas trop pointilleux là dessus.

Réalisation du Projet

Feuille d'heures

Tâche Prlg.
30/10
Prlg.
6/11
Prlg.
13/11
Prlg.
20/11
Prlg.
8/1
S1
15/1
S2
22/1
S3
29/1
S4
5/2
S5
12/2
S6
19/2
Vacs.
26/2
Total
Analyse et préparation 2 8 10
Prise en main FPGA et tests 5.5 1 0.5 7
Rédaction wiki 2 2.5 5 4.5 1.5 3 3 21.5
Système Raspberry Pi 3 7 10
Routage contrôleur moteur 3 9 3 1 2 18
Routage carte de puissance 0.5 0.5 0.5 0.5 6 4 12
Autre 0.5 0.5
Analyse et implémentation des capteurs 2 2.5 2 1 7.5
Nettoyage & Consolidation 3 3
Communication entre les appareils 22 8 17 47
Analyse et implémentation des capteurs 1.5 1.5
Total 5 5.5 1 8.5 0.5 14.5 13.5 8 12.5 31.5 17.5 20 138

Prologue

Codeuses, Arduino & FPGA

Pour connaitre la rotation des roues du moteur pour l'asservissement, on utilise des codeuses de référence HEDS-5500 C06. Chacune de ces codeuses disposent de deux sorties tout ou rien, nommées A et B, dont la sortie en fonction de la rotation de roue évoluent comme ci-contre.

IMA17-18P66-Codeuse.png

Pour un tour de roue, il y aura 100 périodes du signal. On peut donc connaitre la rotation de la roue en comptant le nombre de fronts montant d'une des sorties, à condition que la roue tourne dans un sens. On peut s'affranchir de cette condition et connaitre le sens de rotation de la roue, en regardant l'état de B lors d'un front montant. Pour utiliser pleinement les capacités que nous propose les codeuses, on considèrera les différents fronts de chaque entrée, soit 4 fronts par périodes.

Faisons un rapide calcul. Les roues de nos moteurs font 4 cm de diamètre, et rouleront à un maximum de 10 km/h, soit un maximum de 11 tours par seconde, ce qui représente un maximum de 45270 fronts par seconde (pour une roue), ou une définition de 0,06 mm.

Cela représenterait une interruption toutes les 22 µs, ce qui fait beaucoup pour un Arduino. C'était ce que nous avions essayé lors de l'édition précédente de la coupe, en ne comptant que les fronts montants d'une seule sortie, le sens étant récupéré d'après l'ordre donné au moteur, et la seconde roue a été considérée mécaniquement symétrique à celle comptée. Autant vous dire que ni les performances de l'Arduino ni la précision de la mesure n'étaient au rendez-vous.

L'utilisation d'un FPGA en réponse à ce problème est donc totalement justifiée, ce dernier fonctionnant à 100 MHz, il peut largement gérer tous les fronts de la codeuse.

Code VHDL utilisé pour les codeuse

Workflow utilisé pour la programmation par FPGA

Paragraphe ajouté rétro-activement puisqu'utile pour la suite.

Le FPGA que nous utilisons est un Xilinx Spartan 3A. A priori, ces types de FPGA ne sont programmables qu'en utilisant les environnement de développement integrés Xilinx ISE et Xilinx Vivado. N'étant pas de grands fan des environnements de développement integrés (et de tout ce qui s'utilise avec une interface graphique en général), nous avons préféré utiliser un fichier Makefile qui appelle les outils internes de Xilinx ISE afin de générer le fichier .bit qui sera téléversé sur le FPGA.

Un des avantages de cette technique est qu'elle permet une organisation beaucoup plus concise de notre dépôt. En effet, toute la configuration est stockée dans un seul fichier et non dans une hiérarchie complexe de fichiers XML comme le générerait un projet Xilinx ISE. Les fichiers générés (et donc à ne pas inclure dans le dépôt) sont tous inclus dans un même dossier facile à exclure du système de contrôle de version. En guise de bonus, la synthétisation d'un design est 50% plus rapide qu'en utilisant l'IDE (nous n'avons pas su l'expliquer). Enfin et surtout, on pourra intégrer la synthétisation dans les scripts de mises à jour du robot sans peine.

Le désavantage de cette technique est qu'il devient plus difficile d'utiliser les outils plus poussés de l'IDE, tel que la génération d'IP cores ou la simulation. Pour le premier ce n'est pas trop un problème car notre programme ne sera pas très complexe (et que certains IP core ne fonctionnerait pas dans notre cas vu l'exotisme de notre FPGA). Pour le deuxième, on utilisera par la suite un système de simulation différent et à notre goût plus performant.

Semaine 1

Dimensionnement de la carte de puissance

Nous utiliserons comme source d'énergie une batterie Lithium-Polymère (ou LiPo) 4s délivrant une tension de 14.8V.

Note rétro-active : Certaines valeurs et remarques lors de cette analyse initiales sont erronnées, elles ont été corrigées en semaine 4.

Voici l'ensemble des consommateurs constituants le robot :

  • Arduino MEGA : consommant 500mA avec une tension d'alimentation recommandé de 7 à 12V ou par USB de 5V mais cette option est peu recommandée car elle peut entraîner des manques de stabilité dans le fonctionnement du micro-contrôleur et dans la qualité du 5V donnée par les broches.
  • Raspberry Pi 3 : consommant 2.5A avec une tension d'alimentation de 5V.
  • Moteur déplacement: consommant 3A chacun au maximum de leur utilisation nominale cependant ils s'avèrent surdimensionnés pour notre usage. Empiriquement leur utilisation étaient plutôt de l'ordre de 1.5 A maximum. La tension nominale est de 24V nous pouvons donc les alimenter en 12V tout en maintenant une bonne qualité de pilotage. Cependant on choisira de garder l'alimentation du contrôleur moteur en 24V afin de laisser pour les années à venir le choix aux futurs équipes.
  • FPGA Spartan 6 : Consommant au grand maximum 1A à une tension d'alimentation de 5V.
  • Moteur pour les actions du robot. Les actions a proprement parler n'ont pas encore toutes été parfaitement déterminées par notre client. On y reviendra donc plus tard.

Dimensionnement du contrôleur moteur avec pont en H intégré

Voici les caractéristiques demandées par le contrôleur moteur :

  • alimentation au moins en 12V minimum et 24V maximum
  • sortie en 24 V maximum avec 3A de courant par moteur (donc x2)
  • dimensions réduites
  • capacité à être réparé/remplacé facilement lors de la Coupe de France
  • optionnel: protection intégré contre les retours de courants et les courts circuits

Lors de nos recherches nous avons trouvés les 4 commposants suivants répondants à première vue à nos besoins :

Le L298 offre un courant de 4 A maximum donc il ne permet pas de contrôler les deux moteurs en même temps il est donc d'office éliminé.

Le LM 18200T et le LM 18201T offrent un courant de 6 A en pilotant deux moteurs, ils ne sont pas très différents l'un de l'autre à part un prix plus élevé pour le LM 18201T alors qu'il ne possède pas de capteur de courant. De toute façon nous n'avons pas prévu d'utiliser cette fonctionnalité. Le LM18200T permet lui un pilotage plus précis des moteurs avec des capteurs de courants et de températures intégrés mais la densité des pins rend plus complexes le routage et les réparations rapides.

Le TLE 5206-2 est bien plus simple de fonctionnement et offre moins de services que le LM18200T, il permet donc également une simplicité de routage et de modularité mais il ne permet de piloter qu'un seul moteur.

Notre choix s'arrête donc sur la conception dans un premier temps du contrôleur avec les TLE 5206-2 avec deux PCB isolés (un par moteur), puis on utilisera un LM18200T qui pilotera les deux moteurs à lui tout seul en tant que solution alternative.

FreeRTOS pour Arduino

L'Arduino du robot doit gérer plusieurs tâches à la fois, telles que : la gestion de l'asservissement, des capteurs, l'envoi des données de déboguage... Pour cela, l'utilisation d'un ordonnanceur est inévitable. On aura probablement besoin de sémaphores pour (entre autres) la gestion des ports série et des variables communes aux taches (celles concernant la position du robot notamment).

Nous avons choisi d'utiliser le système d'exploitation temps réel FreeRTOS pour deux raisons. La première est qu'il est très léger, et n'embarque pas plus que ce dont nous avons besoin. La deuxième est que c'est le système que nous avons utilisé dans les TP de l'enseignement Temps Réel, nous avons donc déjà un peu d'experience dans le domaine. La configuration de FreeRTOS pour un hôte Linux et une cible Arduino Mega 2560 nous a été fourni par M. Forget.

Buildroot pour Raspberry Pi

Le Raspberry Pi est le composant qui décide et envoie les ordres de déplacement à l'Arduino et au FPGA. Même s'il n'a pas besoin d'autant de réactivité que ses confrères, il est souhaitable que dès qu'il reçoit l'information que l'ordre précédent a été réalisé (et ses conditions de réalisation), il calcule et et envoie l'ordre suivant dès que possible.

Le problème d'un système d'exploitation de bureau est qu'il y a un certains nombre de services pour simplifier la vie de l'utilisateur tels que l'indexation des fichiers, la découverte réseau, le pare-feu, la vérification des mises à jour... Nous pouvons difficilement contrôler ces tâches, et si notre robot a besoin de la puissance de calcul de la carte quand le système réalise ces tâches plus ou moins inutiles dans notre cas, le temps de réponse pourrait augmenter. Sur une application comme la notre où le temps est compté, cela peut avoir une influence (elle est très probablement minime dans notre cas, mais on choisira de ne pas la négliger).

Répartition de la taille du système d'exploitation

Nous allons donc utiliser un système d'exploitation alternatif conçu uniquement les fonctionnalités dont nous avons besoin. Notons que le cahier des charges nous impose de pouvoir utiliser le Wi-Fi et de pouvoir mettre à jour le système des autres cartes, et on souhaitera pour cela utiliser des outils pré-existants. On n'utilisera donc pas un système type FreeRTOS. Notre choix se portera sur Buildroot qui est un utilitaire qui permet de construire des images de système d'exploitation sur base de noyaux Linux en sélectionnant les options et programmes via un simple fichier de configuration. Le système nous propose aussi de créer nos propres programmes et s'occupe lui-même de la cross-compilation, ce que l'on utilisera pour le(s) programme(s) régissant la logique du robot. La compilation des programmes étant faite sur une machine hôte (et non sur la machine cible, ici le Raspberry Pi), cela nous permet de réduire les temps de compilation. Cela sera particulièrement utile lors des phases de test du robot.

Après ~45 minutes de compilation, une image d'une soixantaine de Mio contenant notre système d'exploitation est générée. Le système démarre en une poignée de seconde, et en idle ne consomme qu'une dizaine de Mio de RAM et il n'y a que très peu d'activité sur le CPU. Toutes le reste des ressources sont alors disponibles pour notre utilisation. Seul bémol, devoir reflasher la carte à chaque modification du système (le programme étant inclus) est assez lourd. On décrira une solution à ce problème dans une prochaine section.

Semaine 2

Mode production / Mode debug

Lorsque le robot sera assemblé, il pourra être fastidieux de brancher un câble à l'interieur pour pouvoir mettre à jour les différentes cartes possèdant une mémoire (Raspberry Pi, Arduino et FPGA). D'autre part, après notre projet terminé, le robot sera transferé à Robotech qui s'occupera d'ajouter des actionneurs pour mener à bien sa tâche pour la compétition, et qui testera le robot. Il va donc falloir mettre à jour les programmes un nombre important de fois.

C'est pour cela qu'a été instauré la contrainte de pouvoir mettre à jour la mémoire des cartes via une communication sans fil. Nous avons choisi d'utiliser une communication Wi-Fi, car elle est simple à mettre en place, et elle permet d'utiliser le protocole SSH qui nous semble le plus simple à configurer pour déboguer. La simplicité est ici de mise, ce n'est pas une section critique du fonctionnement du robot donc si la méthode utilisé pour le déboguage n'est pas la plus performante, ce n'est pas un problème. De plus, l'utilisation d'un protocole très connu et bien testé nous évitera les complications.

IMA4-1718-P66-debugPin.png

Cependant, pour assurer que le Raspberry Pi se lance en un minimum de temps lors de la compétition, on s'assurera de charger uniquement ce qui est nécessaire. Les outils de debug, la connexion Wi-Fi ne seront activées que lorsque deux broches du Raspberry Pi sont court-circuitées. La vérification sera faite à la dernière étape de lancement à l'aide du binaire testpin, qui prend comme argument deux numéros de pins selon la bibliothèque Wiring Pi.

Raspberry Pi 3 : Réparation de la puce Wi-Fi interne

Nous avons constaté durant la semaine précédente que le wifi ne fonctionnait plus. Après avoir éliminé une possible source software nous avons voulu vérifier qu'aucun court-circuit n'était présent sur la carte, elle a donc été nettoyé avec du flux en C201. Le problème a persisté. Par curiosité nous avons mesuré la tension d'alimentation de la puce wifi, elle est de 1.34 V. Or la datasheet du constructeur nous a indiqué que la tension d'alimentation de cette puce doit être comprise entre 3 et 5V. Il semble donc que le problème se trouve au niveau de la carte de puissance. Le Raspberry Pi n'étant pas open hardware (et la possibilité d'une réparation assez faible, vu la taille et la protection des pistes), nous avons arrêté là nos investigations et installé un dongle wifi USB.

Raspberry Pi 3 : Mise en fonctionnement du Wi-Fi

Sur un système d'exploitation classique, il suffit généralement de brancher un dongle Wi-Fi pour faire en sorte qu'il fonctionne. Pour fonctionner, un dongle Wi-Fi (comme beaucoup d'autre périphériques) a besoin d'un firmware, c'est à dire un petit bout de code qui est chargé sur le matériel depuis par le noyau afin qu'il puisse fonctionner. Or, dans notre système d'exploitation à la carte, celui pour notre dongle Wi-Fi n'est pas installé par défaut, il a donc fallu le faire compiler. Ensuite à l’exécution, il faut charger le module correspondant au dongle via un `modprobe`, car il n'est pas chargé automatiquement par le système lors de l'insertion (cela nécessiterait un démon supplémentaire). À partir de là, l'interface `wlan0` est fonctionelle et on peut potentiellement se connecter à un réseau Wi-Fi.

Donc a priori, si on crée un fichier `/etc/network/interfaces` comme nous avons vu en TP de réseau et qu'on lance un `ifup wlan0` cela devrait fonctionner non ? Pas tout à fait. Il s'avère que la commande `ifup` inclue dans notre système (fournie par la boîte à outils BusyBox) n'est pas aussi complète que celle dans l'OS Raspbian utilisé en TP et ne gère pas les instructions `wpa-*` du fichiers `interfaces`. Pour parer à cela, il suffit d'appeler `wpa-supplicant` directement, qui est le programme qui s'occupe (même sur Raspbian) de l'authentification au réseau Wi-Fi. On peut ensuite utiliser `ifup` pour la configuration IP.

Après un rapide test de ping, on installe (enfin plus précisément on dit à Buildroot de compiler dans l'image, puisque le système n'a pas de gestionnaire de paquets) un serveur SSH sur la machine, et on met en place un petit système afin que les la clef privée et l'empreinte de la clef du client soient sur le Raspberry Pi afin de se connecter simplement et rapidement à la machine.

Conception de la carte de contrôleur moteur avec le composant TLE5206

Schematic du contrôleur moteur à base de TLE5206
Routage du contrôleur moteur à base de TLE5206

L'intérêt de ce contrôleur est qu'il très bon marché (4€/pièce), et il permet de contrôler un moteur jusque 5A avec un pic de courant de 6A et une tension d'alimentation allant jusque 40V.

Cependant il disposes de quelques limites :

  • Le pic de courant accepté n'est que de 100ms, ce qui peut être court si nous voulons avoir un déplacement agressif lors de la compétition.
  • Il possède assez peu de protections. En regardant la datasheet on voit que beaucoup court-circuits éventuels ne sont pas couvert par le système de protection, ni par l'indication de flag. La non-détection d'un court circuit au niveau du moteur pourrait lui entrainer des dommages. Étant l'élément le plus cher du robot, notre client nous a demandé d'apporter un soin particulier à ce composant, d'où cette préoccupation.

La conception de la carte a été faite sur Eagle après avoir suivi plusieurs cours en ligne pour se former au logiciel.

Pour nous assurer de la bonne qualité de notre carte, nous avons demandé à M. Flamen un retour sur la qualité de la conception. Voici les premiers éléments à améliorer :

  • Les pistes sont trop étroites. Il est nous est conseillé d'utiliser l'application Electrodroid pour les choisirs.
  • Il faut éviter les angles aigus.
  • Il faut mettre les composants de puissance en bordure de PCB pour permettre l'installation d'un dissipateur.

Semaine 4

Conception de la carte de contrôleur moteur avec le composant TLE5206

Exemple d'un mauvais routage n'optimisant pas l'espace avec des pistes parallèles

Un deuxième retour nous a été effectué par M. Flamen.

Compatibilité Électro-Magnétique : Les angles à 90° sont à éviter mais pas forcément à proscrire, surtout si l'on ne fonctionne pas en haute fréquence (ce qui est notre cas). Les angles inférieurs à 45° et ceux supérieurs à 135° sont à éviter autant que ceux à 90°. Il faut également essayer de garder le même angle entre des broches parallèles afin d'optimiser l'espace et les fraises. En effet en cas d'angle très aigus (comme ceux formés par une connexion en arc de cercle avec une ligne droite) la jonction entre les deux forment un angle très aigus que la fraiseuse va devoir usiner avec des fraises très spécifiques coûtant souvent plus cher que la machine. De plus il s'agit d'une bonne pratique à garder si l'usinage des cartes est chimique car il peut favoriser une collection d'acide entraînant des grignotages sur la carte pouvant altérer son fonctionnement.

Texte sur la carte : L'ajout d'annotations gravées sur le circuit directement est fondamentale, il permet d'éviter les erreurs de branchements et permet de garder un contrôle des versions sur les PCB. Il faut l'ajouter au format tdocu dans l'onglet Computer-Aided Manufacturing afin de graver les lettres et non le contour des lettres. De cette façon on économise en temps de conception et on éviter de trop user les fraises.

Design Rule Check : Il faut modifier la valeur copper dimension à 4mm afin de suivre les spécifications de la graveuse numérique. Cette valeur représente l'espace entre la découpe du contour du PCB et l'espace sans cuivre qu'on laisse autour.

Divers :

  • Il faut faire attention avec le plan de masse à ne pas laisser des zones trop étroite, cela pourrait engendrer des échauffements.
  • Il faut faire attention aux trous de fixation : il faut prendre en compte la tête de la vis. Pour se simplifier la tâche on utilisera Drill 3, qui la prend en compte sur le PCB contrairement à Hole qui se contente de faire un trou.

Après quelques ajustements mineurs par la suite, la carte a été envoyé en impression.

Centrale inertielle

Illustration des 3 composantes
Visualisation d'une séquence de Yaw

Le problème avec les encodeurs de moteurs est qu'ils ne sont pas sensibles à d'éventuels dérapages des roues sur la piste. Dans la mesure où nous souhaitons de fortes accélérations, nous ne pouvons néglier ces pertes. C'est pourquoi nous allons utiliser une centrale intertielle, ou Inertial Measurement Unit (IMU), qui est un PCB embarquant avec lui un gyroscope, un accéléromètre et une boussole. Bien que la précision du capteur soit bonne que les encodeurs, elle permettra de détecter des incohérences liées aux dérapages et les corriger.

Notre IMU, une MinIMU-9 v3 embarque le gyroscope L3GD20H et un accéléromètre/magnétomètre LSM303D.

Nous avons fait des tests préliminaires A l'aide de la documentation fournie par Pololu nous nous sommes assurés du câblage et avons pu nous renseigner sur la communication I2C et les différentes possibilités de l'IMU.

L'IMU peut nous donner les paramètres suivants : le yaw, le pitch et le roll.

Sur l'enregistre de gauche on voit que pour un passage brutal d'angle de la position verticale à horizontale on obtient un pic négatif important (50% de la variation réelle). Cependant il reste très bref (quelques millisecondes).

Un pic similaire a pu être observé sur les autres axes.

Il ne semble pas que celui ci soit un obstacle à la fonctionnalité recherchée mais il est à prendre en compte dans la conception du programme d'asservissement afin d'éviter des corrections excessives en cas de rotation brutale.

Mise à jour du/par Raspberry Pi

Mise à jour de l'OS du Raspberry Pi

Nous avons vu que pour mettre à jour le système d'exploitation du Raspberry Pi, ré-écrire la carte SD en entier n'est ni pratique, ni rapide, ni bon pour la durabilité de la carte. On a donc établi -conformément à ce qui était demandé dans le cahier des charges- un moyen de le mettre à jour par liaison sans file. On a déjà un moyen de se connecter en SSH au Raspberry Pi par Wi-Fi, on transférera donc par ce canal les fichiers générés par buildroot avant mise en image, vers la racine de la carte. On utilisera pour cela `rsync`. Cela rajoute un programme en plus sur l'OS, mais cela permet de ne pas ré-envoyer les fichiers qui n'ont pas changé. Ce n'est pas une solution très élégante, mais elle est redoutablement fonctionelle. Il suffit alors de taper `make upgrade-filesystem` pour lancer l'opération.

Mise à jour de l'Arduino

Le programme utilisé pour téléverser un programme sur un Arduino s'appelle avrdude, et par chance il est dans les programmes proposés par buildroot. Il suffit simplement de l'activer dans la configuration de buildroot et d'ajouter une entrée `upgrade-arduino` dans le Makefile qui se chargera de l'envoi vers le Raspberry Pi et de l'invocation de la commande de téléversement.

Mise à jour du FPGA

On procèdera de la même manière pour téléverser un programme sur le FPGA. Cependant, le FPGA utilisé étant assez peu connu, il n'existe pas de programme directement dans buildroot capable d'effectuer le téléversement. De plus, le programme fourni par le constructeur pour le téléversement est sous forme d'interface graphique ce qui n'est pas adapté pour notre cas. Heureusement, la source du programme est ouverte, et quelqu'un l'a réécrit sous forme de programme en ligne de commande. Il ne reste qu'à créer un package pour buildroot et le tour est joué.

Semaine 5

Carte de puissance

Après de nombreuses discussions auprès du client (à savoir les différentes équipes travaillant sur le robot principal) il semble que les besoins en diverses tensions et courant sont à présent fixés, nous avons donc :

Bilan de puissance
Quantité Consommateur Alimentation Courant maximum
1 Arduino MEGA 9-12V 500mA
1 Raspberry Pi 3 5V 1A
2 Moteur Faulhaber 24V 4,2 A bridé à 2,5A environ
1 FPGA MicroNova Mercury 5V 275mA (nominal 60mA)
1 Dynamixel AX-12 (demmande client) 9-10V 900mA (à vérifier)
2 QH4 4347 (demmande client)  ?  ?


Nous avons donc besoin de sources de tension suivantes :

  • 5V délivrant 1,275A maximum
  • 9V délivrant 1,4A maximum
  • 24V délirant 5A maximum

Il reste une inconnue pour le moment, l'alimentation du moteur QH4 4347.

Il nous reste à présent le choix des composants, 3 possibilités s'offrent à nous :

  • Acheter des convertisseurs clés en mains [1] de ce type. Ils proposent souvent un prix imbattable mais sont rarements fiable presque dangereux.
  • Acheter des composants à souder sur des sites réuputés de ce type. Le prix est plus élevé mais nous avons un composants bien plus fiable et où les échauffements sont très réduits offrant une efficacité imbattable. De plus on a le plaisir de concevoir le PCB qui l’accueillera.
  • Créer nous même le convertisseur en descendant encore d'un niveau. Cependant cela demande de nombreuses heures de conceptions et de tests tout en ayant un prix pas si compétitif face à l'option 1 et 2 et aucune garantie quant à l'efficacité du produit final.
Carte d'alimentation des moteurs
Carte d'alimentation des parties non motorisées

Si l'on s'appuie sur l'expériences des dernières années nous pouvons prospecter la deuxième option : Pour le 5 et le 9V nous pouvons : [2]. Pour le 24V : [3]. Il s'agit de la même famille de composants qui permettent de choisir la tension de sortie à l'aide de quelques composants extérieurs offrant une modularité à cette carte pour les années suivantes. Soit un total de plus de 70€, une solution couteuse mais de qualité.

Pour trancher cette décision nous en avons discuté avec un professeur d'électronique de puissance, M. Delarue.

Il nous a conseillé de favoriser l'option 2 qui reste la meilleure option « en terme de fiabilité, de rendement, d'encombrement, de prix, ... ».

Les composants proposés précédemment sont cepednat des step-down, ils ne peuvent pas produire des tensions supérieures à la tension d'alimentation. On ne pourra donc pas créer de tension à 24V.

Pour le booster qui alimentera nos deux moteurs nous avons vérifié la datasheet du moteur. Il n'y a pas d'indications sur le pic de courant au démarrage du moteur, nous nous baserons donc sur les composants qui ont résisté lors des compétitions précédentes pour que ceux choisis correspondent au minimum aux mêmes caractéristiques techniques.

Pour alimenter nos moteurs nous utiliserons ce composant en 2 exemplaires (1 par contrôleur moteur et donc par moteur).


Nous avons donc routé une première version de deux cartes d'alimentation, une pour les moteurs et une pour le reste (images ci-dessus). Elles sont encore améliorables, il est notamment question d'éventuellement placer un bornier sur les pins inutilisés afin de permettre un éventuel usage plus tard.


Communication entre les appareils

Le Raspberry Pi, l'Arduino et le FPGA doivent pouvoir communiquer ensemble afin de remplir leur rôle. Pour établir un système de communication adapté à leur besoins, établissons la liste (grossière) des informations qui doivent être envoyées d'un appareil à l'autre.

Raspberry Pi → Arduino

  • Ordre d'arrêt
  • Ordre de nouvelle destination
  • Réinitialisation des informations de position

Arduino → Raspberry Pi

  • Arrivée à destination
  • Informations d'état pour le débug

Arduino → FPGA

  • Réinitialisation de la valeur des encodeurs

FPGA → Arduino

  • Valeur des encodeurs
  • Valeur des capteurs de distance

Informons nous sur les différents modes de communication natif des différents appareils :

  • Le Rapsberry Pi possède des accélérateurs matériels pour communiquer en I2C, en SPI et en UART. De plus, une liaison série supplémentaire avec un Arduino est aisément possible à l'aide d'un câble USB.
  • L'Arduino Mega 2560 possède 4 liaisons UART matérielles, et une liaison SPI matérielle.
  • Le FPGA peut utiliser n'importe quel protocole de communication sans effort.

Passons en revue les autres systèmes de communication que nous seront amenés à utiliser et pour lesquels il n'y a peut-être pas de solution alternative.

  • Sur le Raspberry Pi, on aimerait garder la liaison UART matérielle étant un moyen très peu prones aux erreurs d'accéder à un shell du Raspberry Pi. De plus, le port SPI sera utilisé pour l'écran LCD qui servira pour l'interface humain-machine.
  • Sur l'Arduino, la liaison SPI sera utilisée pour communiquer avec la centrale intertielle. La liaison série n°0 est aussi utilisée pour la mise à jour du programme de l'Arduino par USB, il faudra donc éviter de brancher quelque chose dessus.

Cependant ces deux contraintes n'en sont pas réellement, puisque le protocole SPI autorise le branchement de tous les périphériques sur le même réseau de par son schéma maître-esclave. En conséquence, chaque élément possède un temps de parole limité, ce qui peut être problématique dans notre cas d'usage. En effet, il serait facheux que le FPGA doive attendre pour transmettre des informations concernant une collision imminente alors que le réseau est occupé à transférer des données de debug. De plus, les périphériques esclaves ne peuvent communiquer entre eux, tout doit passer par le maître qui devra jouer le rôle de messager au besoin.

Pour ces raisons, et aussi pour des raisons de simplicité, on connectera chaque appareil deux à deux à l'aide d'une liaison série. On obtient un schéma de communication suivant :

IMA4SC1718-Communication.svg

Pour les liaisons séries, on utilisera en couche applicative notre propre format de trame. Chaque trame commencera par un octet indiquant le type d'information à être envoyé. Elle peut être ensuite suivie par des données, dont la taille et la consitution est définie par le type d'information. Chaque information pouvant être transmise, et la structure de données à envoyer est définie dans des fichiers .h, un pour la communication Arduino↔FPGA et un pour la communication Arduino↔Raspberry Pi (dans ces fichiers le Raspberry Pi est aussi appelé Chef, pour le nom du programme).

Certaines informations seront envoyée à l'initiative de l'appareil possédant l'information (Direct), tels que les ordres du Raspberry Pi à l'Aruino. D'autres, seront envoyés à l'initiative de l'appareil ayant besoin de l'information (Indirect), tels que les valeurs des codeuses qui changent bien plus souvent que l'Ardnuio ne saura les traiter. Les dernières, seront envoyés dès que certaines valeurs dépassent un certain seuil (Trigger), seuil fixé par l'appareil reçevant l'information, telles que les valeurs des capteurs de distance. Tout cela permet de garder uniquement les informations utiles, afin de réduire au maximum la congestion du réseau et le traitement par les appareils.

Communication série par interruptions sur Arduino

Jusque là en cours, pour envoyer ou reçevoir des octets sur l'Arduino, on utilisait une boucle qui attendait que les bits RXCn et UDREn du regsitres UCSRnA soit mis à 1, affin d'attendre qu'un octet soit reçu ou prêt à être envoyé respectivement. Le problème de cette méthode, est qu'elle utilise excessivement le CPU et empêche de faire quelque chose d'autre en même temps. Avec le système RTOS, on peut faire plusieurs choses à la fois, mais il faut attendre que la tâche de cette boucle soit élue pour pouvoir traiter l'envoi / la réception de données.

Heureusement, l'Atmega2560 dispose d'interruptions sur le port série. Il suffit d'activer le bit RXCIEn dans le registre UCSRnB pour qu'à chaque réception d'octet sur le port série, l'interruption USARTn_RX_vect se déclenche. Dans notre cas, cette interruption réveille une tâche FreeRTOS à l'aide d'une notification, tâche qui va s'occuper récupérer et traîter les données juste reçues, et se ré-endort jusqu'à la prochaine réception.

On pourrait directement traîter les données dans l'interruption, mais cette méthode a plusieurs avantages. En effet la durée de l'interruption est minime, permet d'utiliser le système de priorités des tâches (alors que l'interruption a une priorité absolue) et évite d'empêcher l'arrivée d'autres interruptions. D'autre part, la tâche peut-être interrompue à n'importe quel endroit, elle est donc un moyen simple de stocker à quel endroit de la reception on en est.

Pour la transmission, deux choix s'offrent à nous : l'utilisation de l'interruption USARTn_TX_vect ou de l'interruption USARTn_UDRE_vect. La première est déclenchée quand un caractère vient de finir sa transmission. On peut alors utiliser cette interruption pour envoyer le prochain caractère dans la file d'attente. Cependant, si on utilise la même méthode que pour la réception, entre le moment où la transmission d'un caractère est terminée et celui où la transmission d'un nouveau caractère est initiée, il va falloir que la tâche faisant l'envoi soit élue. On peut en revanche utiliser le cache matériel de l'Atmega2560, qui permet de stocker deux caractères, et nous permet donc d'envoyer une suite ininterrompue de caractères, et ainsi envoyer les messages plus rapidement. Il faut pour cela utiliser l'autre interruption, USARTn_UDRE_vect qui se déclenche quand il est possible d'écrire dans le cache.

Cependant, cette interruption s'utilise différemment des deux précédentes. En effet, là où les interruptions se déclenchent à un changement d'état (e.g. reception d'un octet), USARTn_UDRE_vect se déclenche continuellement quand le cache de la liaison série est écrivable. D'une part, il faut donc désactiver l'interruption quand il n'y a rien à transmettre. D'autre part, il faut donc écrire dans le cache à l'interieur de l'interruption. On définiera donc un pointeur global vers les données à écrire et leur taille qui sera écrit depuis la tâche voulant envoyer des informations et lue par 'interruption. Une fois l'envoi terminé, l'interruption se désactivera d'elle même et réveillera la tâche ayant initié l'envoi. Cette méthode nous permet d'utiliser au maximum de sa capacité la liaison série tout en encombrant un minimum le processeur de l'Arduino.

Répartitions des messages reçus

Que ce soit du côté de l'Arduino ou du Raspberry Pi, la réception d'octets sur la liaison série est gérée par une seule tâche (ou thread sur le Raspberry Pi). Cependant, pour éviter de complexifier trop cette tâche et de la rendre indépendante des types de messages reçus, on utilisera un système d'observateurs. N'importe quelle partie du programme peut demander à ajouter un observateur sur un certain type de message. L'observateur, étant une fonction, est éxecutée lors de la réception dudit type de message. Cette fonction peut alors récupérer les données du message pour les stocker à l'endroit voulu, et dire à une autre tâche de faire quelque chose avec ces données.

Pour faire cela, la tâche de réception garde un tableau d'observateurs indexés par le type de message auquel il est accroché. Quand le début d'un message est reçu, la tâche regarde dans le tableau si un observateur a été associé au type de message, si oui éxecute la fonction (dans la même tâche, afin que cette fonction puisse lire le reste du message) et si non affiche une erreur.

Récupération de session

Chaque appareil (FPGA, Arduino et Raspberry Pi) est censé pouvoir fonctionner indépendament. Par exemple, si l'on pousse le robot alors que le programme chef du Raspberry Pi est inactif, on veut quand même enregistrer le déplacement afin d'éviter de devoir re-calibrer la position du robot par rapport à son environnement. Ce n'est pas inclus dans le cahier des charges, mais c'est une fonctionalité simple à réaliser vu la réalisation choisie. On pourra donc travailler facilement sur le programme principal (c'est à dire le redémarrer et le modifier) sans que ce dernier n'ait à sauvegarder la dernière position du robot puis la relire.

Cependant, que se passe-t-il si le programme du Raspberry Pi est interrompu alors que l'Arduino est en train d'attendre des informations ? Vraisemblablement, les premiers messages envoyés par le Raspberry Pi seront considerés comme des données de message et seront donc ignorés en tant que message, et par la suite un décalage s'ensuivra. Pour éviter cela, on instaure un nouveau message, le ping. Quand le Raspberry Pi envoi un message de ce type (sur 1 octet), l'Arduino doit lui renvoyer un message du même type et ne rien faire d'autre. Lors du démarrage du programme du Raspberry Pi, ce dernier envoi plein de requêtes ping à la suite, jusqu'à ce que ce que l'Arduino lui renvoie son message. De cette manière tout message en cours de réception côté Arduino sera rempli et les deux appareils seront de nouveau synchronisés. Il faut juste prendre gare à envoyer un message d'arrêt des actionneurs du robot dès la première réponse reçue, car le message en cours de réception contient alors des données invalides qu'il faut annuler.

Semaine 6

Simulation du FPGA

Tests unitaires avec un échec pour le module de communication du FPGA

Écrire un programme pour FPGA est un processus plus compliqué que l'écriture d'un programme pour ordinateur. En effet, dans le premier, il n'y a pas possiblité d'utiliser de débuggueurs pour observer le contenu des variables, ou de moyen simple d'afficher des messages à l'écran. De plus, le processus de synthétisation est plutôt long, et lorsque le FPGA est utilisé avec d'autres périphériques il n'est pas toujours facile de les avoir sous la main pour tester.

Heureusement, il est possible de simuler les programmes de FPGA à l'aide de simulateurs. La génération d'une simulation est généralement beaucoup plus rapide que la synthétisation d'un design, et permet d'observer les signaux internes des composants. L'outil Isim, proposé par Xilinx -le constructeur du FPGA que nous utilisons-, est l'un de ces simulateurs, mais il n'est pas très flexible et s'utilise difficilement sans projet de l'IDE Xilinx, que nous n'utilisons pas pour des raisons évoquées dans le prologue. Nous allons plutôt utiliser deux outils libres, GHDL et GTKWave.

Affichage des signaux pour le module de communication du FPGA

La simulation d'un process commence par l'élaboration d'un testbench, qui est un fichier VHDL qui embarquera comme composant le module à tester, et génèrera des signaux sur les entrées du module à différents instants de la simulation. On peut alors vérifier que les sorties du modules soient conformes à ce qui est attendu : on réalise de la sorte des tests unitaires (cf capture de terminal à gauche). On peut aussi afficher avec GTKWave l'évolution des signaux en fonction du temps afin de débuguer plus finement le programme (cf capture d'écran à droite). Bien entendu, tout le processus de simulation (à part l'élaboration du testbench) a été intégré dans un makefile, afin de pouvoir rafraichir la simulation d'un seul relancement de commande. On retrouvera des fichiers XXX_tb.vhd contenant le testbench pour le module XXX ; des fichiers build/XXX.ghw contenant l'évolution des signaux dans la simulation ; et des fichiers XXX.gtkw contenant les informations d'affichage desdits signaux dans le logiciel (ordre, couleur, type de données...).

Il faut faire cependant attention aux différences existantes entre la simulation et la synthétisation. En effet la simulation est beaucoup plus permissive ce qui permet notamment de simplifier l'écriture de testbenchs. Cependant, certains comportements sont inconnus voire ignorés par le synthétiseur. Par exemple, dans un process il est possible de définir des listes de sensiblité, qui font en sorte que le process ne soit executé uniquement si une des valeurs des éléments de cette liste est changée. Cependant sur le vrai FPGA, cette liste de sensibilité est totalement ignorée et le process est éxecuté à chaque front d'horloge, ce qui peut causer de grandes différences entre la simulation et la réalité. Il faut donc garder en tête ces différences lors de la simulation.

Vacances

Vue d'ensemble du FPGA

Cette semaine nous allons beaucoup parler du FPGA. Pour mieux comprendre la suite, il peut être utile de rappeler ce que cette carte est censée faire et comment nous comptons lui faire faire.

Les tâches à réaliser par le FPGA sont les suivantes :

  • Récupérer les valeurs des capteurs de deux capteurs distance (un devant et un derrière) (pour l'instant ce sont des capteurs ultrasons de type HC-SR04)
  • Filtrer les précédentes valeurs de façons à enlever les valeurs aberrantes liées aux interférences
  • Récupérer les valeurs des encodeurs (un à gauche et un à droite)
  • Communiquer les valeurs récupérées par liaison série

Basiquement, on écrira un modules VHDL pour chaque tâche, respectivement hcsr04.vhd, fir.vhd,

Récupération des données des encodeurs

Au départ on pensait stocker les valeurs des encodeurs (générées par le FPGA) sur un entier signé de 32 bits, et ce dernier serait envoyé à l'Arduino à chaque fois que ce dernier en a besoin pour actualiser la position du robot. Cependant, on s'est rendu compte que l'Arduino n'a besoin que de la différence entre la précédente valeur et la valeur actuelle pour calculer le déplacement en position. Nous avons donc fait en sorte d'envoyer directement la différence, en remettant à 0 les valeurs à chaque lecture par l'Arduino. Cela se fait par l'entrée zero des modules VHDL des encodeurs, forçant leur valeur à 0, qui est donc mise à '1' pendant un cycle d'horloge.

Mais que se passe-t-il si la valeur des encodeurs change pendant une lecture  ? L'utilisation d'un signal VHDL pour stocker les valeurs ne permet pas d'être modifiée deux fois en un cycle d'horloge (une pour remettre à 0 et une pour incrémenter/décrémenter la valeur), on perdrait donc un peu de données. On utilisera plutôt une variable VHDL. À l'instar d'un signal, elle permet de stocker des données (ici un entier) mais au lieu d'être relative au module elle est relative au processus mais permet d'être écrite plusieurs fois dans le même cycle d'horloge : on ne perd donc pas de données. La probabilité d'une perte de donnée est faible (0,073% de chance pour chaque lecture de valeur à 10 km/h) et l'erreur aussi faible (0,077 mm pour chaque perte), et ce problème aurait certainement pu être négligé par rapport aux dérapages de la roue.

On peut d'ailleurs en profiter pour réduire le nombre entier des valeurs des encodeurs à 16 bits, ce qui laisse au robot le temps de parcourir 5 m sans mise à jour de position avant de faire un dépassement.

Implémentation du filtre pour les interférences

Note : le travail sur le filtre est basé en partie sur le travail réalisé dans le cadre du tutorat de Circuits Numériques Programmables du S7 par Eloi Zalczer et Geoffrey Preud'homme.

Pour filtrer les intérférences et autres valeurs erronées des capteurs de distance, on utilisera un filtre à réponse impulsionnelle finie (ou FIR). L'avantage de ce type de filtres est qu'il est très générique : on peut changer le mode de filtrage (passe-bas, passe-haut...) et ses paramètres (fréquence de coupure...) en changeant les valeurs d'un tableau de coefficients. Plus le nombre N de coefficients est grand, plus Le calcul du signal de sortie se fait simplement en faisant la somme du produit de chaque coefficient par le signal d'entré décalé dans le temps proportionellement à l'indice du coefficient.

Schéma fonctionnel d'un FIR

Les opérations réalisées sont donc de simples retard, additions et multiplications (à l'opposé du filtre à réponse impulsionelle infinie), qui sont des opérations très simple pour le FPGA. Cepedant, les facteurs du filtre sont des décimaux inférieurs à 1, ce que traite difficilement un FPGA. Pour pallier à ce problème, on utilisera la propriété linéaire du filtre : on multipliera les facteurs par un nombre N afin qu'ils signifient quelque chose en tant qu'entier, puis on divisera le résultat par N. Afin de pouvoir effectuer la division simplement sur le FPGA, on prendra une puissnce de 2 comme valeur de N : la division se simplifie alors par un décalage de bits par la droite.

Résumé de l'utilisation du FPGA contenant un filtre à 128 coefficients. À gauche: méthode « immédiate ». À droite méthode « pipeline »

L'implémentation réalisée précédemment calcule la sortie du filtre en un seul front d'horloge. Cette méthode a un avantage : elle est très rapide car prend avantage des ressources du FPGA : chaque multiplication est réalisée en parallèle et chacune utilise une partie des ressources du FPGA (i.e. les tables de correspondances (LUT) et les bascules (flip-flop)). Mais c'est aussi un inconvénient, car ces ressources ne peuvent pas être réutilisées pour quelque chose d'autre. Dans notre cas, la sortie du filtre n'a pas besoin d'être calculée en un coup d'horloge (20 ns), on préfèrera utiliser un fonctionnement dit en « pipeline ». Cela consiste à répartir une partie des calculs sur différents coups d'horloge. Dans notre cas, on effectuera une multiplication et une addition par coup d'horloge. Beaucoup moins de ressources du FPGA seront utilisées, car elles seront utilisées plusieurs fois pour le calcul de plusieurs coefficients (cf capture ci-contre).

On peut remarquer que la méthode « pipeline » utilise un des multiplieurs 18 bits × 18 bits du FPGA. Or, ils n'étaient pas utilisés dans la méthode « immédiate ». On peut supposer ceci : étant donné que les coefficients du filtre étaient fixes, chaque multiplication effectuée possèdait un membre fixe. Les blocs de multiplication ont pu donc être optimisés (par exemple une multiplication par un coefficient de valeur '1' peut être remplacée par une identité).

Corrections après usinage carte 5206

Suite à l'usinage nous avons constaté que le plan de masse n'avais pas été correctement interprété par le logiciel, il s'avère que cette toute première étape avait été mal faite. En effet le polygone permettant de créer la masse comportait un segment supplémentaire qui probablement à causé une mauvaise interprétation du logiciel. Cependant grâce au sauvetage de Mr Flamen, nous pouvons tout de même utiliser la carte afin de réaliser un premier test lors de la semaine de rentrée.

Finalisation avec le "client" des besoins en terme de puissance

A la suite d'une dernière réunion nous avons tranché les besoins et les composants de puissances ont donc pu être commandés.


Semaine 7

I2C et IMU

Après avoir étudié les données que nous fourni l'IMU, étudions d'un peu plus près la communication entre l'IMU et l'Arduino, qui avait été faite par abstraction jusqu'à aujourd'hui. La communication se fait via le protocole I2C. Une communication I2C fonctionne à l'aide de 2 pins, SCL et SDA. La pin SCL fourni une clock à l'IMU pour que celui-ci puisse envoyer ses datas via SDA.

La communication peut se faire à plusieurs vitesses différentes, la commutation des bits se fait sur un intervalle de durée déterminé par le tableau ci-dessous.

Mode tLOWmin tHIGHmin
Standard 4,7 μs 4 μs
Fast 1,3 μs 0,6 μs
Fast plus 0,5 μs 0,26 μs

On remarque que les délais sont assez courts. De plus, l'Arduino ne possède pas d'accélérateur matériel pour ce genre de communication. On en déduit donc que le code d'exemple que nous avons utilisé jusqu'ici gère la communication I2C par le programme, et monopolise le CPU pour avoir un timing conforme.

Or, le problème est que notre Arduino est multi-tâches. A première vue FreeRTOS ne nous autorise pas un contrôle aussi précis d'une tâche, et même si c'était le cas les performances seraient probablement fortement dégradées. On abandonne donc l'idée d'utiliser l'IMU depuis l'Arduino.

Retour sur nos pas

Une confusion avait été faite lors de l'élaboration du système d'inter-communication des périphériques. En effet, on pensait que l'IMU communiquait en SPI au lieu de I2C, protocole de communication pour lequel l'Arduino possède un accélérateur matériel. On va donc devoir repenser ce système.

La solution la plus simple pour passer outre ce problème serait d'utiliser le FPGA pour recevoir les communications I2C et les re-transmettre par la liaison série. Cependant, considérons les choses suivantes :

  • Le Raspberry Pi possède un accélérateur matériel pour les liaisons I2C
  • Le Raspberry Pi possède aussi des broches de sortie tout ou rien et deux sorties PWM, de quoi contrôler les moteurs
  • L'Arduino prend beaucoup de temps à effectuer les calculs en point flottant (environ 7 ms pour simplement calculer la position à partir des informations des codeuses), alors que le Raspberry Pi est beaucoup plus rapide

Il serait beaucoup plus judicieux d'effectuer les calculs de position et d'asservissement directement sur le Raspberry Pi, et s'affranchir complètement de l'Arduino. Et c'est d'ailleurs ce que nous allons faire à partir de maintenant.

Pourquoi ne pas être parti sur cette méthode depuis le départ alors ? La raison principale est qu'il était initialement prévu de réaliser l'asservissement sur le FPGA, et ne faire des calculs de positions qu'à chaque nouvel ordre (soit relativement peu fréquemment). En voyant la possibilité de faire de la fusion de données (pour pouvoir connaitre la position à partir de deux sources, les codeuses et la centrale inertielle), trop compliquée à réaliser sur un FPGA à notre niveau, on a simplement remonté le traitement d'un étage sans se poser de question. Ce qui était une erreur, parce que les calculs en points flottant (qu'on devra utiliser de toute manière si l'on ne veut pas rentrer dans de la théorie mathématique trop poussée pour utiliser des nombres entiers) sur l'Arduino ont une performance très faible. On le savait, mais une autre erreur a été de penser que la latence rajoutée du fait des lents calculs était négligeable par rapport à la latence du Raspberry Pi liée au système d'exploitation. Après avoir vérifié en pratique, il se trouve que c'est même l'inverse.

L'Arduino n'a donc plus aucun rôle à jouer dans le déplacement du robot. Mais le travail réalisé sur la communication Raspberry Pi <-> Arduino et sur la carte de puissance n'est pas perdu puisqu'il y aura toujours un Arduino sur le robot pour réaliser les actions nécessaires pour le client mais hors du contexte du projet. De plus une partie sera réutilisée pour la communication Raspberry Pi <-> FPGA.

Voici donc ci-dessous le système de communication repensé. A noter qu'une confusion avait été aussi faite précédemment sur le système de communication de l'écran LCD, qui est lui aussi en I2C et non en SPI. Cependant cela ne pose pas de problème car le protocole I2C supporte le mode maître-esclave et que l'écran ne sera pas mis à jour très régulièrement.

TODO Exporter Communication.xml en PDF et le convertir en SVG

Semaine 8

Carte de puissance 24V

Nous avons pu tester notre composant de puissance 24V, nous avons ainsi pu noter que : le composant est capable de délivrer un 24V continu on note un décrochage à 8,5V et une tension d'accrochage à 9V. Certaines fonctionnalités des pins Sense et du ON/OFF ont été vérifiée à l'aide d'un potentiomètre mais nous n'en aurons pas l'usage. Cependant pour respecter le choix du client nous garderons toutes les pins disponibles pour assurer la modularité du composant à long terme. Plusieurs modifications doivent donc être ajoutées au design du PCB.

Documents Rendus

Bibliographie