[Débutants] Exemple de simplification de code (+ exemple poo)

Python est le langage de prédilection du Raspberry Pi

Modérateurs : Francois, Manfraid

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code

Message par Bud Spencer » ven. 16 août 2019 12:20

Le mode pwm n’est pas bloquant, ce qui sous-entend qu’il n’arrête pas le fonctionnement du programme, alors pourquoi ne pas enrichir encore l’objet Led pour s’offrir un mode blink asynchrone en toute simplicité ?

Pour ça il suffit de créer une nouvelle action (blinkasync) qui va passer les bons paramètres à l’action pwm, à savoir un duty cycle à 50% et un délai qui sera posé sous 1 pour convertir en frequence (F = 1/T). J’en ai profité déporté le pwm stop dans une action interne qui a pour rôle d’arrêter le pwm, d’attendre la fin d’un éventuel cycle en cours et remettre les variables _pwmfreq et _pwm a leur état par défaut (ce que j’avais oublié de faire dans le code précédent)
pwm#4.png
pwm#4.png (72.43 Kio) Vu 5244 fois
Modifié en dernier par Bud Spencer le ven. 16 août 2019 13:25, modifié 4 fois.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code

Message par Bud Spencer » ven. 16 août 2019 12:23

Le petit programme de test qui va avec.
pwm#5.png
pwm#5.png (12.36 Kio) Vu 5259 fois
On peut maintenant faire clignoter une led tout en laissant le programme continuer à faire le reste de son boulot. Une simple instruction led.off() ou led.on() suffit pour arrêter le blink et positionner la led dans l’etat demandé.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code

Message par Bud Spencer » ven. 16 août 2019 12:42

Un petit recap du fonctionnement de l’objet Led

Import : from led import Led
Création d’un objet : maled = (GPIO,n° de pin)
maled.on() : allume la led
maled.off() : éteint la led
maled.blink(nbblink,delais) : fait clignoter la led nblink fois à un rytme de delais
maled.pwm(pourcentage) : fait éclairer la led avec pourcentage de luninosité (asynchrone)
maled.blinkasync (delais) : fait clignoter la led à un rytme de delais (asynchrone)
maled.etat : retourne l’état de la led (booléen)
maled.etat = bool : positionne la led à l’etat bool (True ou False)

Le code du fichier led.py

Code : Tout sélectionner

#!/usr/bin/python
# coding: utf-8
from time import sleep
class Led (object):   
    def __init__(self,gpio,pin):        
        self._gpio = gpio
        self._pin = pin
        self._pwm = None
        self._pwmfreq = 300
        self._gpio.setup(self._pin, self._gpio.OUT, initial = self._gpio.LOW)     
            
    def on(self):
        if not self._pwm == None: self._pwmstop()
        self._gpio.output(self._pin,self._gpio.HIGH)

    def off(self):
       if not self._pwm == None: self._pwmstop()
       self._gpio.output(self._pin,self._gpio.LOW)

    def blink(self,count,delais):
        if not self._pwm == None: self._pwmstop()
        for x in range(count * 2):
            self._set_etat(not self._get_etat())
            sleep(delais / 2)

    def blinkasync(self,delais):
        self._pwmfreq = 1 / delais 
        self.pwm(50)

    def pwm(self,percent):
        if self._pwm == None:
            self._pwm = self._gpio.PWM(self._pin, self._pwmfreq)
            self._pwm.start(percent)
        else:
            self._pwm.ChangeFrequency(self._pwmfreq)
            self._pwm.ChangeDutyCycle(percent)
    
    def _pwmstop(self):
        self._pwm.stop()
        sleep(1/self._pwmfreq)
        self._pwmfreq = 300
        self._pwm = None
 
    def _set_etat(self,valeur):
        if not self._pwm == None: self._pwmstop()
        self._gpio.output(self._pin,self._gpio.HIGH if valeur == True else self._gpio.LOW)

    def _get_etat(self):
        return True if self._gpio.input(self._pin) == self._gpio.HIGH else False

    etat = property(_get_etat,_set_etat)
et un petit programme pour le tester

Code : Tout sélectionner

#!/usr/bin/python
# coding: utf-8
import RPi.GPIO as GPIO
from time import sleep
from led import Led

GPIO.setmode(GPIO.BOARD)
maled = Led(GPIO,11)

maled.on()
print("Led On, Etat = " + str(maled.etat ))
sleep(5)

maled.off()
print("Led Off, Etat = " + str(maled.etat ))
sleep(5)

print("Ledpwm")
for x in range (10,100,10):
    maled.pwm(x)
    print ("Led % = " + str(x) + "%")
    sleep(1)
