Exemples Phyque
Exemples Phyque
Exemples Phyque
Nous allons commencer avec deux exemples très simples pour mettre en évidence tout le potentiel de cette carte dans
les expériences de physique ou de chimie au lycée.
• Le premier exemple nous permettra de commander en allumage une diode RGB grâce aux entrées/sorties
numériques
• Le deuxième concerne l’utilisation d’une entrée analogique propre à la réception d’informations lors de la mise
en fonctionnement d’un capteur.
4.1 Synthèse additive des couleurs avec un actionneur de type diode électroluminescente RGB
Dans un premier temps, l’objectif est d’utiliser une DEL capable de produire trois couleurs différentes et de réaliser une
synthèse additive avec les couleurs rouge, vert et bleu.
4.1.2 La réalisation
13. À partir du programme test (cf 2.5), écrire un programme Arduino permettant de faire clignoter la LED avec une
fréquence de 1 Hz et avec une alternance des couleurs Rouge, Vert, Bleu.
14. Modifier votre programme pour obtenir le clignotement de la LED mais avec l’alternance de couleurs Jaune,
Cyan, Magenta et Blanc.
15. Combien de couleurs peut-on obtenir en utilisant la fonction digitalWrite ?
16. Il est possible d’augmenter le nombre de couleurs grâce à la fonction : analogWrite. Lire l’API Arduino pour
comprendre l’utilisation de cette fonction.
17. Écrire un programme Arduino permettant d’obtenir quatre niveaux d’intensité différents sur un même canal
(0, 75, 125, 250) avec un changement toutes les secondes. Attention il faudra peut-être modifier la position de
votre DEL suivant vos attentes. En effet seules les broches précédées d’un ∼ sont utilisables avec la fonction :
analogWrite
18. Combien de couleurs peut-on obtenir avec la fonction : analogWrite ?
Deux possibilités s’offrent à nous. Soit on utilise un stroboscope classique que l’on trouve normalement au laboratoire
de physique ou bien il peut être remplacé par une application smartphone.
• Télécharger n’importe quelle application de stroboscope sur votre smartphone, pour cette expérience j’ai utilisé
Stroboscopique
• ou télécharger l’application Physics Toolbox Suite, puis cliquer sur stroboscope dans le menu de gauche.
• Régler la fréquence sur 1 Hz
• Placer le flash de votre téléphone au dessus de la photorésistance ou de la photodiode
Le code Arduino associé à cette expérience est extrêmement simple, il nous suffit juste de lire les valeurs envoyées
par le capteur (photorésistance ou photodiode) sur une des entrées analogiques de la carte Arduino. Rappelez-vous,
celle-ci propose 6 entrées analogiques ( de A0 à A5) connectées à un convertisseur analogique-numérique 10 bits (210
valeurs possibles de 0 à 210 − 1). Ce qui permet de transformer la tension d’entrée comprise entre 0 et 5V en une valeur
numérique entière comprise entre 0 et 1023. La résolution (écart entre 2 mesures) est de : 5 volts / 210 intervalles, soit
0.0049 volts (4.9 mV).
1 // Variables à déclarer
2
3 void setup ( ) {
4 Serial . begin ( 1 9 2 0 0 ) ;
5 }
6
7 void loop ( ) {
8 // À compléter // valeur numérique lue sur la broche A0
9 Serial . print ( valeur ) ; // Envoi la mesure au PC par la liaison série (port USB)
10 Serial . print ( "\t" ) ; // Ajout d’un espace
11 Serial . println ( m i l l i s ( ) ) ; // Envoi de la valeur temps puis retour à la ligne
12 // Une éventuelle temporisation
13 }
Nous allons maintenant utiliser Python pour automatiser la gestion des données envoyées par le capteur. Pour cela il
faut commencer par ouvrir un nouveau notebook que l’on pourra renommer : stroboscope
Dans la première cellule de code recopier les importations des packages nécessaires à la gestion de cet exemple.
Code Python
Dans une deuxième cellule nous allons nous concentrer sur l’écriture du code principal permettant de récupérer et
d’organiser les données. Attention la connexion Python avec le port série demande à être adaptée en fonction de votre
système d’explotation (3.4.2).
• lignes 9 et 10 : déclaration de deux listes qui recevront les mesures de l’expérience (comme dans les colonnes
d’un tableur).
• ligne 11 : On vide la mémoire tampon de la liaison série. Cela permet d’effacer d’éventuelles données de l’acquisi-
tion précendente restées en mémoire.
• ligne 12 : On démarre une boucle qui permet de récupérer 1 000 valeurs. Toutes les instructions associées à la
boucle sont indentées.
• ligne 13 : permet de lire le flux de données envoyé sur le port série par Arduino. Rappelez-vous le programme
Arduino envoie deux valeurs sur le port série, le temps et la mesure du capteur. Il faut donc séparer ces deux
valeurs. Pour cela nous utilisons la fonction split(). Elle sépare les valeurs grâce à l’espace que nous avons
laissé et les rangent dans une liste Python. Une liste Python peut-être vue comme un tableau dont chaque case
porte un numéro.
— La première case a le numéro 0.
— Pour ajouter une valeur dans la liste on utilise la fonction append()
— Pour lire la valeur contenu dans la première case de la liste val on écrit : val[0], pour lire la valeur contenue
dans la n ième case on écrit : val[n], pour lire les valeurs comprises entre les cases n et m incluses on écrit :
val[n : m+1]
• ligne 14 : try permet de gérer une erreur d’exécution dans un programme sans pour autant que le programme
s’arrète brutalement.
Le mécanisme de gestion des exceptions s’effectue en deux phases :
— La levée d’exception avec la détection d’erreurs : le problème se trouve lignes 15 et 16 lors de la conversion.
— Le traitement approprié : ligne 20 nous décidons de ne rien faire avec le mot clé pass
• ligne 15 à 18 : Nous essayons de convertir les données reçues en valeurs décimales et nous les ajoutons aux
listes temps et mesure . N’oublions pas que les données envoyées par Arduino sont au format texte. Il est donc
nécessaire de les convertir en valeur numérique. La conversion réalisée est de type float soit des valeurs décimales.
• ligne 19 et 20 : Si cela ne marche pas, on passe et on lit une nouvelle ligne envoyée par Arduino
Normalement plus de mystère vous pouvez maintenant recopier le code correspondant à l’acquisition des mesures. Le
gros avantage c’est que l’on écrit le code une fois pour toute. Il peut même être déja disponible dans un notebook que
vous donnez à vos élèves. Mais rien n’empèche de le modifier pour satisfaire une demande particulière.
L’affichage sous la forme d’un graphique
1 # On évite les effets de bord en éliminant
2 #les valeurs de début et de fin de transmission
3 p l t . plot ( temps [ 1 0 0 : 9 0 0 ] , mesure [ 1 0 0 : 9 0 0 ] )
4 p l t . x l a b e l ( "Temps (s)" )
5 p l t . y l a b e l ( "Intensité" )
6 p l t . g ri d ( )
7 p l t . show ( )
On voit qu’après chaque flash (supposé suffisamment court), le photorécepteur reste conducteur pendant une durée
qui va dépendre du type de photorécepteur
• pour la photodiode temps de réponse très court de quelques microsecondes. Cela illustre la bonne réponse en
fréquence de la photodiode.
• pour la photoresistance un temps de réponse relativement court mais elle reste conductrice durant plusieurs
dixièmes de secondes
On peut améliorer la lecture du flux de données afin d’assouplir l’utilisation du code Python. Pour cela nous allons
écrire deux fonctions Python dont nous détaillerons l’utilisation.
1 def a c q u i s i t i o n (n , s e r i a l _ p o r t ) :
2 ’’’
3 Cette fonction permet de faire l’acqusition des données
4 en fonction du temps reçues par le port USB.
5 Elle renvoie deux listes : temps et mesures (du capteur)
6
7 n <int> : nombre total de valeurs à lire
8 serial_port <serial> : le port série ouvert à la communication
9 ’’’
10 i = 0
11 temps , mesures = [ ] , [ ]
12 while i < n :
13 v a l = s e r i a l _ p o r t . readline ( ) . s p l i t ( )
14 try :
15 t = float ( v a l [ 1 ] )
16 m = float ( v a l [ 0 ] )
17 temps . append ( t )
18 mesure . append (m)
19 i = i + 1
20 except :
21 pass
22 return temps , mesures
23. Comment le code de la fonction acquisition a t-il été modifié par rapport au code précédent et pourquoi ?
Dans l’exemple précédent l’acquisition dépend d’un nombre de points. Mais il est souvent plus utile de pouvoir
contrôler le temps d’acquisition. Le code Arduino ne change pas et le code Python ne va subir qu’une toute petite
modification au niveau de la boucle. Au lieu de compter un nombre de points nous allons définir un temps d’acquisition.
Rappelons que le code Arduino transmet à chaque itération de la fonction loop une ligne contenant une valeur et une
date d’acquisition. Pour contrôler le temps d’acquisition il suffit donc de surveiller la différence entre la date en cours
d’acquisition et la date du début d’acquisition. Comme les dates d’acquisition sont dans une liste temps, nous allons
surveiller temps[-1] - temps[0] avec :
• temps[-1] le dernier élément de la liste temps
• temps[0] le premier élément de la liste
24. Écrire une fonction acquisition_temps(duree, serial_port) qui prend en paramètres la durée d’acquis-
tion et la connexion au port série. Cette fonction renvoie dans l’ordre la liste des dates et mesures de l’acquisition.
L’objectif est d’ajouter à l’expérience du stroboscope, un bouton poussoir pour déclencher l’acquisition coté Arduino
afin que Python puisse enregistrer les données transférées. Dans cet exemple, très fortement inspiré d’une activité de
Jean-Luc Charles 5 , nous parlerons d’automate.
Concept d’automate
Un automate fini est un modèle mathématique des systèmes ayant un nombre fini d’états et que des actions (externes
ou internes) peuvent faire passer d’un état à un autre.
La broche numérique 3 de la carte Arduino est utilisée comme une entrée numérique qui reste à LOW tant que le
bouton n’est pas enfoncé. Le bouton se comporte comme un intérrupteur qui ne laisse pas passer le courant tant qu’il
est en position haute. Dans cet exemple la broche 3 est en mode INPUT : pinMode(3, INPUT), pour indiquer que la
broche est en mode lecture. Elle ne va donc pas piloter du courant, mais être à l’écoute du courant qui lui arrive.
5. Jean-Luc Charles, enseignant chercheur à l’ENSAM Talence
Coté Arduino ça donne quoi ? Commençons par les variables globales et la fonction setup
Comme convenu dans l’introduction nous avons défini les différents états de notre automate et initialisé une va-
riable oldEtatBP qui nous permettra de garder en mémoire l’état du bouton avant un nouvel appui. On remarquera
également que l’état de notre automate est WAIT, nous attendons le démarrage de l’acquisition.
1 void loop ( ) {
2 int etatBP = digitalRead (BP ) ; // Lecture du bouton
3 if ( oldEtat == LOW && etatBP == HIGH ) { //gestion des états
4 if ( e t a t == WAIT)
5 {
6 e t a t = START ;
7 }
8 else if ( e t a t == STOP)
9 {
10 e t a t = START ;
11 }
12 else if ( e t a t == START)
13 {
14 e t a t = STOP ;
15 }
16 }
17 //Traitement des états
18 if ( e t a t == START ) {
19 int valeur = analogRead ( broche ) ;
20 Serial . print ( valeur ) ;
21 Serial . print ( "\t" ) ;
22 Serial . println ( m i l l i s ( ) ) ;
23 }
24 oldEtat = etatBP ;
25 delay ( 1 0 ) ;
26 }
25. Modifier le programme pour que lorsque l’acquisition s’arrète, c’est à dire que l’on appuie sur le bouton pour la
deuxième fois, la chaîne -1\t -1 s’affiche dans le moniteur série. Attention dans le moniteur série le \t sera
remplacé par une tabulation.
Attention le code Arduino ci-dessous fonctionnera correctement uniquement si vous avez répondu à la question
précédente, si cela pose un problème consulter la solution dans les annexes, compléter le code Arduino et poursuiver.
1 # les modules à importer
2 import serial
3 import matplotlib . pyplot as p l t
Pour tester l’ensemble, assurez-vous que vous avez bien effectué les étapes de la section précédente coté Arduino :
• Valider les cellules du Notebook.
• Normalement sur la gauche de la deuxième cellule vous observez une petite étoile : In [*]
• Pas de panique avec le bouton on a tout notre temps.
• Positionner votre stroboscope au dessus de la photorésistance
• Lancer l’acquisition des valeurs en appuyant une première fois sur le bouton.
• Terminer l’acquisition en appuyant une deuxième fois sur le bouton, si tout c’est bien passé l’étoile de votre In [*]
disparait pour laisser place à un nombre.
• Afficher vos résultats dans un graphique.
À chaque fois que l’on termine une acquisition il faut revalider la cellule du notebook contenant le code ci-dessus pour
mettre en attente le code Python d’une nouvelle acquisition. L’instruction serial_port.close() réinitialise le code
Arduino et met donc l’automate coté Arduino dans l’état WAIT. Il n’y a plus qu’à appuyer sur le bouton...
La dépendance en température d’une résistance CTN n’est pas linéaire, elle peut être bien approximée en fonction de
la résistance R T h de la thermistance à l’aide de la relation suivante :
1
θ= − 273.15
RT h
µ ¶
ln
R0 1
+
β T0
β est une constante de température (kelvin), R 0 est une résistance de référence (ohms) et T0 est la température à
laquelle s’applique la résistance de référence (kevlin). Ces constantes sont caracteristiques de la thermistance utilisée.
Il est possible d’acheter des thermistances CTN (10K) étanches pour un prix très raisonnable (< 1 € ref : NTC Thermis-
tance précision capteur de température 10 K 1% 3950 Sonde Étanche 1 m)
• β = 3380 K ± 1%
• R 0 = 10 kΩ ± 1%
• plage de mesure :-20 à 105 o C avec T0 ' 298 K
Coté Arduino
Le code à compléter ci-dessous peut-être l’occasion de discuter de la conversion d’une valeur numérique codée sur 10
bits (A0 et A1) en valeur analogique. Pour compléter ce code nous pourrons utiliser la fonction map.
Il est possible d’obtenir des informations supplémentaires et des exemples liés à cette fonction avec l’API d’Arduino.
Coté Python
Dans la cellule des modules à importer rien de nouveau à part la ligne 6. Dans les exemples précédents, nous avions
l’habitude d’écrire %matplotlib inline. Nous avons remplacé inline par auto afin de pouvoir afficher une fenêtre
extérieure au Notebook. Cette fenêtre offre quelques fonctionnalités de base étendues comme la possibilité de suivre la
courbe avec un réticule.
La cellule suivante donne la définition d’une fonction permettant d’effectuer la synchronisation temporelle pour le
transfert des valeurs entre Arduino et Python. Les instructions liées à cette fonction ont déjà été décrites dans la partie
Communication Arduino - Python via le port série
1 # Cellule 2
2 def synchro_arduino ( port_name , v i t e s s e ) :
3 """
4 Cette fonction initialise et renvoie une référence sur la connexion
5 avec la carte arduino à travers le port série (USB).
6 Elle permet également de synchroniser le lancement de l’acquisition
7 coté Arduino avec la récupération des données coté Python.
8 """
9 s e r i a l _ p o r t = serial . Serial ( port = port_name , baudrate = v i t e s s e )
10 s e r i a l _ p o r t . setDTR ( False )
11 time . sleep ( 0 . 1 )
12 s e r i a l _ p o r t . setDTR ( True )
13 s e r i a l _ p o r t . flushInput ( )
14 return s e r i a l _ p o r t
À vous de compléter la fonction modelisation_CTN afin de calculer la température correspondante aux mesures
reçues par Python.
1 # Cellule 3
2 def modelisation_CTN ( mesures ) :
3 """
4 Cette fonction réalise le traitement des données, associées au capteur
5 thermistance, reçues de la carte Arduino.
6 Elle renvoie :
7 tensionU -> float : la tension délivrée par la carte Arduino
8 tensionUther -> float : la tension aux bornes du capteur
9 Rther -> float : la valeur de la résistance de la thermistance
10 temps -> float : la date de la mesure
11 temperature -> float : la valeur de la temperature
12 Elle prend en argument la liste des mesures effectuées par Arduino
13 tensionU -> float
14 tensionUther -> float
15 temps -> float
16 """
17 Rzero = 10000 # en ohms
18 beta = 3380 # en Kelvins
19 Tzero = 298 # en Kelvins
20
21 tensionU , tensionUther , temps = mesures
22
23 Rther = tensionUther * ( 1 / ( tensionU−tensionUther ) * Rzero )
24 temperature = # À compléter
25
26 return tensionU , tensionUther , Rther , temps , temperature
La dernière cellule concerne essentiellement l’affectation des valeurs à afficher à la bonne structure de données, dans
notre cas des listes Python. Cette cellule est pratiquement identique à celle des exercices précédents sans le bouton
poussoir. Libre au lecteur de l’adapter s’il en ressent le besoin. J’ai juste ajouté le formatage des données pour une
bonne lecture dans la sortie du Notebook. J’ai essayé de faire en sorte que cela ressemble à un tableau. On peut faire
bien mieux en utilisant un module plus adapté comme Pandas avec ses DataFrames mais cela sortirait du cadre de
cette formation.
1 # Cellule 4
2 # ouverture du port série
3 s e r i a l _ p o r t = synchro_arduino ( "/dev/ttyACM0" , 9600)
4
5 # les mesures
6 temperature = []
7 temps = []
8 duree = 100 # en seconde (1min 40s)
9 end = False
10
11 # On s’occupe de l’affichage des résultats
12 head = "tensionU\t tensionUther\tRther\ttemps\ttemperature\n"
13 print ( head . expandtabs ( 1 0 ) )
14 fmt = "{0:.2f}\t{1:.2f}\t{2:.2f}\t{3:.2f}\t{4:.2f}" . expandtabs ( 1 6 )
15
16 # on récupère les données et on modélise
17 while end == False or temps[ −1] − temps [ 0 ] < duree :
18 data_arduino = s e r i a l _ p o r t . readline ( ) . s p l i t ( )
19 try :
20 mesures = np . array ( data_arduino , dtype=’float’ ) # String -> flottant
21 mesures = modelisation_CTN ( mesures ) # Calcul température
22 temps . append ( mesures [ 3 ] ) # remplissage liste des temps
23 temperature . append ( mesures [ 4 ] ) # remplissage liste des températures
24 print ( fmt . format ( * mesures ) ) # formatage de l’affichage
25 end = True
26 except :
27 pass
28 # fermeture du port série
29 s e r i a l _ p o r t . close ( )
De nombreuses expériences sont possibles, pour ma part j’ai déposé quelques glaçons dans le fond d’un premier
récipient avec un peu d’eau puis j’ai rempli un deuxième récipient avec un peu d’eau à la température de la pièce.
• Téléverser le code Arduino dans la mémoire de la carte
• Valider les cellules 1, 2 et 3
• Plonger la thermistance environ 30 secondes dans le récipient avec les glaçons
• Plonger la thermistance dans l’eau du deuxième récipient puis valider la cellule 4
Voici les résultats obtenus dans le Notebook
Exploitation
Le temps de réponse t 90% peut ainsi être calculé facilement avec Python