Sur TangenteX.com, nous utilisons la plupart du temps l’informatique pour construire des programmes de simulation ou de calcul. Aujourd’hui, je vous propose d’explorer une autre utilisation des moyens informatiques : l’acquisition et le traitement de données. L’objectif est de comprendre le fonctionnement d’un système d’acquisition de données, tant sur le plan théorique que pratique. Nous utiliserons les connaissances que les élèves de terminale S abordent maintenant concernant le traitement des informations analogiques : échantillonnage, numérisation, stockage.
Pour aborder ce domaine très vaste, j’ai choisi une expérience simple, la décharge d’une pile dans une résistance et un outil, l’Arduino. De manière pas très logique, mais vous me pardonnerez, nous allons d’abord étudier l’outil.
L’Arduino est une merveille, regardez :
C’est un microcontrôleur monté avec ses circuits d’entrée/sortie sur une petite carte électronique très pratique. Il est capable de mesurer des tensions, et donc d’acquérir des grandeurs physiques qui auront été traduites en tension électrique, comme un courant électrique, une température, une pression, une accélération, etc.
Il est capable de générer des tensions (avec les voies PWM qui peuvent être utilisées en conversion numérique analogique) et donc de produire une information analogique, qui pourra être exploitée par une interface (un moteur, une LED, un outil).
Il peut commander en tout ou rien (ON/OFF) un moteur ou un actionneur une machine ou une LED, par exemple.
Et bien sur, il peut effectuer des traitements informatiques et mémoriser des données. Il a le bon goût d’être programmable en C.
Son utilisation est très simple : vous chargez sur votre PC l’IDE gratuit qui permet de le programmer, vous branchez la carte Arduino sur l’interface USB de votre PC, vous écrivez votre programme (un sketch dans l’argot arduinesque !), vous le chargez dans l’Arduino et vous le lancez. C’est tout !
Il présente une autre possibilité très intéressante : on peut empiler des cartes d’interfaces sur la carte mère (le piggy back cher aux électroniciens) et augmenter ses fonctions. On appelle ces cartes des « shields » dans l’argot arduinesque. Il existe un shield Ethernet, que je vais utiliser pour son lecteur de carte SD, un shield Wi-Fi, un shield GSM, un shield pour contrôler des moteurs et un tas d’autres choses !
En bref, il permet d’opérer sur le monde physique selon un modèle qui aura été programmé. L’Arduino est petit et simple, mais c’est un modèle presque parfait des systèmes de contrôle/commande de l’industrie.
Enfin, signalons que l’Arduino, son hardware et son software sont entièrement libres : vous pouvez le bidouiller ou le reproduire autant que vous voulez, ou même en construire un vous-même !
Le prix : une carte Arduino Uno R3 chez Selectronic vaut 24 euros TTC et 52 euros TTC avec le sheild Ethernet ! Publicité gratuite... Avouez que ce n'est pas cher !
J’utilise la carte standard Arduino Uno revision 3 (R3), dont les caractéristiques techniques principales sont :
Le bootloader est un programme stocké à demeure en EEPROM et accessible par le microcontrôleur à la mise sous tension de la carte. Il permet de gérer la communication avec le PC sur le bus USB et le chargement des programmes depuis le PC.
Il est probable que la mémoire vous surprend par sa très petite taille ! Moi-même, j’ai l’impression de remonter 30 ans en arrière, époque où il fallait économiser chaque octet de la mémoire ! Il faudra donc prendre de bonnes habitudes de programmation et ne pas faire n’importe quoi sans réfléchir à la taille des programmes et des données…
La carte comporte deux rangées de connecteurs dont le brochage est indiqué sur le schéma ci-dessous :
Pour l'application qui nous intéresse, c'est à dire la mesure de tension, voici quelques données supplémentaires tirées de la "data sheet" de l'ATMega328. La fréquence maxima d'échantillonnage avec des mots de 10 bits est de 15 kSPS (kilo Samples Per Second). L'ATMega328 effectue sa conversion analogique/digitale par approximations successives en 260 microsecondes max.
D'après le théorème de Nyquist-Shannon, cela signifie qu'il ne faut pas compter traiter des signaux de fréquence supérieure à 7,5 kHz, disons 7 kHz pour être tranquille. Nous sommes limités à la BF!
Je vous encourage vivement à consulter le site officiel d’Arduino et ne vous plaignez pas vous cultiverez aussi votre anglais!
Pour apprendre à programmer l’Arduino :
Un peu de littérature en français sur l’Arduino :
Bien sur, je n’ai aucune action chez ces éditeurs ni auteurs, bien que je connaisse les publications de Christian Tavernier depuis plus de 30 ans et ses premiers articles dans Microsystème ou le Haut-Parleur avec le microprocesseur Motorola 6800 ! Très vieille histoire !
Bon, revenons un peu à la physique ! Nous allons étudier la décharge d’une pile saline de type Leclanché, qui fonctionne par oxydoréduction du zinc et du dioxyde de manganèse. Pour la description complète de son fonctionnement théorique, je vous renvoie à votre cours de chimie de 1ere S sur la rédox, que bien sur, vous connaissez par cœur. Pour s’amuser, j’ai choisi sa forme la plus simple, une pile plate 3R12, composée de 3 cellules Zn/MnO2 en série, qui délivre chacune une fem de 1,5V. Ma pile délivre donc 4,5 V.
Attention à ne pas utiliser une pile alcaline: sa capacité est bien plus grande et la durée de la manipulation sera beaucoup plus longue! De plus, la courbe de décharge n'est pas la même. Mais bien sur, vous pouvez toujours tenter l'expérience !
Nous allons donc étudier la décharge lente d’une pile dans une charge résistive composée d’une résistance R et d’une diode LED témoin pour animer un peu la manip. Le but est de tracer la courbe U= f(t), U étant la tension aux bornes de la pile, qui évoluera, nous le supposons, au cours du temps. Le courant de décharge sera relativement faible, 120 mA environ, suffisant pour que l'expérience ne dure pas trop longtemps, mais pas assez fort pour griller mes résistances dont la puissance admissible ne dépasse pas 0,5 W.
Imaginez que vous deviez faire l’expérience à la main. Toutes les minutes ou les dix minutes, vous seriez obligés de mesurer la tension aux bornes de la pile puis de reporter les résultats dans un tableau, au mieux sur une feuille Excel. Puis à la fin de la manip, vous devriez tracer une belle courbe sur du papier millimétré. Un peu pénible non ?
Nous allons faire faire tout ça par nos esclaves électroniques, Arduino pour l’acquisition et PC pour le tracé de courbe.
Pour mener à bien notre expérience, nous devons mesurer la tension aux bornes de la pile pendant sa décharge. L’Arduino sait mesurer une tension comprise entre 0 et 5V, avec une précision égale à 5/2^10 V, soit environ 4,8 mV. La pile choisie présente une f.e.m de 4,5 V, ce qui est compatible avec la plage en tension d’entrée de l’Arduino, sans montage d’adaptation en tension, comme des ponts diviseurs de tension ou autre diode Zener.
La première chose à prendre en compte est la durée du phénomène de décharge, qui est de l’ordre de la journée. Le phénomène de décharge est à variation lente, voire très lente et ne présente pas de phénomène transitoire. On peut donc prévoir une fréquence d’acquisition très faible. Il faut faire un compromis entre le nombre de points acquis, la durée du phénomène et aussi la capacité mémoire de stockage pour obtenir un signal le plus représentatif possible.
La carte SD que j'utilise pour stocker les données présente une capacité de 2 Go. De ce coté pas vraiment de limitation. Le théorème simplifié de Nyquist-Shannon stipule que « la représentation discrète d'un signal par des échantillons régulièrement espacés exige une fréquence d'échantillonnage supérieure au double de la fréquence maximale présente dans ce signal ». Dans notre cas, la période est de l’ordre de la journée, et donc la période d’échantillonnage doit être au minimum de l’ordre de la demi-journée. Assez peu contraignant non ! Une mesure toutes les 2 minutes produit 720 mesures en une journée, ce qui est très raisonnable pour tracer une courbe.
S’agissant d’une mesure automatique, il faut définir une condition qui mettra fin à la mesure. Plusieurs possibilités s’offrent à nous :
En fait, la logique de la programmation de l'Arduino complique un peu les choses. Nous verrons plus loin que sa routine principale, la routine loop(), boucle indéfiniment comme son nom l'indique. Il n'y a pas de moyen d'en sortir sinon de faire un reset. J'ai donc choisi une quatrième possibilité, bien que j'ai programmé la troisième. J'ai décidé d'arrêter la manip lorsque la LED rouge témoin de décharge sera éteinte, c'est à dire lorsque la tension à ses bornes sera inférieure à sa tension de seuil, comprise entre 1,6 V et 2 V pour une LED rouge. Cela conviendra bien à notre besoin, qui est de tracer une courbe de décharge pour en examiner sa forme.
Le principe est simple. Je créé un circuit composé d’une pile qui débite dans une résistance de charge montée en série. Pour agrémenter le montage, je disposerai en parallèle sur cette résistance de charge, un groupe série composé d'une LED rouge et d'une résistance limitatrice de courant (une LED fonctionne avec un courant d'environ 20 mA).
Je mesure et j'enregistre la tension aux bornes de la pile.
Le schéma complet de câblage:
Et une photo du montage électronique réalisé sur une plaquette d’essai installée à coté de l’Arduino.
Vous remarquez la LED et sa résistance limitatrice de 220 ohm.
Vous remarquez aussi un groupe de 5 résistances de 220 ohm montées en parallèle. Je m'explique. Pour obtenir un temps de décharge de l'ordre de la journée, sachant que la capacité standard d'une pile saline est en principe de 2700 mAh, il faut faire circuler un courant de l'ordre de 110 mA. J'ai déjà un courant de 20 mA qui circule dans la branche de la LED. Il me faut donc un courant d'environ 90 mA qui circule dans la résistance.
Je sais d'autre part que mes résistances ne supportent qu'une puissance max de 0,5 W, ce qui, d'après la célébre formule P = UI (nous sommes en courant continu), me donne un courant max de I = P/U, soit I = 0,5/4,5 soit environ I = 100 mA. Nous faisons ici de l'électronique, donc vive les ordres de grandeur, pas besoin de sortir la calculette !
Donc, pas de pb pour la valeur du courant, environ 100 mA. Pour calculer la résistance correspondante, j'applique bien sur la célèbre loi d'Ohm, soit U = RI, ce qui me donne R = U/I soit R = 4,5/0,1 = 45 ohm. Attention aux unités quand vous faites les calculs de tête !
Il se trouve que je n'ai pas ça sous la main, je n'ai que des 220 ohm. Donc, j'applique la règle de calcul des résistances en parallèle ! Pour obtenir environ 45 ohm, j'utilise 5 résistances de 220 en parallèle. Et le tour est joué. J'espère que tout le monde a compris, sinon, révision obligatoire du cours d'élec.
Contrôle fait, la résistance équivalente que j'obtiens fait 43 ohm...
Comme vous l'avez vu sur la photo, j'ai câblé tout ça sur une plaque d'essai, un peu à l'arrache, je vous l'accorde. Mais bien sur, vous pouvez faire ça autrement, selon le matériel dont vous disposez.
L’algorithme mis en œuvre sera très simple :
- Nous commencerons par initialiser les circuits d’acquisition et de stockage sur la carte SD de l’Arduino.
- Puis nous construirons une boucle d’acquisition qui déclenchera périodiquement, selon la période d’échantillonnage fixée ci-dessus, les opérations suivantes :
Jusqu’à ce que la tension lue soit inférieure au seuil VMin.
Je vais donc enregistrer, pour chaque mesure, deux valeurs dans un fichier ASCI nommé Pile.txt, afin de pouvoir les traiter plus tard avec un autre programme. Chaque enregistrement du fichier se présentera ainsi:
NumMesure;ValeurMesure
Par exemple:
21;4.648
Vous serez peut-être surpris de constater que le programme de l'Arduino ne réalise que l'acquisition et le stockage des données dans un fichier. C'est ce qu'il fait le mieux !
Ce principe de séparation des fonctions dans plusieurs programmes, un programme d'acquisition, un programme de traitement et un programme de visualisation, est fondateur de l'informatique scientifique. Pour plusieurs raisons:
Comme je vous l'ai dit, l'Arduino se programme en C. Comme dans n'importe quel programme C, le code commence par la liste des headers à inclure. Nous n'en avons qu'un seul, le fichier SD.h qui comprend les ent-têtes de routines de gestion de la carte SD et de son lecteur.
Puis vient la liste des variables globales et des constantes. Arrêtons nous sur les constantes suivantes:
const int Pile = 0; // la pile est branchée sur l'entrée analogique 0
const int LedVerte = 2; // la led verte est branchée sur la sortie 2
const int SDCard = 4; // broche de la SDCard sur le shield Ethernet
const int SelectEther = 10; // broche de sélection du shield Ethernet
Il s'agit de la définition des différents ports du microcontrôleur. La pile sera branchée sur l'entrée analogique A0 de l'Arduino. la LED verte, témoin de mesure, sera branchée sur la sortie analogique 2. La broche 4 de l'Arduino commande le lecteur SD installé sur le shield Ethernet, lequel est adressé sur la broche 10. Inutile de dire que toute erreur dans cette configuration est sanctionnée par le non-fonctionnement du programme !
Un programme Arduino est composé d'au moins deux routines de base : la routine setup() et la routine loop().
La routine setup() s'exécute une seule fois, au démarrage du programme ou à la mise sous tension de l'Arduino. Elle doit contenir le code d'initialisation de la carte et du process. Dans notre cas, il s'agit d'initialiser la carte SD.
Après le setup, l'Arduino passe dans la routine loop() qui boucle indéfiniment jusqu'à ce que l'Arduino soit mis hors tension ou que le bouton Reset soit appuyé.
Notre routine loop() comprend quatre parties:
- La lecture de la tension sur l'entrée A0 et la construction de la donnée "tension":
ValeurCAN = analogRead(Pile);
Tension = map(ValeurCAN, 0, Range, 0, TensionRef);
Tension = Tension / 1000.0;
dtostrf(Tension,5,3,sTension);
Le programme lit une valeur comprise entre 0 et 1023 sur la broche A0 du CAN, qu'il convient de convertir en tension. C'est le rôle de l'instruction map(). La constante TensionRef désigne la tension de référence de l'Arduino, fixée à 5 V. On peut aussi se priver de l'usage de map() en faisant une simple règle de trois, mais je trouve que l'usage de map() est plus propre.
La tensoin calculée par map() est exprimée en millivolt, je la convertis en V en divisant pas 1000.0. Attention à exprimer 1000.0 en float !
La dernière instruction convertit la valeur float de la tension en une chaine de 5 caractères avec 3 chiffres après la virgule (ex: 4.876)
- Le stockage des données, numéro de mesure et valeur de la tension lue, sur la carte SD et l'incrémentation du numéro de mesure:
Buffer = "";
Buffer = String(NumMesure,DEC) + ";" + String(sTension);
SDFile = SD.open("Pile.txt", FILE_WRITE); // ouvre le fichier en écriture
if (SDFile)
{
SDFile.println(Buffer); // écriture des données
SDFile.close(); // fermeture du fichier
}
else
{
// Serial.println("Erreur a l'ouverture du fichier de donnees");
return;
}
// Incrémentation du compteur de mesure
NumMesure++;
Vous noterez que je ferme le fichier de mesures après chaque écriture. C'est une habitude lorsqu'on fait de l'acquisition à faible fréquence. Si le dispositif se plante entre deux mesures, ce qui peut arriver, au moins nous ne perdrons pas les mesures déjà faites, ce qui serait probablement le cas si le fichier restait ouvert.
- Le clignotement de la LED, qui indique qu'une mesure vient d'être réalisée, et que le dispositif vit !
digitalWrite(LedVerte,LOW);
delay(500);
digitalWrite(LedVerte,HIGH);
Ces trois instructions permettent d'alimenter la LED verte pendant 500 ms puis de l'éteindre. Attention à l'inversion de logique BAS HAUT qui correspond au câblage. D'ailleurs, j'aurais pu mettre ces trois instructions dans une routine Blink(), par exemple, ça aurait été plus propre...
- La temporisation de mesure, ici une mesure toutes les deux minutes, et la condition de sortie (qui ne sert pas à grand chose !)
if (Tension >= TensionMin)
delay(Tempo); // Temporisation entre deux mesures
else
{
// Serial.println("Fin de la manipulation");
return;
}
Rien à dire, sinon que la constante Tempo vaut 120 000 ms soit 2 minutes. Nous avons donc une mesure toutes les deux minutes.
Le code complet du programme DechargePile est disponible ici. Ppour l'utiliser, vous devez le charger dans l'IDE d'Arduino puis dans l'Arduino après avoir vérifier sa syntaxe et sa bonne compilation.
Pour lancer l'expérience, il faut:
J'ai donc lancé l'expérience un après-midi à 16:10. Voilà à quoi ressemblait ma manip initiale :
Dans cette version initiale, la pile débitait uniquement dans la résistance limitatrice de courant de la diode, d'une valeur de 220 ohm, avec un courant de 20 mA... Je ne vous dis pas la durée de la manip, si je l'avais laissé aller au bout !
Vous notez que l'Arduino est relié à mon PC par un câble USB. D'abord, et surtout, pour l'alimenter électriquement. Et aussi, pour transférer les données à chaque mesure histoire de suivre la manip. Voilà à quoi ressemblait l'écran de mon PC.
A droite, vous voyez la fenêtre de l'IDE d'Arduino et à gauche le moniteur série, qui affiche les valeurs de la tension au fur et à mesure de leur acquisition.
Mais j'avais oublié la mise en veille du PC ! En se mettant en veille prolongée, le PC coupe l'alimentation de la prise USB et par conséquent, l'alimentation de l'Arduino. Donc arrêt des mesures et reprise de celles-ci lorsque le PC sort de veille. Pas terrible! Je pourrais reparamétrer la veille prolongée de mon PC, mais cela m'ennuie de le laisser fonctionner pendant plusieurs jours sans arrêt.
J'ai donc arrêté la manip pour corriger ce léger inconvénient !
En examinant le fichier de données, j'ai aussi constaté des mesures aberrantes, trop basses puis revenant vers 4,5V. En cherchant, je me suis aperçu qu'il s'agissait d'un faux contact dans la soudure du pôle positif de la pile. Honte à moi !
Bref, j'étais condamné à relancer la manip: c'est assez courant en physique expérimentale... Mais j'ai d'abord apporté quelques modifications à mon montage et à mon programme :
J'ai donc repris une pile neuve, en faisant attention à mes soudures, et j'ai relancé la manip, après avoir effacé le fichier de mesures sur la carte microSD bien sur! Le montage modifié :
La tension à vide de la pile était de 5.002 V , mesurée au multimètre de laboratoire.
A la fin de la manip, j'ai éjecté la carte SD de l'Arduino puis j'ai transféré le fichier Pile.txt qui contient les données sur mon PC pour tracer la courbe. Ce fichier fait environ 13 Ko. Attention à stocker ce fichier dans le même répertoire que le script Python TracePile.
Une bonne habitude à prendre est de faire un contrôle visuel du fichier de données (on appelle ça nettoyer les données), histoire de vérifier la qualité des données et les anomalies éventuelles :
J'ai donc parcouru mon fichier Pile.txt, que vous pouvez télécharger ici, et je n'ai pas constaté d'anomalie. Ouf ! je vais donc pouvoir passer directement à la visualisation sans traitement post-acquisition.
Pour tracer la courbe de décharge de la pile, j'ai rédigé un petit script Python qui lira le fichier des données issues de l’expérience et tracera la courbe. Il est disponible ici.
Sa seule particularité est la routine Read_Data qui lit séquentiellement le fichier, découpe chaque enregistrement en ces différents mots (numéro de mesure et valeur de mesure séparés par un ;) et stocke le mot qui nous intéresse (la valeur de mesure) dans la liste Ltension.
A noter la puissance du Python pour effectuer ces opérations, en particulier la méthode split sur la ligne ! Essayez d'écrire ça en C, c'est plus lourd !
def Read_Data(filename):
datafile = open(filename,'r')
Ltension = []
for line in datafile:
data = line.split(";")
tension = float(data[1])
Ltension.append(tension)
datafile.close()
Ltension
La partie affichage du code est elle très classique et n'appelle pas de commentaire.
Voici la courbe de décharge obtenue à partir du fichier de données Pile.txt, à l'aide du programme TracePile:
La décharge a duré bien plus longtemps que prévu. Après 38 heures de décharge, avec un courant de décharge de 120 mA, la tension aux bornes de la pile était encore de 1.388 V. Il aurait fallu mesurer le courant pour savoir ce qu'il en est réellement. D'ailleurs, c'est tout à fait faisable, en branchant en série une résistance de précision et en mesurant la tension aux bornes de cette résistance. Arduino sait faire, il faut le programmer!
La forme de la courbe de décharge est typique de la décharge d'une pile saline : un décroché brutal en début de décharge, puis une décharge à peu près constante mais assez rapide.
La valeur initiale de la tension lue par l'Arduino est de 5.000 V pour 5.002 V lu sur le multimètre de labo. La précision d'Arduino est donc bien dans l'intervalle attendu (4.8 mV).
Vous observerez sur la courbe des petits pics, vers le haut ou vers le bas. Ce sont des points qui s'écartent de la moyenne. Les causes peuvent être multiples. La plupart du temps, il s'agit de bruits d'origine thermique. On observe aussi un décroché curieux vers le pas 500, donc après 17 heures d'expérience, que je ne m'explique pas vraiment.
J'espère que cette petite manip vous aura convaincu de l'intérêt de l'Arduino et, comme moi, vous aura donné envie d'en faire plus ! Vous pouvez l'améliorer en mesurant à la fois la tension et le courant circulant. Ou bien en trouvant une condition d'arrêt plus rigoureuse. Là, j'ai une idée: plutôt que de mettre la boucle d'acquisition dans la routine loop() qui est ingérable, pourquoi ne pas la mettre dans la routine setup() et ne rien faire dans loop() ? Bref, il reste à perfectionner cette manip.
Nous voilà à la fin de cette très brève incursion dans le monde de la mesure assistée par ordinateur. C’est un domaine captivant, qui occupe une foule d’ingénieurs dans l’industrie et la recherche. L’Arduino est un équipement merveilleux avec lequel je compte travailler à nouveau. Vous aurez sans doute l’occasion de rencontrer à nouveau l’Arduino dans les pages de TangenteX.com !
Contenu et design par Dominique Lefebvre - tangenteX.com septembre 2014 -- Vous pouvez me joindre par ou sur PhysiqueX
Cette œuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Pas de Modification 3.0 France .