sleep(5)

print("Led clignote 5 fois")
maled.blink(5,0.5)
sleep(5)

print("Led clignote, le programme continue")
maled.blinkasync(0.5)
sleep(5)

maled.on()
print("Led On, Etat = " + str(maled.etat ))
sleep(5)

print("Led etat : False")
maled.etat = False

GPIO.cleanup()
Et le résultat du test en console:
LedRes.png
LedRes.png (15.65 Kio) Vu 5240 fois
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code

Message par Bud Spencer » sam. 17 août 2019 11:11

Exemple d’Héritage
Très bien, j’ai un bel objet Led bien complet mais ce serait dommage d’en rester là. Pourquoi ne pas étendre ce concept à tout un ensemble de fonctions pour le GPIO du pi. Entrées, Sorties, sondes diverses ect … Si je regarde mon objet Led, il regroupe déjà toutes les fonctions d’une sortie et les seules actions que l’on peut définir comme étant propre à une led sont seulement on, off et les 2 actions de blink. Donc plutôt que de tout réécrire pour créer un objet Sortie, je vais séparer le code en 2 objets (Sortie et Led) et faire en sorte que l’objet Led soit automatiquement rattaché à un objet Sortie et qu’il utilise ses possibilités. C’est le principe d’héritage.

J’écris donc un nouvel objet Sortie et j’y place le code de Led qui concerne ce nouvel objet. Il ne reste qu’à dire à la class Led qu’elle hérite de Sortie (class Led (Sortie):) et dans ce qui fait office de constructeur (__init__) de Led, j’initialise un objet Sortie en lui passant les paramètres. Bien sûr, il ni a plus de raison que mon fichier s’appelle led.py, je le renomme donc pigpio.py
heritage.png
heritage.png (70.95 Kio) Vu 5213 fois
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code

Message par Bud Spencer » sam. 17 août 2019 11:32

Encapsulation :
Quand j’avais créé mon objet Led, j’avais défini une valeur fixe pour la fréquence du pwm (300Hz). Maintenant que j’ai transformé ca en Sortie, je dois pouvoir utiliser le pwm avec d’autres fréquences. Pour ça je vais créer une propriété (property) qui va me permettre de changer cette valeur. Une propriété est vue de l’extérieur comme une variable de l’objet. Pour faire la lisaion entre la propriété et la variable interne de l’objet, je vais passer par 2 fonctions distinctes. Une première pour pouvoir récupérer la valeur de la variable interne et une seconde pour pouvoir la modifier. Le nom de ces 2 fonctions est défini par convention ( _ , get ou set , nom de la variable interne) et porte les noms d’ accesseur (get qui permet d’accéder à la valeur) et de mutateur (set qui permet de la modifier). C’est le principe d’encapsulation. On accède depuis l’extérieur a des propriétés et tous les traitements et contrôles nécessaires sont fait à l’interieur de l’objet en fonction de ses propres contraintes et de facon totalement transparente pour le reste du programme
encapsulation.png
encapsulation.png (54.38 Kio) Vu 5213 fois
La réinitialisation de valeur par défaut de _pwmfreq dans l’action interne _pwmstop n’a plus lieu d’etre donc je la supprime.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code

Message par Bud Spencer » sam. 17 août 2019 11:42

Je peux toujours utiliser le pwm avec l’objet Led, mais cela sous entendrait qu’il faudrait déjà que j’initialise la fréquence a une valeur correcte. Pour eviter cela et simplifier l’usage de Led, je vais ajouter une action pwm a Led. Quand j’utiliserais un objet Led, ce sera donc son action pwm qui sera appelée et non plus celle de sortie. De la sorte, je vais pouvoir initialiser en toute transparence la bonne fréquence pour le pwm et ensuite faire appel à la fonction pwm de Sortie
encapsulation2.png
encapsulation2.png (27.1 Kio) Vu 5209 fois
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code

Message par Bud Spencer » sam. 17 août 2019 11:54

On a maintenant 2 objets pour le prix d’un :D

Sortie : from pigpio import Sortie
Création d’un objet Sortie : masortie = (GPIO,n° de pin)
masortie.etat = bool : position la sortie à bool (True ou False)
masortie.etat : retourne l’état de la sortie (boolean)
masortie.pwmfreq = Hz : initialise le pwm de la sortie a Hz
masortie.pwmfreq : retourne la valeur courante de la fréquence du pwm
masortie.pwm(pourcentage) : génère un signale pwm pourcentage sur la sortie (asynchrone)

