Logo Mon Club Elec

PyQt Lab’ : Port Série : en réception : Afficher dans un QwtDial, le widget d’affichage analogique « à aiguille », une valeur de conversion analogique numérique (0-1023) reçue sur le port série en provenance d’Arduino.

PyQt Lab’ : Port Série : en réception : Afficher dans un QwtDial, le widget d’affichage analogique « à aiguille », une valeur de conversion analogique numérique (0-1023) reçue sur le port série en provenance d’Arduino.

Par X. HINAULT – Juin 2013

PyQt Lab’ : Port Série : en réception : Afficher dans un QwtDial, le widget d’affichage analogique « à aiguille », une valeur de conversion analogique numérique (0-1023) reçue sur le port série en provenance d’Arduino.

Ce que l’on va faire ici

  • Dans ce code PyQt, interface permettant d’afficher dans un QwtDial, le widget d’affichage analogique « à aiguille », une valeur de conversion analogique numérique (0-1023) reçue sur le port série en provenance d’Arduino.

Pré-requis

  • python 2.7
  • pyqt4.x
  • modules :
    • python-serial
    • python-qwt5-qt4

Téléchargement :

  • Ces codes sont disponibles ici : ..

Le fichier d’interface *.py

  • Fichier obtenu automatiquement avec l’utilitaire pyuic4 à partir du fichier *.ui créé avec QtDesigner :
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file
#
# Created: Mon Jan  7 20:26:19 2013
#      by: PyQt4 UI code generator 4.9.1
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui
from PyQt4.Qwt5 import * # <=== ligne à ajouter

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName(_fromUtf8(« Form »))
        Form.resize(464, 271)
        self.qwtDial = QwtDial(Form)
        self.qwtDial.setGeometry(QtCore.QRect(180, 5, 266, 261))
        self.qwtDial.setReadOnly(True)
        self.qwtDial.setLineWidth(5)
        self.qwtDial.setFrameShadow(QwtDial.Sunken)
        self.qwtDial.setMode(QwtDial.RotateNeedle)
        self.qwtDial.setOrigin(90.0)
        self.qwtDial.setWrapping(False)
        self.qwtDial.setObjectName(_fromUtf8(« qwtDial »))
        self.labelDebit = QtGui.QLabel(Form)
        self.labelDebit.setGeometry(QtCore.QRect(10, 45, 111, 16))
        self.labelDebit.setObjectName(_fromUtf8(« labelDebit »))
        self.comboBoxPort = QtGui.QComboBox(Form)
        self.comboBoxPort.setGeometry(QtCore.QRect(5, 20, 151, 24))
        self.comboBoxPort.setEditable(True)
        self.comboBoxPort.setObjectName(_fromUtf8(« comboBoxPort »))
        self.comboBoxPort.addItem(_fromUtf8(«  »))
        self.comboBoxPort.addItem(_fromUtf8(«  »))
        self.comboBoxPort.addItem(_fromUtf8(«  »))
        self.comboBoxPort.addItem(_fromUtf8(«  »))
        self.labelReception = QtGui.QLabel(Form)
        self.labelReception.setGeometry(QtCore.QRect(5, 135, 191, 16))
        self.labelReception.setObjectName(_fromUtf8(« labelReception »))
        self.textEditReception = QtGui.QTextEdit(Form)
        self.textEditReception.setGeometry(QtCore.QRect(5, 155, 156, 111))
        self.textEditReception.setObjectName(_fromUtf8(« textEditReception »))
        self.pushButtonInitSerial = QtGui.QPushButton(Form)
        self.pushButtonInitSerial.setGeometry(QtCore.QRect(5, 95, 131, 31))
        self.pushButtonInitSerial.setObjectName(_fromUtf8(« pushButtonInitSerial »))
        self.comboBoxDebit = QtGui.QComboBox(Form)
        self.comboBoxDebit.setGeometry(QtCore.QRect(5, 60, 111, 24))
        self.comboBoxDebit.setObjectName(_fromUtf8(« comboBoxDebit »))
        self.comboBoxDebit.addItem(_fromUtf8(«  »))
        self.comboBoxDebit.addItem(_fromUtf8(«  »))
        self.comboBoxDebit.addItem(_fromUtf8(«  »))
        self.comboBoxDebit.addItem(_fromUtf8(«  »))
        self.comboBoxDebit.addItem(_fromUtf8(«  »))
        self.comboBoxDebit.addItem(_fromUtf8(«  »))
        self.comboBoxDebit.addItem(_fromUtf8(«  »))
        self.comboBoxDebit.addItem(_fromUtf8(«  »))
        self.labelPort = QtGui.QLabel(Form)
        self.labelPort.setGeometry(QtCore.QRect(10, 5, 101, 16))
        self.labelPort.setObjectName(_fromUtf8(« labelPort »))

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        Form.setWindowTitle(QtGui.QApplication.translate(« Form », « PyQt + PyQwt +PySerial : QwtDial affiche can brute (0-1023) », None, QtGui.QApplication.UnicodeUTF8))
        self.labelDebit.setText(QtGui.QApplication.translate(« Form », « Débit Série (bauds) : », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxPort.setItemText(0, QtGui.QApplication.translate(« Form », « /dev/ttyACM0 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxPort.setItemText(1, QtGui.QApplication.translate(« Form », « /dev/ttyACM1 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxPort.setItemText(2, QtGui.QApplication.translate(« Form », « /dev/ttyUSB0 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxPort.setItemText(3, QtGui.QApplication.translate(« Form », « /dev/ttyUSB1 », None, QtGui.QApplication.UnicodeUTF8))
        self.labelReception.setText(QtGui.QApplication.translate(« Form », « Réception sur le port série : « , None, QtGui.QApplication.UnicodeUTF8))
        self.pushButtonInitSerial.setText(QtGui.QApplication.translate(« Form », « Initialiser le port Série », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(0, QtGui.QApplication.translate(« Form », « 115200 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(1, QtGui.QApplication.translate(« Form », « 57600 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(2, QtGui.QApplication.translate(« Form », « 38400 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(3, QtGui.QApplication.translate(« Form », « 28800 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(4, QtGui.QApplication.translate(« Form », « 19200 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(5, QtGui.QApplication.translate(« Form », « 14400 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(6, QtGui.QApplication.translate(« Form », « 9600 », None, QtGui.QApplication.UnicodeUTF8))
        self.comboBoxDebit.setItemText(7, QtGui.QApplication.translate(« Form », « 4800 », None, QtGui.QApplication.UnicodeUTF8))
        self.labelPort.setText(QtGui.QApplication.translate(« Form », « Port Série : », None, QtGui.QApplication.UnicodeUTF8))

# from qwt_plot import QwtPlot # <=== ligne à supprimer ou inactiver avec #

if __name__ == « __main__ »:
    import sys
    app = QtGui.QApplication(sys.argv)
    Form = QtGui.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

 

Le fichier d’application *Main.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

# Par X. HINAULT – Tous droits réservés – GPLv3
# Jan 2013 – www.mon-club-elec.fr

# — importation des modules utiles —
from PyQt4.QtGui import *
from PyQt4.QtCore import * # inclut Qtimer..

import os,sys

import serial # communication serie
from PyQt4.Qwt5 import * # module Qwt

# — importation du fichier de description GUI —
from tuto_pyqt_pyqwt_pyserial_qwtdial_can_brutex1 import *

# classe principale contenant le code actif
class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4

        # Note : ici self représente la classe

        def __init__(self, parent=None):
                QWidget.__init__(self) # initialise le Qwidget principal
                self.setupUi(parent) # Obligatoire

                # —— code actif initial ——

                #Réalisez les connexions supplémentaires entre signaux et slots
                self.connect(self.pushButtonInitSerial, SIGNAL(« clicked() »), self.pushButtonInitSerialClicked)

                #initialisation Timer
                self.timer=QTimer() # déclare un timer Qt
                self.connect(self.timer, SIGNAL(« timeout() »), self.timerEvent) # connecte le signal timeOut de l’objet timer à l’appel de la fonction voulue

                #— déclaration utiles —
                self.serialPort=None # déclaration initiale

                #===== Initialisation QwtDial ========

                #– définition plage des valeurs du QwtDial
                # void  setRange (double vmin, double vmax, double vstep=0.0, int pagesize=1)
                self.qwtDial.setRange(0, 1023.0)  # modifie la plage de valeurs de l’afficheur

                #– paramétrage initial du QwtDial —
                self.qwtDial.setOrigin(90.0) # point de référence du tracé – 0°=3H, 90° = 6H, etc..
                #self.qwtDial.setScaleArc(90.0, 270.0) # angle début / angle fin du tracé par rapport à l’origine
                self.qwtDial.setScaleArc(45.0, 315.0) # angle début / angle fin du tracé par rapport à l’origine
                self.qwtDial.setScale(0.0,10.0,100.0) # valeur min/max/pas des graduations de l’échelle – ici pas de 10 avec 10 intermédiaires

                #– création de l’aiguille et association au QwtDial
                #QwtDialSimpleNeedle    (       Style   style, bool     hasKnob = true, const QColor &          mid = Qt::gray, const QColor &          base = Qt::darkGray )
                aiguille=QwtDialSimpleNeedle(QwtDialSimpleNeedle.Arrow,True,QColor(Qt.red),QColor(Qt.blue)) # défini un QwtDialSimpleNeedle = aiguille simple
                # .Arrow = style aiguille « flèche » | .Ray = style simple ligne
                self.qwtDial.setNeedle(aiguille) # associe l’aiguille au QwtDial

                #– paramétrage de l’aiguille
                aiguille.setWidth(6.0) # fixe la largeur de l’aiguille

        #— les fonctions appelées, utilisées par les signaux
        def pushButtonInitSerialClicked(self):
                print(« Bouton Init cliqué »)
                if self.serialPort: # si le port existe déjà
                        self.serialPort.close() # ferme le port si existe

                # — initialise paramètres initialisation
                if self.comboBoxPort.currentText()==«  » : # si le champ d’initialisation Port est vide = initialisation par défaut
                        strPortInit=« /dev/ttyACM0 » # port par défaut
                else :
                        strPortInit=str(self.comboBoxPort.currentText()) #sinon utilise paramètre champ texte pour le port

                strDebitInit=str(self.comboBoxDebit.currentText()) # paramètre champ texte pour debit

                #— initialisation série avec gestion erreur —                      
                try: # essaie d’exécuter les instructions
                        self.serialPort=serial.Serial(strPortInit, strDebitInit) # initialise port serie
                        self.serialPort.flushInput() # vide la file d’attente série
                        print(« Initialisation Port Série : «  + strPortInit + » @ «  + strDebitInit + » = OK « ) # affiche debug

                        #– change aspect bouton init
                        self.pushButtonInitSerial.setStyleSheet(QString.fromUtf8(« background-color: rgb(0, 255, 0); »)) # bouton en vert
                        self.pushButtonInitSerial.setText(« Connexion OK »)  # change titre bouton

                except: # si erreur initialisation
                        print(« Erreur initialisation Série »)           

                        #– change aspect bouton init
                        self.pushButtonInitSerial.setStyleSheet(QString.fromUtf8(« background-color: rgb(255, 127, 0); »)) # bouton en orange
                        self.pushButtonInitSerial.setText(QString.fromUtf8(« Non connecté »))  # change titre bouton

                self.timer.start(10) # lance le timer avec délai en ms – 10 pour réception rapide

        def timerEvent(self): # fonction appelée lors de la survenue d’un évènement Timer – nom fonction indiférrent
                #– variables de réception —
                self.chaineIn=«  »;
                self.char=«  »;

                # lecture des données reçues           
                if self.serialPort: # seulement si le port série existe
                        self.timer.stop() # stoppe le timer le temps de lire les caractères et éviter « réentrée »

                        while (self.serialPort.inWaiting()): # tant que au moins un caractère en réception
                                self.char=self.serialPort.read() # on lit le caractère
                                #self.chaineIn=self.chaineIn+self.char          # forme minimale…

                                if self.char==\n: # si saut de ligne, on sort du while
                                        print(« saut ligne reçu ») # debug
                                        break # sort du while
                                else: #tant que c’est pas le saut de ligne, on l’ajoute à la chaine
                                        self.chaineIn=self.chaineIn+self.char                                  

                        if len(self.chaineIn)>0: # … pour ne pas avoir d’affichage si «  »     
                                print(self.chaineIn) # affiche la chaîne
                                self.textEditReception.append(self.chaineIn[:-1]) # ajoute le texte au textEdit en enlevant le dernier caractère (CR)

                                self.chaineIn=self.chaineIn[:-1] # retire dernier caractère avant extraire valeur numérique (LF)

                                if self.chaineIn.isalnum(): # si la chaine est un chiffre
                                        print(« que des chiffres ») # debug
                                        self.valeur=float(self.chaineIn)

                                        self.qwtDial.setValue(self.valeur) # fixe la valeur du qwtDial à partir de la valeur reçue sur port série

                                # fin if isalnum

                        # fin if len>0

                        self.timer.start() # redémarre le timer

                # fin if Serial Port

        # fin def timerEvent

        #— fonctions actives
        # …

# fonction principale exécutant l’application Qt                       
def main(args):
        a=QApplication(args) # crée l’objet application
        f=QWidget() # crée le QWidget racine
        c=myApp(f) # appelle la classe contenant le code de l’application
        f.show() # affiche la fenêtre QWidget
        r=a.exec_() # lance l’exécution de l’application
        return r

# pour rendre le fichier *.py exécutable
if __name__==« __main__ »: # pour rendre le code exécutable
        main(sys.argv) # appelle la fonction main
 

Code Arduino d’exemple

// — constantes des broches —

const int RVar=0; //declaration constante de broche analogique

// — Déclaration des variables globales —
int mesureBrute=0;// Variable pour acquisition résultat brut de conversion analogique numérique

//**************** FONCTION SETUP = Code d’initialisation *****

void setup()   { // debut de la fonction setup()

Serial.begin(115200); // initialise connexion série à 115200 bauds
// IMPORTANT : régler le terminal côté PC avec la même valeur de transmission

} // fin de la fonction setup()

//***** FONCTION LOOP = Boucle sans fin *****

void loop(){ // debut de la fonction loop()

// acquisition conversion analogique-numerique (CAN) sur la voie analogique
mesureBrute=analogRead(RVar);

// affiche valeur numerique entière ou à virgule au format décimal
Serial.println(mesureBrute);

delay(500);

} // fin de la fonction loop() – le programme recommence au début de la fonction loop sans fin
 

Utilisation

  • Les 2 fichiers suivants sont à enregistrer dans un même répertoire, l’un en nom.py et l’autre en nomMain.py.
  • Puis lancer l’application depuis Geany ou équivalent, en exécutant le fichier nomMain.py
  • Initialiser la communication série
  • La valeur reçue sur le port série s’affiche de façon analogique.
Noter cet article

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Archive Mon Club Elec

Articles populaires

Newsletter

Inscrivez-vous maintenant et bénéficiez d'un soutien continu pour réaliser vos travaux électriques en toute sécurité.