Page 1 of 1

[RESOLU] python : comment eviter les faux positifs sur add_event_detect

Posted: Thu Jun 27, 2019 9:16 am
by iznobe
Bonjour ,

voici un script qui n ' est surement pas parfait :?

sur le long therme j ' ai parfois de faux positifs de detection event , il ne s' agit pas de rebond car le flotteur ne bouge pas dans les tests, une solution pour eviter ce phenomene ?

Code: Select all

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

import RPi.GPIO as GPIO
import time
from datetime import datetime

GPIO.setmode(GPIO.BOARD)

pin_flotteur=36
GPIO.setup(pin_flotteur, GPIO.IN, pull_up_down=GPIO.PUD_UP) # en mode entree Tout Ou Rien

# Fonctions
def sendmail (): # fonction qui envoie les mails
    import smtplib
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
########################################################################

time.sleep(0.5) # pause de demarrage
GPIO.add_event_detect(pin_flotteur, GPIO.BOTH, bouncetime=1000) # GPIO.FALLING GPIO.BOTH GPIO.RISING  , callback=my_callback

while True :# a utiliser a la place de la fonction callback pour le moment
    state = GPIO.input(pin_flotteur) # lecture etat de l ' entree
    
    if not state : # l ' eau fait monter le flotteur et coupe le contacteur relais
        #GPIO.remove_event_detect(pin_flotteur)
        print("il ya une fuite d' eau")
        #sendmail()
        now=(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        fichier = open("/home/pi/projets_auto/logs/envoi_mail_auto.log", "a")
        fichier.write("le flotteur est passe en position haute a : "+ now+"\n")
        fichier.close()
        while not state : # tant qu on est en etat bas donc flotteur en position haute, on attend qu il redescende.
            state = GPIO.input(pin_flotteur) # lecture etat de l ' entree
            time.sleep(1)
    time.sleep(1) # eviter surcharge proc
# a utiliser a la place de la fonction callback pour le moment
voici le log associé :

Code: Select all

le flotteur est passe en position haute a : 27/06/2019 11:14:42
le flotteur est passe en position haute a : 27/06/2019 11:16:37
le flotteur est passe en position haute a : 27/06/2019 11:17:31
le flotteur est passe en position haute a : 27/06/2019 11:19:11
le flotteur est passe en position haute a : 27/06/2019 11:20:27
le flotteur est passe en position haute a : 27/06/2019 11:20:46

le montage est le suivant :
3.3v => contacteur => resistance 1 kohms => pin 36 ( physique )
la resistance est-elle trop elevee ? le montage n ' est pas bon ?
quel peut etre le probleme selon vous ?

Re: python : comment eviter les faux positifs sur add_event_detect

Posted: Thu Jun 27, 2019 4:39 pm
by ernesto
A ce que je vois cela ne devrait pas fonctionner du tout, en effet:
Le gpio 36 est relié à une résistance de pull up et le montage applique 3.3V sur le gpio 36 lorsque le contacteur se ferme. Dans ces conditions le gpio ne peut rien détecter.
GPIO.setup(pin_flotteur, GPIO.IN, pull_up_down=GPIO.PUD_UP) # en mode entree Tout Ou Rien
3.3v => contacteur => resistance 1 kohms => pin 36 ( physique )
Pour que cela puisse fonctionner il y a deux solutions
1) pull up et 0v sur le contacteur
GPIO.setup(pin_flotteur, GPIO.IN, pull_up_down=GPIO.PUD_UP) # en mode entree Tout Ou Rien
0v => contacteur => resistance 1 kohms => pin 36 ( physique )
2) pull down et 3.3 v sur le contacteur
GPIO.setup(pin_flotteur, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # en mode entree Tout Ou Rien
3.3v => contacteur => resistance 1 kohms => pin 36 ( physique )
Préférer le câblage 1 car en électronique on n'aime pas bien que l'alimentation se promène trop loin dans des câbles.

Nota: avec les infos que vous donnez il ne devrait pas y avoir de détection si c'est le cas cela peut être dû à des parasites, la longueur des câbles ...

Re: python : comment eviter les faux positifs sur add_event_detect

Posted: Fri Jun 28, 2019 9:30 am
by tqhien
Bonjour,

Alors j'ai un peu répondu sur ton autre post, mais je remets ma réponse ici.

Théoriquement un interrupteur, c'est ouvert ou fermé. Dans la réalité, entre le passage de l'un à l'autre, il y a une foule de micro coupures (de rebond). Selon l'interrupteur, ces rebonds durent plus ou moins longtemps. Il faut donc procéder à une élimination de ces artefacts, c'est ce qu'on appelle le debouncing. Elle s'effectue en deux étapes : dans la déclaration du add_event_detect, le paramètre bouncetime définit qu'il faut ignorer deux appels rapprochés. Et dans ton callback, tu vérifies au bout d'un certain temps qu'on a bien changé d'état.

La trame du traitement est alors la suivante :

Code: Select all

import RPi.GPIO as GPIO

mon_gpio = 17 #quel pin à surveiller

def my_callback(channel):
    GPIO.remove_event_detect(channel) #on neutralise les interruptions sur ce gpio pendant le traitement
    print('Bouton appuye')
    b4_time = time.time() # a quel moment a -t-on appuye
    t = time.time() - b4_time
    time.sleep(.1) # on va attendre pour confirmer ou non l'appui
    while not GPIO.input(channel) :# on attend le retour du bouton : soit on est pas rentrée dans la boucle=artefact, soit on y est, on attend le relaché
         t = time.time() - b4_time
         time.sleep(.1) # on scrute toutes les .1s
     if t >= .1:
          faire_quelque_chose()
    GPIO.add_event_detect(channel,GPIO.FALLING,callback=input_left_callback,bouncetime=50) # onréactive la détection
    
    
GPIO.add_event_detect(mon_gpio,GPIO.FALLING,callback=input_left_callback,bouncetime=50) #on déclare le callback pour l'interruption associée à mon gpio

while (True) : # boucle principale. ya pas grand chose à faire vu qu'on utilise les interruptions
    pass
Hien.

Re: python : comment eviter les faux positifs sur add_event_detect

Posted: Mon Jul 01, 2019 8:25 am
by iznobe
Bonjour et merci a vous deux pour votre participation ;)