Led : from pigpio import Led
Création d’un objet Led : maled = (GPIO,n° de pin)
maled.on() : allume la led
maled.off() : éteint la led
maled.blink(nb blink, delais) : fais clignoter la led nbblink fois à un rytme de delais
maled.blinkasync (delais) : fait clignoter la led à un rytme de delais (asynchrone)
maled.pwm(pourcentage) : fait éclairer la led avec pourcentage de luminosité (asynchrone)
et bien sur les propriétés etat et pwmfreq de Sortie
maled.etat = bool : position la sortie à bool (True ou False)
maled.etat : retourne l’état de la sortie (boolean)
maled.pwmfreq : retourne la valeur courante de la fréquence du pwm de Sortie
maled.pwmfreq = Hz : Ne sert a rien avec l'objet led vu qu'il impose sa propre fréquence

Le code du fichier pigpio :

Code : Tout sélectionner

#!/usr/bin/python
# coding: utf-8
from time import sleep

class Sortie (object):
    def __init__(self,gpio,pin):        
        self._gpio = gpio
        self._pin = pin
        self._pwm = None
        self._pwmfreq = 10
        self._gpio.setup(self._pin, self._gpio.OUT, initial = self._gpio.LOW) 

    def pwm(self,percent):
        if self._pwm == None:
            self._pwm = self._gpio.PWM(self._pin, self._pwmfreq)
            self._pwm.start(percent)
        else:
            self._pwm.ChangeFrequency(self._pwmfreq)
            self._pwm.ChangeDutyCycle(percent)
    
    def _pwmstop(self):
        self._pwm.stop()
        sleep(1/self._pwmfreq)
        self._pwm = None
 
    def _set_etat(self,valeur):
        if not self._pwm == None: self._pwmstop()
        self._gpio.output(self._pin,self._gpio.HIGH if valeur == True else self._gpio.LOW)

    def _get_etat(self):
        return True if self._gpio.input(self._pin) == self._gpio.HIGH else False

    def _set_pwmfreq(self, valeur):
        self._pwmfreq = valeur
   
    def _get_pwmfreq(self):
        return self._pwmfreq

    etat = property(_get_etat,_set_etat)
    pwmfreq = property(_get_pwmfreq,_set_pwmfreq)
        

class Led (Sortie):   
    def __init__(self,gpio,pin):        
        self._gpio = gpio
        self._pin = pin
        Sortie.__init__(self,gpio,pin)
               
    def on(self):
        self._set_etat(True)

    def off(self):
       self._set_etat(False)

    def blink(self,count,delais):
        for x in range(count * 2):
            self._set_etat(not self._get_etat())
            sleep(delais / 2)

    def blinkasync(self,delais):
        self._pwmfreq = 1 / delais 
        Sortie.pwm(self,50)

    def pwm(self,percent):
        self._set_pwmfreq(300)
        Sortie.pwm(self,percent)

Et pour tester, on peu utiliser exactement le meme code que celui qui a été utilisé pour l'objet led ou il suffit juste de modifier la ligne :

Code : Tout sélectionner

from led import Led
en

Code : Tout sélectionner

from pigpio import Led
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code (+ exemple poo)

Message par Bud Spencer » dim. 18 août 2019 12:56

Dans les épisodes précédents, on a utilisé des itérations pour écrire moins de code dans le programme. Un autre intérêt des itérations, c’est que l’on plus facilement utiliser des fichiers de configuration qui contienne des listes. Plutôt que de définir les pins et les seuils de chaque barre du bargraphe, je vais les mettre dans un fichier de config qui va contenir des objets JSON. Et je l’écris comme ça :
json.png
json.png (21.13 Kio) Vu 5183 fois
Il y une liste pour les leds cpu, une liste pour les leds ram et une variable Refresh que je vais utiliser pour le timing de la boucle.
Modifié en dernier par Bud Spencer le dim. 18 août 2019 13:13, modifié 1 fois.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code (+ exemple poo)

Message par Bud Spencer » dim. 18 août 2019 13:01

Pour m’éviter d’avoir à créer des listes que je passerais à la construction des bargraphes, j’enrichis mon objet Bargraph d’une nouvelle fonction (addBarre) qui va me permettre de lui passer des paramètres de barre pour qu’il créé lui-même les objets Barrette :
addBarre.png
addBarre.png (15.96 Kio) Vu 5185 fois
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: [Débutants] Exemple de simplification de code (+ exemple poo)

Message par Bud Spencer » dim. 18 août 2019 13:06

