Notre objectif consiste à présenter à l'écran d'un ordinateur, sous la forme d'un graphique cartésien qui se met à jour en temps réel, les mesures prises par un capteur branché à une carte Arduino, elle-même branchée à un des ports USB de l'ordinateur. Pour ce faire, nous utiliserons un script en langage Python ainsi que les bibliothèques matplotlib et pyserial.
Circuit
Pour mes tests, j'ai utilisé en guise de capteur un simple potentiomètre contrôlant la tension à l'entrée A0 d'un Arduino Uno. Il va sans dire qu'en modifiant légèrement le sketch, vous pouvez remplacer ce potentiomètre par n'importe quel type de capteur.
Sketch de l'Arduino
Comme vous pouvez le constater ci-dessous, le sketch versé dans l'Arduino est plutôt bref. Il se limite à attendre la réception d'un message UART en provenance de l'ordinateur. Chaque fois que l'Arduino reçoit le caractère 'e", il envoie à l'ordinateur un message constitué de la mesure de l'entrée analogique A0 et de l'instant où cette mesure à été prise. Ce temps est remis à zéro lors de la réception du caractère 'i'.
-
-
Installation des bibliothèques matplotlib et pyserial
Le script en Python qui sera exécuté sur l'ordinateur aura besoin de la bibliothèque pyserial, qui gère la communication série, et de la bibliothèque matplotlib, qui se spécialise dans la présentation de données sous forme de graphique.
On peut les installer avec pip:
pip install pyserial
pip install matplotlib
Vous trouverez quelques informations supplémentaires concernant l'utilisation de ces bibliothèques dans ces récents billets, qui sont les précurseurs du présent article: Communiquer en Python avec un Arduino (pyserial) et Rasbperry Pi, présenter les mesures sous forme de graphique cartésien (matplotlib).
Script en Python pour l'ordinateur
Le script fait d'abord un scan des ports série actifs: s'il n'en trouve qu'un seul, il établit la connexion avec ce port. S'il en trouve plusieurs, il demande à l'utilisateur de choisir le port série souhaité. L'utilisateur doit également choisir à quelle fréquence les mesures seront prises (dans mon cas, le maximum était d'environ 1000 mesures par seconde; au-delà, le graphique ne se trace pas).
Le script envoie ensuite le message 'i' à l'Arduino afin de remettre son chronomètre à zéro, et lui envoie régulièrement le signal 'e' pour lui demander une nouvelle mesure, qui est ajoutée au graphique.
-
-
Résultat
Voici un exemple de graphique tracé pendant que je tourne lentement le bouton du potentiomètre.
À lire aussi
Puisque je m'intéresse beaucoup à l'utilisation de l'Arduino comme instrument de mesure scientifique, d'autres façons d'arriver à des résultats similaires ont été explorés dans le passé: graphique cartésien sur Android (avec MIT App Inventor 2), graphique cartésien sur écran OLED SH1106 ou sur LCD Nokia 5110, envoi des données à un tableur (Excel ou Libre Office Calc), utilisation d'une carte Leonardo pour écrire les données dans un tableur, utilisation du service en ligne Carriots, enregistrement des données sur une carte SD, etc.
Personnellement, j'aime bien la solution abordée dans le présent article: il est facile de modifier le script Python selon nos besoins.
Yves Pelletier (Twitter, Facebook)
Circuit
Pour mes tests, j'ai utilisé en guise de capteur un simple potentiomètre contrôlant la tension à l'entrée A0 d'un Arduino Uno. Il va sans dire qu'en modifiant légèrement le sketch, vous pouvez remplacer ce potentiomètre par n'importe quel type de capteur.
Sketch de l'Arduino
Comme vous pouvez le constater ci-dessous, le sketch versé dans l'Arduino est plutôt bref. Il se limite à attendre la réception d'un message UART en provenance de l'ordinateur. Chaque fois que l'Arduino reçoit le caractère 'e", il envoie à l'ordinateur un message constitué de la mesure de l'entrée analogique A0 et de l'instant où cette mesure à été prise. Ce temps est remis à zéro lors de la réception du caractère 'i'.
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
L'Arduino émet par communication série | |
les mesures d'un capteur (un potentiomètre | |
branché à l'entrée A0). | |
Plus d'infos: | |
https://electroniqueamateur.blogspot.com/2019/12/graphique-en-temps-reel-des-mesures.html | |
*/ | |
unsigned long tempsDebut; | |
void setup() { | |
Serial.begin(115200); | |
} | |
void loop() { | |
int messageRecu = 0; | |
unsigned long valeurx; | |
int valeury; | |
if (Serial.available() > 0) { | |
messageRecu = Serial.read(); | |
if (messageRecu == 'i') { // commande d'initialisation | |
tempsDebut = millis(); // remise à zéro du chronomètre | |
} | |
if (messageRecu == 'e') { // commande d'envoi de données | |
valeurx = millis() - tempsDebut; | |
valeury = analogRead(A0); | |
Serial.println(String(valeurx)+' '+String(valeury)); | |
} | |
} | |
} |
Installation des bibliothèques matplotlib et pyserial
Le script en Python qui sera exécuté sur l'ordinateur aura besoin de la bibliothèque pyserial, qui gère la communication série, et de la bibliothèque matplotlib, qui se spécialise dans la présentation de données sous forme de graphique.
On peut les installer avec pip:
pip install pyserial
pip install matplotlib
Vous trouverez quelques informations supplémentaires concernant l'utilisation de ces bibliothèques dans ces récents billets, qui sont les précurseurs du présent article: Communiquer en Python avec un Arduino (pyserial) et Rasbperry Pi, présenter les mesures sous forme de graphique cartésien (matplotlib).
Script en Python pour l'ordinateur
Le script fait d'abord un scan des ports série actifs: s'il n'en trouve qu'un seul, il établit la connexion avec ce port. S'il en trouve plusieurs, il demande à l'utilisateur de choisir le port série souhaité. L'utilisateur doit également choisir à quelle fréquence les mesures seront prises (dans mon cas, le maximum était d'environ 1000 mesures par seconde; au-delà, le graphique ne se trace pas).
Le script envoie ensuite le message 'i' à l'Arduino afin de remettre son chronomètre à zéro, et lui envoie régulièrement le signal 'e' pour lui demander une nouvelle mesure, qui est ajoutée au graphique.
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
''' | |
Mise en graphique des données reçues de l'Arduino, | |
par le port série. | |
Plus d'infos: | |
https://electroniqueamateur.blogspot.com/2019/12/graphique-en-temps-reel-des-mesures.html | |
''' | |
# bibliothèques nécessaires pour la communication série | |
import serial | |
import serial.tools.list_ports | |
#bibliothèques nécessaires pour le tracé du graphique | |
import matplotlib.pyplot as plt | |
from matplotlib.animation import FuncAnimation | |
temps_pause = 50 # nombre de millisecondes entre 2 mesures consécutives | |
valeurs_x = [] # données en abcisse | |
valeurs_y = [] # données en ordonnée | |
baud = 115200 #vitesse de la liaison série (doit être synchro avec l'Arduino) | |
# routine de mise à jour du graphique | |
def animate(i): | |
#on envoie à l'Arduino le message de requête | |
message = 'e' | |
arduino.write(message.encode('utf-8')) | |
donneesBrutes = arduino.readline()[:-2] | |
if (donneesBrutes): # si on a reçu quelque chose | |
listeDonnees = donneesBrutes.split() # on sépare l'abcisse et l'ordonnée | |
valeurs_x.append(float(listeDonnees[0])/1000.0) # conversion des millisecondes en secondes | |
valeurs_y.append(float(listeDonnees[1])) | |
plt.cla() # on efface le graphique déjà tracé | |
plt.plot(valeurs_x, valeurs_y) # tracé de la courbe | |
plt.title('Mesures du capteur') # titre du graphique | |
plt.xlabel('temps (s)') # identification de l'abcisse | |
plt.ylabel('Valeur mesuree') # identification de l'ordonée | |
print("Recherche d'un port serie...") | |
ports = serial.tools.list_ports.comports(include_links=False) | |
if (len(ports) != 0): # on a trouvé au moins un port actif | |
if (len(ports) > 1): # affichage du nombre de ports trouvés | |
print (str(len(ports)) + " ports actifs ont ete trouves:") | |
ligne = 1 | |
for port in ports : # affichage du nom de chaque port | |
print(str(ligne) + ' : ' + port.device) | |
ligne = ligne + 1 | |
portChoisi = input('Ecrivez le numero du port desire:') | |
else: | |
print ("1 port actif a ete trouve:") | |
portChoisi = 1 | |
# on établit la communication série | |
arduino = serial.Serial(ports[portChoisi - 1].device, baud, timeout=1) | |
print('Connexion a ' + arduino.name + ' a un baud rate de ' + str(baud)) | |
frequence = input("Frequence d'acquisition desiree, en Hz (max: 1000): ") | |
temps_pause = 1000.0/float(frequence) | |
#on envoie à l'Arduino le message d'initialisation | |
message = 'i' | |
arduino.write(message.encode('utf-8')) | |
ani = FuncAnimation(plt.gcf(), animate, interval=temps_pause) # mise à jour du graphique | |
plt.show() #affichage à l'écran | |
else: # on n'a pas trouvé de port actif | |
print("Aucun port actif n'a ete trouve") | |
Résultat
Voici un exemple de graphique tracé pendant que je tourne lentement le bouton du potentiomètre.
À lire aussi
Puisque je m'intéresse beaucoup à l'utilisation de l'Arduino comme instrument de mesure scientifique, d'autres façons d'arriver à des résultats similaires ont été explorés dans le passé: graphique cartésien sur Android (avec MIT App Inventor 2), graphique cartésien sur écran OLED SH1106 ou sur LCD Nokia 5110, envoi des données à un tableur (Excel ou Libre Office Calc), utilisation d'une carte Leonardo pour écrire les données dans un tableur, utilisation du service en ligne Carriots, enregistrement des données sur une carte SD, etc.
Personnellement, j'aime bien la solution abordée dans le présent article: il est facile de modifier le script Python selon nos besoins.
Yves Pelletier (Twitter, Facebook)
Gardé dans les tablettes... Une fois réadapté pour ma charge électronique DIY je pourrais afficher et enregistrer mes courbes de décharge de mes batteries...
RépondreSupprimerMerci au débutant en Python que je suis Pascal / F4CVM
Bonjour,
RépondreSupprimerLignes 31 et 75 du script python :
arduino.write("i")
Mon linux n'aime pas. Je remplace par pour que ca marche
arduino.write(bytes("e", 'utf-8'))
"e" ou "i" bien entendu
Change le par :arduino.write(b'i') et arduino.write(b'e')
SupprimerBonjour j'aimerais savoir si le code peut être ajusté et exécuté avec 4 tracés de lecture de pression simultanément. Les capteurs agissent comme de potentiomètres.. j'en ai fait l'essai dans les entrés analogues. J'aimerais vraiment pouvoir l'adapter a un banc d'essai. Merci pour la réponse
RépondreSupprimer