Alors effectivement , j ' avais pas compris cet histoire de pull_up ( pourtant pas faute d' en avoir lu sur le sujet ) mais votre explication , m ' a enfin permis de comprendre ce qui se passait au niveau du micro controlleur : le pull_up UP , simule en fait un etat logique haut sur le pin concerné , et donc lorsqu ' on passe physiquement en etat bas ( a nous de brancher correctement ) le programme execute le code dans la fonction de call_back.

Ensuite j ' ai compris , comment faire ce fameux double debounce qui permet d' eviter les faux positifs , et j' ai donc readapter mon code en fonction .

Mais je pense que je fais encore des choses pas comme il faut , ou bien le pi a subi des avaries par ma faute , mais ca ne fonctionne pas comme ca le devrait , bien que ca se rapproche du fonctionnement attendu , le processus prend un coeur du proc a 100 % :mrgreen:

voici mon code modifié :

Code: Select all

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

import RPi.GPIO as GPIO
import time
from datetime import datetime

GPIO.setmode(GPIO.BOARD) # board = emplacements physiques , BCM emplacements logiques du proc

# les pins 15 , 8 , 36 sont inutilisables ...
global pin_flotteur
pin_flotteur=15
#TEST#
pin_test=36
GPIO.setup(pin_test,GPIO.OUT)
#TEST#
GPIO.setup(pin_flotteur, GPIO.IN, pull_up_down=GPIO.PUD_UP) # en mode entree Tout Ou Rien
#GPIO.setup(GPIO_LEFT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# On se met en pullup, l'état du GPIO est donc à 1 par défaut, on détectera un appui lorsqu'il passe à zero (et donc FALLING)
def my_callback(pin_flotteur): # fonction de detection etat du pin en entree
    GPIO.remove_event_detect(pin_flotteur) # on évite un autre appel pendant qu'on traite celui déjà présent
    #global state
    
    time.sleep(5) # ici on faut un debounce : on attend 0.1s pour confirmer ou non l'appui
    state = GPIO.input(pin_flotteur) # lecture etat de l ' entree
    print(state)
    
    if not state :
        print("le flotteur est en position haute")
        #sendmail()
        now=(datetime.now().strftime("%d/%m/%Y %H:%M:%S"))
        fichier = open("/home/pi/projets_auto/logs/envoi_mail_auto.log", "a")
        fichier.write("le flotteur est passe en position haute a : "+ now+"\n")
        fichier.close()
    else : # le flotteur est repasse en position basse , donc le contacteur ( laisse passer le courant) remet le pin a 1
        GPIO.add_event_detect(pin_flotteur, GPIO.BOTH, callback=my_callback, bouncetime=1000) # on remet la détection maintenant que le traitement a été fait
        
    while not state :# on attend le retour du contacteur.
                     # soit on ne rentre pas dans la boucle: c'était un artefact, 
                     # soit on y rentre et on va tester la durée
        state = GPIO.input(pin_flotteur) # lecture etat de l ' entree
        time.sleep(2)

    else : # le flotteur est repasse en position basse , donc le contacteur ( laisse passer le courant) remet le pin a 1
        GPIO.add_event_detect(pin_flotteur, GPIO.BOTH, callback=my_callback, bouncetime=1000) # on remet la détection maintenant que le traitement a été fait
