Logo Mon Club Elec

PyQt Lab’ : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

PyQt Lab est un logiciel open source qui permet aux utilisateurs de créer des applications graphiques pour le contrôle et l’automatisation des systèmes embarqués. Dans ce tutoriel, nous allons voir comment utiliser PyQt Lab pour contrôler un Arduino à l’aide d’un port série et d’un bouton poussoir pour allumer et éteindre une LED. Nous verrons comment configurer le port série, comment envoyer des données à l’Arduino et comment créer un programme pour contrôler la LED.

PyQt Lab’ : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Par X. HINAULT – Juin 2013

PyQt Lab’ : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Ce que l’on va faire ici

  • Dans ce code PyQt, une interface qui permet d’allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Pré-requis

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

Téléchargement :

  • L’archive des codes est disponible 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: Wed Jan 16 12:06:34 2013
#      by: PyQt4 UI code generator 4.9.1
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

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(432, 255)
        self.comboBoxPort = QtGui.QComboBox(Form)
        self.comboBoxPort.setGeometry(QtCore.QRect(10, 20, 191, 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.labelPort = QtGui.QLabel(Form)
        self.labelPort.setGeometry(QtCore.QRect(10, 5, 101, 16))
        self.labelPort.setObjectName(_fromUtf8(« labelPort »))
        self.comboBoxDebit = QtGui.QComboBox(Form)
        self.comboBoxDebit.setGeometry(QtCore.QRect(10, 65, 106, 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.labelDebit = QtGui.QLabel(Form)
        self.labelDebit.setGeometry(QtCore.QRect(10, 50, 111, 16))
        self.labelDebit.setObjectName(_fromUtf8(« labelDebit »))
        self.pushButtonInitSerial = QtGui.QPushButton(Form)
        self.pushButtonInitSerial.setGeometry(QtCore.QRect(125, 55, 81, 41))
        self.pushButtonInitSerial.setObjectName(_fromUtf8(« pushButtonInitSerial »))
        self.textEditReception = QtGui.QTextEdit(Form)
        self.textEditReception.setGeometry(QtCore.QRect(10, 130, 186, 121))
        self.textEditReception.setObjectName(_fromUtf8(« textEditReception »))
        self.labelReception = QtGui.QLabel(Form)
        self.labelReception.setGeometry(QtCore.QRect(10, 110, 191, 16))
        self.labelReception.setObjectName(_fromUtf8(« labelReception »))
        self.line_2 = QtGui.QFrame(Form)
        self.line_2.setGeometry(QtCore.QRect(10, 95, 186, 16))
        self.line_2.setFrameShape(QtGui.QFrame.HLine)
        self.line_2.setFrameShadow(QtGui.QFrame.Sunken)
        self.line_2.setObjectName(_fromUtf8(« line_2 »))
        self.pushButtonLED = QtGui.QPushButton(Form)
        self.pushButtonLED.setGeometry(QtCore.QRect(235, 41, 176, 166))
        self.pushButtonLED.setCheckable(True)
        self.pushButtonLED.setObjectName(_fromUtf8(« pushButtonLED »))
        self.line = QtGui.QFrame(Form)
        self.line.setGeometry(QtCore.QRect(203, 5, 16, 246))
        self.line.setFrameShape(QtGui.QFrame.VLine)
        self.line.setFrameShadow(QtGui.QFrame.Sunken)
        self.line.setObjectName(_fromUtf8(« line »))

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

    def retranslateUi(self, Form):
        Form.setWindowTitle(QtGui.QApplication.translate(« Form », « PyQt + PySerial : Terminal Série : pushButton allume LED », 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.labelPort.setText(QtGui.QApplication.translate(« Form », « 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.labelDebit.setText(QtGui.QApplication.translate(« Form », « Débit Série (bauds) : », None, QtGui.QApplication.UnicodeUTF8))
        self.pushButtonInitSerial.setText(QtGui.QApplication.translate(« Form », « Initialiser », None, QtGui.QApplication.UnicodeUTF8))
        self.labelReception.setText(QtGui.QApplication.translate(« Form », « Réception sur le port série : « , None, QtGui.QApplication.UnicodeUTF8))
        self.pushButtonLED.setText(QtGui.QApplication.translate(« Form », « ALLUMER LED », None, QtGui.QApplication.UnicodeUTF8))

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 – Janv 2013 – Tous droits réservés
# GPLv3 – www.mon-club-elec.fr

# modules a importer
from PyQt4.QtGui import *
from PyQt4.QtCore import *  # inclut QTimer..
import os,sys

import serial # communication serie

from tuto_pyqt_pyserial_terminal_bp_allume_led import * # fichier obtenu à partir QtDesigner et pyuic4

class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4
        def __init__(self, parent=None):
                QWidget.__init__(self) # initialise le Qwidget principal
                self.setupUi(parent) # Obligatoire

                #Ici, personnalisez vos widgets si nécessaire

                #Réalisez les connexions supplémentaires entre signaux et slots
                # connecte le signal Clicked de l’objet bouton à l’appel de la fonction voulue
                self.connect(self.pushButtonInitSerial, SIGNAL(« clicked() »), self.pushButtonInitSerialClicked)
                self.connect(self.pushButtonLED, SIGNAL(« clicked() »), self.pushButtonLEDClicked)

                #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

        # les fonctions appelées, utilisées par les signaux
        def pushButtonLEDClicked(self): # lors appui bouton envoi série

                print(« Bouton LED appuyé »)

                # côté Arduino : H allume LED et L : éteint LED
                if self.serialPort: # seulement si le port série existe – n’existe pas (=None) tant que pas initialisé
                        if self.pushButtonLED.isChecked(): # si bouton appuyé
                                # self.serialPort.write(str(self.lineEditChaineEnvoi.text())+’\n’  ) # envoie la chaine sur le port serie              
                                self.serialPort.write(‘H’ ) # envoie la chaine sur le port serie + saut de ligne (pas obligatoire ici – cf prog Arduino)
                                print(« Envoi Série : «  + ‘H’ )
                        else: # si bouton pas appuyé
                                # self.serialPort.write(str(self.lineEditChaineEnvoi.text())+’\n’  ) # envoie la chaine sur le port serie              
                                self.serialPort.write(‘L’ ) # envoie la chaine sur le port serie + saut de ligne (pas obligatoire ici – cf prog Arduino)
                                print(« Envoi Série : «  + ‘L’ )

        def pushButtonInitSerialClicked(self): # lors appui bouton initialisation série
                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 »

                        if (self.serialPort.inWaiting()): # si au moins un caractère en réception
                                while self.char!=\n: # tant que dernier différent de saut de ligne
                                        self.char=self.serialPort.read() # on lit le caractère
                                        if self.char!=\n: # tant que c’est pas le saut de ligne, on l’ajoute à la chaine
                                                self.chaineIn=self.chaineIn+self.char
                                        else:
                                                #print(« saut ligne reçu ») # debug
                                                break

                        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

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

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

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

 

Code Arduino d’exemple

  • Ce programme fonctionne avec le code Arduino suivant :
// — Programme Arduino —
// Trame de code générée par le générateur de code Arduino
// du site www.mon-club-elec.fr

// Auteur du Programme : X. HINAULT – Tous droits réservés
// Programme écrit le : 29/1/2011.

// ——- Licence du code de ce programme —–
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License,
//  or any later version.
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

// ////////////////////  PRESENTATION DU PROGRAMME ////////////////////

// ——– Que fait ce programme ? ———
 /* Ce programme permet d’allumer une LED connectée sur une broche de la carte Arduino à partir d’un bouton inverseur graphique dans l’interface Processing côté PC.  */

// — Fonctionnalités utilisées —

// Utilise la connexion série vers le PC

// ——– Circuit à réaliser ———

// La connexion série vers le PC utilise les broches 0 et 1 (via le câble USB)

// Broche 2 : Une LED connectée en série avec sa résistance

// /////////////////////////////// 1. Entête déclarative ///////////////////////
// A ce niveau sont déclarées les librairies incluses, les constantes, les variables, les objets utiles…

// — Déclaration des constantes —

// — Inclusion des librairies —

// — Déclaration des constantes utiles —

// — Déclaration des constantes des broches E/S numériques —

const int LED=2; // Constante pour la broche 2

// — Déclaration des constantes des broches analogiques —

// — Déclaration des variables globales —

 int octetReception=0; // variable de stockage des valeurs reçues sur le port Série
 String chaineReception=«  »; // déclare un objet String vide pour reception chaine

// — Déclaration des objets utiles pour les fonctionnalités utilisées —

// ////////////////////////// 2. FONCTION SETUP = Code d’initialisation //////////////////////////
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme

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

// — ici instructions à exécuter 1 seule fois au démarrage du programme —

// ——- Initialisation fonctionnalités utilisées ——-  

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

// ——- Broches en sorties numériques ——-  
 pinMode (LED,OUTPUT); // Broche LED configurée en sortie

// ——- Broches en entrées numériques ——-  

// ——- Activation si besoin du rappel au + (pullup) des broches en entrées numériques ——-  

// ——- Initialisation des variables utilisées ——-  

} // fin de la fonction setup()
// ********************************************************************************

////////////////////////////////// 3. FONCTION LOOP = Boucle sans fin = coeur du programme //////////////////
// la fonction loop() s’exécute sans fin en boucle aussi longtemps que l’Arduino est sous tension

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

// — ici instructions à exécuter par le programme principal —

//—- code type réception valeur sur le port série —

if (Serial.available()>0) { // si un octet en réception

        octetReception=Serial.read(); // Lit le 1er octet reçu et le met dans la variable

        if (octetReception==‘H’) { // si Octet reçu est le H

            digitalWrite(LED, HIGH); // allume la LED

        }

        if (octetReception==‘L’) { // si octet reçu est le L

            digitalWrite(LED, LOW); // éteint la LED

        }

} // fin si octet réception

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

// ////////////////////////// FONCTIONS DE GESTION DES INTERRUPTIONS ////////////////////

// ////////////////////////// AUTRES FONCTIONS DU PROGRAMME ////////////////////

// ////////////////////////// Fin du programme ////////////////////
 

Matériel Nécessaire

L’espace de développement Arduino

  • … pour éditer, compiler le programme et programmer la carte Arduino.
PyQt Lab&rsquo; : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Le matériel suivant pour réaliser le montage associé

  • une plaque d’essai pour montage sans soudures,
PyQt Lab&rsquo; : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.
  • des straps,
PyQt Lab&rsquo; : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.
  • une LED rouge 5mm,
PyQt Lab&rsquo; : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.
  • une résistance 1/4w de 200 Ohms environ,
PyQt Lab&rsquo; : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Instructions de montage

  • La connexion série vers le PC utilise les broches 0 et 1 (via le câble USB)
  • Broche 2 : Une LED connectée en série avec sa résistance

Le schéma théorique du montage

PyQt Lab&rsquo; : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Le schéma théorique du montage (cliquer pour agrandir)

Le circuit du montage

PyQt Lab&rsquo; : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.

Le schéma du montage à réaliser (cliquer pour agrandir)

Fonctionnement du programme

Structure globale du programme

Ce programme simple comprend :

  • une entête déclarative
  • une partie « configuration » qui ne sera exécutée qu’une fois (fonction setup( ) )
  • une partie constituée d’une boucle sans fin que le programme répètera à l’infini ( fonction loop( ) ) : c’est le coeur du programme.

Déroulement du programme

Le programme se déroule de la façon suivante :

  • Après avoir pris en compte les instructions de la partie déclarative,
  • puis après avoir exécuté la partie configuration ( fonction setup( ) ),
  • le programme bouclera sans fin ( fonction loop ( ) ), exécutant de façon répétée le code compris dans la boucle sans fin.
PyQt Lab&rsquo; : Port Série : en envoi : Allumer une LED côté Arduino avec un PushButton en mode ON/OFF.
Le déroulement du programme

Explication du programme

Au niveau de la partie déclarative :

  • On déclare la broche de LED

Au niveau de la fonction d’initialisation setup( ) :

  • On met la broche en sortie

Au niveau de la boucle principale, la fonction loop ( ) :

  • On teste si un caractère est disponible sur le port série :
    • si ce caractères est ‘H’, on allume la LED
    • si ce caractère est ‘L’, on éteint la LED

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
  • L’appui sur le bouton poussoir allume/éteint la LED par l’envoi de la lettre H ou L sur le port série.
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é.