Moniteur série Python-Arduino

Fermé
Armczbt - Modifié le 23 déc. 2019 à 20:44
 trifou - 8 janv. 2020 à 12:11
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

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
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
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
Armczbt > trifou
6 janv. 2020 à 11:47
Bonjour, 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
trifou > Armczbt
6 janv. 2020 à 15:03
Bonjour,

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
Armczbt > trifou
8 janv. 2020 à 10:10
Bonjour, 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
Bonjour,

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