Il existe bien sûr en python comme dans pratiquement tous les langages, une librairie qui permet de charger la structure d’un fichier json (import json) pour pouvoir ‘désérializer’ le contenu du fichier de config. Je peux maintenant réécrire l’équivalent du programme original de façon beaucoup plus ‘synthétique’ en utilisant des itérations, des objets réutilisables et évolutifs et un fichier de configuration :
end.png
end.png (39.4 Kio) Vu 5166 fois
Code pigpio.py

Code : Tout sélectionner

#!/usr/bin/python
# coding: utf-8
from time import sleep

class Sortie (object):
    def __init__(self,gpio,pin):        
        self._gpio = gpio
        self._pin = pin
        self._pwm = None
        self._pwmfreq = 10
        self._gpio.setup(self._pin, self._gpio.OUT, initial = self._gpio.LOW) 

    def pwm(self,percent):
        if self._pwm == None:
            self._pwm = self._gpio.PWM(self._pin, self._pwmfreq)
            self._pwm.start(percent)
        else:
            self._pwm.ChangeFrequency(self._pwmfreq)
            self._pwm.ChangeDutyCycle(percent)
    
    def _pwmstop(self):
        self._pwm.stop()
        sleep(1/self._pwmfreq)
        self._pwm = None
 
    def _set_etat(self,valeur):
        if not self._pwm == None: self._pwmstop()
        self._gpio.output(self._pin,self._gpio.HIGH if valeur == True else self._gpio.LOW)

    def _get_etat(self):
        return True if self._gpio.input(self._pin) == self._gpio.HIGH else False

    def _set_pwmfreq(self, valeur):
        self._pwmfreq = valeur
   
    def _get_pwmfreq(self):
        return self._pwmfreq

    etat = property(_get_etat,_set_etat)
    pwmfreq = property(_get_pwmfreq,_set_pwmfreq)
        

class Led (Sortie):   
    def __init__(self,gpio,pin):        
        self._gpio = gpio
        self._pin = pin
        Sortie.__init__(self,gpio,pin)
               
    def on(self):
        self._set_etat(True)

    def off(self):
       self._set_etat(False)

    def blink(self,count,delais):
        for x in range(count * 2):
            self._set_etat(not self._get_etat())
            sleep(delais / 2)

    def blinkasync(self,delais):
        self._pwmfreq = 1 / delais 
        Sortie.pwm(self,50)

    def pwm(self,percent):
        self._set_pwmfreq(300)
        Sortie.pwm(self,percent)


code bargraph.py

Code : Tout sélectionner

#!/usr/bin/python
# coding: utf-8
class Barrette :
    def __init__(self,barre, seuil):
        self.barre = barre
        self.seuil = seuil

class Bargraph (Barrette):
    def __init__(self,barres):
        self._barres = barres  
    
    def write(self,valeur):
        for x in self._barres:
            x.barre.etat = valeur >= x.seuil
   
    def addBarre(self,barre,seuil):
        self._barres.append(Barrette(barre,seuil))
code config.json

Code : Tout sélectionner

{
  "Refresh": 1,
  "LedCpu": [
    {
      "pin": 11,
      "seuil": 20
    },
    {
      "pin": 13,
      "seuil": 40
    },
    {
      "pin": 15,
      "seuil": 60
    },
    {
      "pin": 12,
      "seuil": 80
    },
    {
      "pin": 16,
      "seuil": 100
    }
  ],
  "LedRam": [
    {
      "pin": 22,
      "seuil": 20
    },
    {
      "pin": 38,
      "seuil": 40
    },
    {
      "pin": 35,
      "seuil": 60
    },
    {
      "pin": 33,
      "seuil": 80
    },
    {
      "pin": 32,
      "seuil": 100
    }
  ]
}
code program.py

Code : Tout sélectionner

#!/usr/bin/python
# coding: utf-8
import RPi.GPIO as GPIO
import psutil
import json
from time import sleep
from bargraph import Bargraph
from pigpio import Led

GPIO.setmode(GPIO.BOARD)

bargraphCpu = Bargraph([])
bargraphRam = Bargraph([])

with open('./config.json', 'r') as f: 
    config = json.load(f)

for x in config["LedCpu"]: 
    bargraphCpu.addBarre(Led(GPIO,x["pin"]),x["seuil"])

for x in config["LedRam"]: 
    bargraphRam.addBarre(Led(GPIO,x["pin"]),x["seuil"])

try:   
    while (True):
        bargraphCpu.write(psutil.cpu_percent())
        bargraphRam.write(100 - psutil.virtual_memory().percent)
        sleep(config["Refresh"])


except KeyboardInterrupt:
    GPIO.cleanup()
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Répondre

Retourner vers « Python »