jeudi 7 juillet 2022

Affichage sur un PC d'un graphique montrant les mesures prises par un Raspberry Pi Pico

Ce projet consiste à afficher à l'écran d'un ordinateur un graphique cartésien qui montre les données transmises par un Raspberry Pi Pico branché à un de ses ports USB (il s'agit d'un projet similaire à celui que j'avais réalisé il y a quelques années avec un Arduino).


Les donnés sont acheminées du Raspberry Pi Pico à l'ordinateur par une communication série à travers le câble USB. Le Raspberry Pi Pico est programmé en MicroPython, alors que l'ordinateur affichant le graphique exécute un script en Python en utilisant la bibliothèque Matplotlib.

Circuit

Pour faire mes tests, j'ai utilisé un potentiomètre branché à la broche GP26 du Raspberry Pi Pico. Il sera facile de modifier le script pour remplacer le potentiomètre par un capteur de votre choix.


Script en Micropython exécuté par le Raspberry Pi Pico

Le rôle du Raspberry Pi Pico se résume à peu de chose. D'abord, il doit vérifier s'il reçoit un message en provenance de l'ordinateur. Si c'est le cas, il doit envoyer à l'ordinateur la mesure du capteur ainsi que le moment où cette mesure a été prise.

L'envoi de données du Raspberry Pi Pico vers l'ordinateur se fait tout simplement par la commande "print()".

La réception d'un message série par le port USB est un peu plus compliquée et, surtout, moins intuitive. Il s'agit des lignes 20, 21, 24 et 25 du script (ça nécessite également l'inclusion des bibliothèques sys et select):

poll = select.poll() 
poll.register(sys.stdin, select.POLLIN)
res = poll.poll()     
mess = res[0][0].read(1) 

-

'''
Affichage d'un graphique à l'écran d'un ordinateur
auqel est branché un Raspberry Pi Pico, par USB.
Ceci est le script du Pico.
Pour plus d'infos, lire cet article:
https://electroniqueamateur.blogspot.com/2022/07/affichage-sur-un-pc-dun-graphique.html
'''
import time
import sys
import select
import machine
tempsDebut = time.time_ns() # sera soustrait de chaque temps
pot = machine.ADC(26) # broche GPIO26 en entrée analogique
poll = select.poll() # pour la réception des messages par USB
poll.register(sys.stdin, select.POLLIN) # pour la réception des messages par USB
while True:
res = poll.poll() # avons-nous reĉu un message?
mess = res[0][0].read(1) # lecture du message
if (mess == 'e'): # on nous demande une donnée
temps = int((time.time_ns()-tempsDebut)/1000000)
print(str(temps) + ' ' + str(pot.read_u16()))
if (mess == 'i'): # on initialise le temps pour un nouveau graphique
tempsDebut = time.time_ns()
view raw graphPico.py hosted with ❤ by GitHub

Script en Python exécuté par l'ordinateur auquel est branché le Raspberry Pi Pico

Sur l'ordinateur hôte, le script est plus élaboré. Si ce n'est pas déjà fait, il faut d'abord installer la bibliothèque Matplotlib , qui prend en charge le tracé du graphique (si vous utilisez Thonny, l'installation est très facile en passant par le menu "Outil - Gérer les plugin...").  La méthode FuncAnimation() permettra une mise à jour régulière du graphique en y ajoutant de nouvelles mesures.

Le script cherche d'abord un port série disponible, et il s'y branche s'il n'en trouve qu'un seul (il demande à l'utilisateur de faire un choix s'il en trouve plusieurs). L'utilisateur doit ensuite choisir le nombre de secondes qui s'écouleront entre deux mesures consécutives.


Un graphique s'affiche alors à l'écran de l'ordinateur, et il se met à jour au rythme qui a été choisi par l'utilisateur. Voici un graphique obtenu pendant que je tournais lentement le bouton du potentiomètre.


Lorsqu'il est temps de prendre une nouvelle mesure, le script envoie le message "e" au Raspberry Pi Pico.
Le message "i" est envoyé au début d'un graphique, pour que le temps initial du graphique soit nul.

-

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Affichage d'un graphique à l'écran d'un ordinateur
auqel est branché un Raspberry Pi Pico, par USB.
Ceci est le script du PC. Il faut avoir installé Matplotlib.
Pour plus d'infos, lire cet article:
https://electroniqueamateur.blogspot.com/2022/07/affichage-sur-un-pc-dun-graphique.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 = 1 # 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 au pico le message de requête
message = 'e'
pico.write(message.encode('utf-8'))
donneesBrutes = pico.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
pico = serial.Serial(ports[portChoisi - 1].device, baud, timeout=1)
print('Connexion a ' + pico.name + ' a un baud rate de ' + str(baud))
reponse = input("Nombre de secondes entre 2 mesures consecutives: ")
temps_pause = float(reponse) * 1000.0 # conversion en millisecondes
#on envoie au pico le message d'initialisation
message = 'i'
pico.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")
view raw graphOrdi.py hosted with ❤ by GitHub

-

Astuce: exécution des deux scripts avec Thonny

Il est possible d'exécuter les deux scripts en utilisant Thonny, sans que Thonny n'intercepte les messages envoyés par le Raspberry Pi Pico. Voici comment j'ai procédé:

- J'ai d'abord exécuté le script sur le Pico au moyen de Thonny, en utilisant l'interpréteur Micropython approprié.

- J'ai ensuite sélectionné le menu "Exécuter - Déconnecter" sur Thonny. Cette action a pour effet d'interrompre les communications entre Thonny et le Raspberry Pi Pico, mais elle n'interrompt pas le script, qui continue son exécution de façon autonome.


- Finalement, j'ai changé d'interpréteur (menu "Exécuter - Sélectionner l'interpréteur...") et j'ai exécuté le deuxième script directement sur le PC.


Il existe d'autres options possibles, comme installer le premier script dans le Pico en le nommant "main.py" pour qu'il s'exécute automatiquement.


À lire également:

Yves Pelletier (Facebook)


Aucun commentaire:

Enregistrer un commentaire