########################################################################

GPIO.add_event_detect(pin_flotteur, GPIO.BOTH, callback=my_callback, bouncetime=1000) # GPIO.FALLING GPIO.BOTH GPIO.RISING

while (True) :
    pass # ou affichage d'infos, etc
    
GPIO.cleanup()
avec ce code , on arrive a faire des actions une seule fois , grace a : " if state : "
avec le while on verifie le nouveau changement d ' etat , et dans le else on repart du debut comme si de rien n ' etait :D

Ca a l ' air de fonctionner maintenant :D ,

Par contre sur mon pi 3 , le processeur a un coeur a 100 % , est normal ? la meme chose chez vous pour votre fonction callback ? ca me parait beaucoup.

Je vous remercie tous les 2 pour votre aide et vous tiens au courant :lol:

Re: python : comment eviter les faux positifs sur add_event_detect

Posted: Mon Jul 01, 2019 1:14 pm
by tqhien
Salut,

Pour le processeur à 100%, c'est à cause du "pass" dans la boucle principale. Le programme ne fait rien, mais il le fait à fond ;) Normalement, je fais un time.sleep(.2) ou tout autre valeur à la place du pass pour réduire la charge processeur entre 2 affichages de mes infos.

Hien.

Re: python : comment eviter les faux positifs sur add_event_detect

Posted: Mon Jul 01, 2019 2:05 pm
by iznobe
Salut
Merci pour cette precision !

effectivement apres avoir planté un sleep a la place ca va beaucoup mieux :D

je ne savais pas que ne rien faire etait autant fatiguant et bouffeur de ressources pour un processeur :lol:

merci beaucoup pour votre aide en tout cas , il ne me reste plus qu ' un detail a regler : le lancement du script au demarrage .

j ' ai edité mon fichier /etc/rc.local dans raspbian et ajouter une ligne de facon a ce qu ' il devienne :

Code: Select all

# lancement script personnalise envoi mail auto en python
python "/home/pi/projets_auto/python/testeur.py" &

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

exit 0
mais apres reboot dans un terminal si je passe la commande top , je ne vois pas de process avec le nom python, je suppose donc que ca ne fonctionne pas , pourtant la ligne : python "/home/pi/projets_auto/python/testeur.py" & passe dans un terminal et lance le tout normalement .

une idee svp ?

EDIT : finalement apres un deuxieme reboot , tout est ok et fonctionne :P

un grand MERCI pour votre aide a tous !!!