Moniteur série Python-Arduino

Bonjour, j'aimerai réaliser une sorte de moniteur série sur tkinter qui recoit les infos envoyées sur le port série par l'Arduino et les affiche sur un widget texte. J'ai déjà ce code

from tkinter import *
import tkinter as tk
import tkinter.messagebox
import tkinter.filedialog
from PIL import ImageTk, Image
import serial
 
 
#CRéation de la fenetre
root = tk.Tk() #On initialise la fenetre
root.title('Inetrface')#On nomme la fenetre
 
 
 
 
#Creation de l'arriere plan et de la taille de la fenetee
image1 = ImageTk.PhotoImage(Image.open("Fichiers annexes\Fondd.png"))
w = image1.width()
h = image1.height()
root.geometry("%dx%d+0+0" % (w, h))
fond = tk.Label(root, image=image1)
fond.pack()
 
log = Text( root, width=30, height=30, takefocus=0)
log.place(x=1300, y=300, anchor='w')
 
# make a scrollbar
scrollbar = Scrollbar(root)
scrollbar.pack(side=RIGHT, fill=Y)
 
# attach text box to scrollbar
log.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=log.yview)
 
 
 
arduinoData = serial.Serial('COM8',9600)
 
def quitter():
    root.destroy()
 
 
def Acqard():
    arduinoData.write(b'1')
 
def stopacq():
    arduinoData.write(b'2')
 
 
#Creation du bouton de validation
Bouton = tk.Button(root, text ="LANCER L'ACQUISITION",command = Acqard, font = ('Calibri', 15),  overrelief= 'ridge', bg= "#922c17", fg ="white")
Bouton.place(x=765, y=530, anchor='w')
 
#Création du bouton d'arret de la focntion
Bouton = tk.Button(root, text ="Arreter le scan",command = stopacq, font = ('Calibri', 15),  overrelief= 'ridge', bg= "#922c17", fg ="white")
Bouton.place(x=365, y=530, anchor='w')
 
#Création du bouton de quitter
Bouton = tk.Button(root, text ='Quitter',command = quitter, font = ('Calibri', 15), overrelief= 'ridge', bg= "#47280C", fg ="white")
Bouton.place(x=1550, y=900, anchor='se' )
 
 
 
 
root.mainloop()
 
while 1:
    var = arduinoData.read()
    log.insert('0.0', var)
 
 
root.update


Seulement, le while ne fonctionne pas...

Des idées?

2 réponses

  1. Oui j'ai compris pourquoi le while ne s'executait pas...
    Seulement si je met le while dans la mainloop la fenetre ne s'affiche pas car il n'arrive jamais au mainloop....
    0
    1. Ce n'est pas comme cela que ça fonctionne, si tu mets une boucle while infinie dans ton application graphique, cela aura pour effet de tout geler et par conséquence ne plus avoir aucune interaction avec la fenêtre.

      Il faut alors faire ça avec un thread ou alors avec ce que fournit la bibliothèque graphique pour faire une action périodiquement, dans le cas de tkinter, c'est after.

      Tout dépend de ce que ton application doit faire.
      0
    2. @trifouBonjour, effectivement j'ai entendu parler du root.after().
      Seulement je ne sais pas trop quoi en faire
      Pour éclaircir ma situation :
      J'ai une maquette de scanner 3d pilotée avec Arduino qui récupère des coordonnées X,Y,Z

      Côté Python j'ai une interface graphique qui via des boutons envoie des chiffres a l'arduino pour Démarrer Arrêter ou Calibrer la maquette.

      Seulement, j'aimerai maintenant récupérer ces coordonnées via python en les enregistrant via un fichier texte. Seulement vu qu'il y a beaucoup de points qui sont pris vites il faut que python lise en permanence ce qui arrive sur le port série tout en restant dans le loup pour ne pas faire geler l'interface graphique et je ne sais pas comment m'y prendre
      Merci
      0
    3. @ArmczbtBonjour,

      Il n'y a pas grand chose à faire, juste créer une fonction qui sera exécutée périodiquement et modifier tes 2 fonctions.

      after_id = None
      def write_data():
          global after_id
          var = arduinoData.read()
          log.insert('0.0', var)
          after_id = root.after(50, write_data)
       
      def Acqard():
          root.after_cancel(after_id)
          arduinoData.write(b'1')
       
      def stopacq():
          arduinoData.write(b'2')
          write_data()
      0
    4. @trifouBonjour, j'ai testé votre code et j'arrive a afficher les données cependant j'ai encore quelques problèmes sur lesquels je viens de passer 2h et que je n'arrive pas à résoudre
      - Quand on arrête l'acquisition et qu'il n'y a donc plus de données qui arrivent, la fenêtre tkinter crash
      -Les données arrivent a l'envers (les données sont retournées)
      - Et je n'arrive pas a sauvegarder toutes les données reçues sous un fichier texte

      Si vous avez des idées .... :)

          from tkinter import *
      import tkinter as tk
      import tkinter.messagebox
      import tkinter.filedialog
      from PIL import ImageTk, Image
      import serial

      #CRéation de la fenetre
      root = tk.Tk() #On initialise la fenetre
      root.title('Interface')#On nomme la fenetre

      fichier = open("Resultat.txt", "a")

      #Creation de l'arriere plan et de la taille de la fenetee
      image1 = ImageTk.PhotoImage(Image.open("Fichiers annexes\Fondd.png"))
      w = image1.width()
      h = image1.height()
      root.geometry('800x700')
      fond = tk.Label(root, image=image1)
      fond.pack()

      log = Text( root, width=25, height=20, takefocus=0, font = ('Tw Cen MT', 15))
      log.place(x=400, y=310, anchor='w')

      # make a scrollbar
      scrollbar = Scrollbar(root)
      scrollbar.pack(side=RIGHT, fill=Y)

      # attach text box to scrollbar
      log.config(yscrollcommand=scrollbar.set)
      scrollbar.config(command=log.yview)

      global flag

      arduinoData = serial.Serial('COM3',9600)

      def quitter():
          root.destroy()

      def write_data():
          var = arduinoData.read()
          log.insert('0.0', var)
          root.after(50, write_data)

      def write_fichier():
          fichier = open("data.txt", "w")
          var = arduinoData.read()
          fichier.write(var)

          root.after(50, write_data)

      def Acqard():
          arduinoData.write(b'1')

          write_data()

          global flag
          flag = 1
          log.insert(END, "Début du scan\n")

      def stopacq():
          global flag
          flag = 0
          arduinoData.write(b'3')

          log.insert(END, "Scan interrompu\n")

      def Calibrage():
          if flag == 1:
              log.insert(END, "Vous ne pouvez pas calibrer en pleine acquisition\n")
              return
          fichier.close()
          arduinoData.write(b'2')
          log.insert(END, "Calibrage\n")

      #Creation du bouton de validation
      Bouton = tk.Button(root, text ="Lancer l'acquisition",command = Acqard, font = ('Tw Cen MT', 15),  overrelief= 'ridge', bg= "#212D64", fg ="white")
      Bouton.place(x=150, y=130, anchor='w')

      #Creation du bouton de validation
      Bouton = tk.Button(root, text ="Calibrage",command = Calibrage, font = ('Tw Cen MT', 15),  overrelief= 'ridge', bg= "#212D64", fg ="white")
      Bouton.place(x=182, y=230, anchor='w')

      #Création du bouton d'arret de la focntion
      Bouton = tk.Button(root, text ="Arrêter le scan",command = stopacq, font = ('Tw Cen MT', 15),  overrelief= 'ridge', bg= "#212D64", fg ="white")
      Bouton.place(x=164, y=330, anchor='w')

      #Création du bouton de quitter
      Bouton = tk.Button(root, text ='Quitter',command = quitter, font = ('Tw Cen MT', 15), overrelief= 'ridge', bg= "#0C1B5E", fg ="white")
      Bouton.place(x=260, y=500, anchor='se' )

      root.mainloop()
      0
    5. @ArmczbtBonjour,

      Je ne sais pas où est appelé write_fichier, mais ça ne va pas, il faut grouper écriture dans tkinter et dans le fichier au même endroit, i.e où les données du moniteur sont lues.
      Si j'ai mit une variable after_id, ce n'est pas pour faire joli, c'est indispensable pour stopper les rappels périodiques. Ensuite, j'ai mit 50 millisecondes, c'est peut-être un peu trop rapide, tu pourrais déjà tester en mettant 500 millisecondes (donc une demie seconde), voire plus.

      Ca pourrait donner

      file_stream = None
      after_id = None # Ne pas enlever cette variable
      
      def write_data():
          global file_stream
          file_stream = open("data.txt", "w") # mode write ou append ?
          wrile_lines()
      
      
      def write_lines():
          global after_id
          data = arduinoData.read()
          log.insert('0.0', data)
          file_stream.write(data)
          after_id = root.after(500, write_lines)
      
      
      def Acqard():
          global flag
          flag = 1
          arduinoData.write(b'1')
          log.insert(END, "Début du scan\n")
          root.after(500, write_data)
      
      
      def stopacq():
          global flag, file_stream
          flag = 0
          root.after_cancel(after_id) # Annulation des rappels automatiques de write_lines
          file_stream.close()
          file_stream = None
          arduinoData.write(b'3')
          log.insert(END, "Scan interrompu\n")
      0
  2. Bonjour,

    Considère le mainloop comme une boucle infinie qui ne se terminera que lorsque la fenêtre sera fermée.

    En sachant cela tu devrais comprendre pourquoi ton while ne s'exécute pas lorsque ta fenêtre est active.
    0