jeek
Posts: 32
Joined: Sun Jul 22, 2012 6:43 am

GPIO-Message d'erreur

Wed Nov 21, 2012 6:41 am

Salut à tous, j'ai un problème lorsque j'essaye de refaire le tutorial suivant :
http://mchobby.be/wiki/index.php?title= ... k-PiAnalog

La première fois que j'exécute le programme, cela fonctionne parfaitement, mais si j'arrête le programme en tapant CTRL + c et que je le relance, j'obtiens les messages d'erreur suivants :

Code: Select all

./test.py:69: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(SPIMOSI, GPIO.OUT)
./test.py:71: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(SPICLK, GPIO.OUT)
./test.py:72: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  GPIO.setup(SPICS, GPIO.OUT)
Cela n'empèche pas le programme de fonctionner, mais j'aimerais quand même régler le problème.

L'une des solutions est d'ajouter

Code: Select all

GPIO.setwarnings(False)
Ca suprime bien les messages d'erreurs mais ça ne règle pas le problème

J'ai aussi essayé d'ajouter à la fin

Code: Select all

GPIO.cleanup()
mais ça ne fonctionne pas (je pense que c'est parce que je quitte le programme avec CTRL + c et que cette commande ne peut pas s'exécuter juste avant de sortir du programme)

Si l'un d'entre vous a rencontré ce problème et a trouvé la solution, ça serait sympa de nous le dire...

User avatar
Gabriel
Posts: 73
Joined: Wed Aug 10, 2011 5:43 pm
Location: France

Re: GPIO-Message d'erreur

Wed Nov 21, 2012 12:39 pm

Bonjour,
En effet il faut "dé-exporter" les pins une fois qu'elles ne sont plus utilisées, sinon quand le programme démarre il essaye d'exporter des pins qui le sont déjà.
Je pense que la commande GPIO.cleanup() devrait résoudre le problème mais il faut en effet que le programme ne soit pas arrêté avant qu'elle soit lue.
La solution pourrait être de
- Améliorer le programme pour que les instructions se trouvant après la boucle principale soient lues donc remplacer

Code: Select all

while True:
De la boucle principale par une condition que l'utilisateur va valider. (par exemple si trim_pot=1024. Mais je ne peux pas trop t'aider car je ne connais pas du tout le python)

ou

-Placer

Code: Select all

GPIO.cleanup()
au début du programme : cela veut dire que la première fois que le programme est lancé il ne nettoie rien (et va peut être donner un message d'erreur mais ce n'est pas gênant) et les fois suivantes il nettoie l'utilisation précédente.
Donc il faut placer GPIO.cleanup() avant les utilisations des GPIO (à partir de la ligne 69 d'après le message d'erreur) mais après

Code: Select all

import RPi.GPIO as GPIO
car il y a besoin de la bibliothèque GPIO.
Cette deuxième méthode est moins "propre" que la première mais elle est parfois plus simple à mettre en oeuvre.
My home-made case : http://goo.gl/nprcI ; My presentation http://goo.gl/5hSar et en français : http://goo.gl/28Vif ; Please think to the FAQ and to the Wiki

jeek
Posts: 32
Joined: Sun Jul 22, 2012 6:43 am

Re: GPIO-Message d'erreur

Wed Nov 21, 2012 3:25 pm

Merci de ton aide.
J'ai essayé de mettre

Code: Select all

GPIO.cleanup()
à plusieurs endroits avant la ligne 69 qui provoque l'erreur, mais ça ne change rien, et donc je ne suis pas sur que cette commande fonctionne ou qu'il n'y a pas une erreur de syntaxe.

mebepi
Posts: 84
Joined: Thu Aug 02, 2012 10:32 pm

Re: GPIO-Message d'erreur

Wed Nov 21, 2012 3:34 pm

Bonjour,

Il faut prévoir une manière propre de sortir de votre programme pour que celui-ci ferme correctement et libère les ressources qu'il a utilisé.
Un CTRL-C me parait un peu brutal pour terminer un programme.

User avatar
fdion
Posts: 307
Joined: Sun Sep 16, 2012 2:33 pm
Location: North Carolina, USA
Contact: Website

Re: GPIO-Message d'erreur

Wed Nov 21, 2012 4:45 pm

Il faut intercepter le CTRL-C par l'entremise de l'exception KeyboardInterrupt:

Code: Select all

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        gpio.cleanup()
La fonction main() contiendra notre boucle principale. Elle sera appelée si on exécute le script (c'est cette condition if __name__ ...), mais pas si on importe simplement ce script comme un module. Le mot clé try: indique en gros, essaie d’exécuter ... et le mot clé except, lui, intercepte l'exception ...

Le résultat de l'interception de l'exception c'est que peut importe ou on est dans le code (milieu d'une boucle while par exemple), un CTRL-C lève une exception KeyboardInterrupt, elle sera interceptée par le except, et gpio.cleanup() sera alors appelé. On peut aussi utiliser le else: et finally: avec les blocs try:

Pour un exemple fonctionnel complet, voir quiz4.py sur cette page:
http://raspberry-python.blogspot.com/20 ... op-01.html

J'explique le pourquoi de chaque partie du code a travers cet article. Il est en anglais, mais il y a un menu google translate a droite (la traduction automatique est quelque peu incompréhensible toutefois. C’était la première partie du PyHack Workshop #01, la deuxième, c'est l'article sur la PiQuizMachine (http://raspberry-python.blogspot.com/20 ... chine.html) qui était en première page de ce site la semaine dernière.

François
Francois
http://raspberry-python.blogspot.com - http://www.3dFutureTech.info - @f_dion

User avatar
fdion
Posts: 307
Joined: Sun Sep 16, 2012 2:33 pm
Location: North Carolina, USA
Contact: Website

Re: GPIO-Message d'erreur

Wed Nov 21, 2012 5:03 pm

J'ai ajouté un point d'ancrage directement a la section ou quiz4.py est situé:

http://raspberry-python.blogspot.com/20 ... html#quiz4
Francois
http://raspberry-python.blogspot.com - http://www.3dFutureTech.info - @f_dion

jeek
Posts: 32
Joined: Sun Jul 22, 2012 6:43 am

Re: GPIO-Message d'erreur

Wed Nov 21, 2012 5:49 pm

J'ai modifié le code en insérant la fonction main() comme ceci :

Code: Select all

#!/usr/bin/env python
# -*- coding: latin-1 -*-

import time
import RPi.GPIO as GPIO

def main():
   """ our main program """
GPIO.setmode( GPIO.BCM )
DEBUG = 1

# Lit les données SPI d'une puce MCP3008, 8 canaux disponibles (adcnum de 0 à 7)
def readadc( adcnum, clockpin, mosipin, misopin, cspin ):
        if( (adcnum > 7) or (adcnum < 0)):
                return -1

        GPIO.output( cspin, True )

        GPIO.output( clockpin, False ) # met Clock à Low
        GPIO.output( cspin, False )    # met CS à Low (active le module MCP3008)

        commandout = adcnum # numéro de channel
        commandout |= 0x18  # OR pour ajouter Start bit + signle-ended bit
                            # 0x18 = 24d = 00011000b
        commandout <<=3     # décalage de 3 bits à gauche

        # Envoi des Bits sur le bus SPI
        for i in range(5):
                # faire un AND pour determiner l'état du bit de poids le plus 
                # fort (0x80 = 128d = 10000000b)
                if( commandout & 0x80 ): # faire un AND pour déterminer l'état du bit
                        GPIO.output( mosipin, True )
                else:
                        GPIO.output( mosipin, False )
                commandout <<= 1 # décalage de 1 bit sur la gauche

                # Envoi du bit mosipin avec signal d'horloge
                GPIO.output( clockpin, True )
                GPIO.output( clockpin, False )

        # lecture des bits renvoyés par le MCP3008
        # Lecture de 1  bit vide, 10 bits de données et un bit null
        adcout = 0
        for i in range(12):
                # Signal d'horloge pour que le MCP3008 place un bit
                GPIO.output( clockpin, True )
                GPIO.output( clockpin, False )
                # décalage de 1 bit vers la gauche
                adcout <<= 1
                # stockage du bit en fonction de la broche miso
                if( GPIO.input(misopin)):
                        adcout |= 0x1 # active le bit avec une opération OR

        # Mettre Chip Select à High (désactive le MCP3008)
        GPIO.output( cspin, True )

        # Le tout premier bit (celui de poids le plus faible, le dernier lut)
        # est null. Donc on l'elimine ce dernier bit en décalant vers la droite
        adcout >>= 1

        return adcout

# Broches connectées sur l'interface SPI du MCP3008 depuis le Cobbler
# (changer selon vos besoins)
SPICLK = 18
SPIMISO = 23
SPIMOSI = 24
SPICS = 25



# Initialisation de l'interface SPI
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPICS, GPIO.OUT)

# Potentiomètre 10KOhms raccordés sur le canal ADC #0
potentiometer_adc = 0

while True:
        # Lecture analogique, retourne une valeur entre 0 et 1023 
        # pour une valeur de tension entre 0 et VRef (3.3v)
        trim_pot = readadc( potentiometer_adc, SPICLK, SPIMOSI, SPIMISO, SPICS )

        print( "Valeur: " + str( trim_pot ) )

        # convertir en tension
        print( "tension: "+ str( (3.3*trim_pot)/1024 ) )

        # attendre une demi-seconde
        time.sleep(0.5)


 if __name__ == "__main__":  
    try:  
      main()  
    except KeyboardInterrupt:  
      gpio.cleanup()  
Mais le programme se bloque et j'ai le message d'erreur suivant :

Code: Select all

  File "./test4-0.py", line 95
    if __name__ == "__main__":
                               ^
IndentationError: unindent does not match any outer indentation level

User avatar
fdion
Posts: 307
Joined: Sun Sep 16, 2012 2:33 pm
Location: North Carolina, USA
Contact: Website

Re: GPIO-Message d'erreur

Wed Nov 21, 2012 6:30 pm

Je vois que le site que tu indique, c'est une traduction de cet article de Adafruit:
http://learn.adafruit.com/reading-a-ana ... i/overview

Ce sont des programmeurs C, et on le "feel" a travers le code et le formatage... (je fait du C aussi depuis très longtemps).

Bon, pour ta question, si tu défini:

Code: Select all

def main():
La ligne qui suit devra être décalée. C'est de cette façon que Python définit le scope d'une fonction, d'une boucle etc. C'est fondamental au code Python.

Ici, on a 2 options. J'y vais par le plus court chemin, on déplace le def main(): juste avant la boucle while. Il faut donc décaler le while et tout ce qui est dans cette boucle.

Python veut un nombre défini d'espaces pour l'alignement. Dans leurs cas ils ont utilisé 8 espaces. C'est beaucoup. Je recommande et utilise plutôt 4. Et pas de tabulation. Tout éditeur qui se respecte a cette fonction (geany, gedit, scribes, vim, emacs, spe etc).

Il y a un guide de style que je met ici comme reference:
http://lapagearegis.free.fr/guidedestyle.html

Mais, bon, j'ai utilisé les 8 espaces pour corriger le script que tu as mis ici. J'ai aussi enlevé des espaces ou normalement il n'y en a pas. C'est plus facile a lire ainsi. Donc voila le code:

Code: Select all

#!/usr/bin/env python
# -*- coding: latin-1 -*-

import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
DEBUG = 1


# Lit les données SPI d'une puce MCP3008, 8 canaux disponibles (adcnum de 0 à 7)
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
        if((adcnum > 7) or (adcnum < 0)):
                return -1

        GPIO.output(cspin, True)

        GPIO.output(clockpin, False)  # met Clock à Low
        GPIO.output(cspin, False)     # met CS à Low (active le module MCP3008)

        commandout = adcnum  # numéro de channel
        commandout |= 0x18   # OR pour ajouter Start bit + signle-ended bit
                             # 0x18 = 24d = 00011000b
        commandout <<= 3      # décalage de 3 bits à gauche

        # Envoi des Bits sur le bus SPI
        for i in range(5):
                # faire un AND pour determiner l'état du bit de poids le plus
                # fort (0x80 = 128d = 10000000b)
                if(commandout & 0x80):  # faire un AND pour déterminer l'état du bit
                        GPIO.output(mosipin, True)
                else:
                        GPIO.output(mosipin, False)
                commandout <<= 1  # décalage de 1 bit sur la gauche

                # Envoi du bit mosipin avec signal d'horloge
                GPIO.output(clockpin, True)
                GPIO.output(clockpin, False)

        # lecture des bits renvoyés par le MCP3008
        # Lecture de 1  bit vide, 10 bits de données et un bit null
        adcout = 0
        for i in range(12):
                # Signal d'horloge pour que le MCP3008 place un bit
                GPIO.output(clockpin, True)
                GPIO.output(clockpin, False)
                # décalage de 1 bit vers la gauche
                adcout <<= 1
                # stockage du bit en fonction de la broche miso
                if(GPIO.input(misopin)):
                        adcout |= 0x1  # active le bit avec une opération OR

        # Mettre Chip Select à High (désactive le MCP3008)
        GPIO.output(cspin, True)

        # Le tout premier bit (celui de poids le plus faible, le dernier lut)
        # est null. Donc on l'elimine ce dernier bit en décalant vers la droite
        adcout >>= 1

        return adcout

# Broches connectées sur l'interface SPI du MCP3008 depuis le Cobbler
# (changer selon vos besoins)
SPICLK = 18
SPIMISO = 23
SPIMOSI = 24
SPICS = 25

# Initialisation de l'interface SPI
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPICS, GPIO.OUT)

# Potentiomètre 10KOhms raccordés sur le canal ADC #0
potentiometer_adc = 0


def main():
        while True:
                # Lecture analogique, retourne une valeur entre 0 et 1023
                # pour une valeur de tension entre 0 et VRef (3.3v)
                trim_pot = readadc(potentiometer_adc, SPICLK, SPIMOSI, SPIMISO, SPICS)

                print("Valeur: " + str(trim_pot))

                # convertir en tension
                print("tension: " + str((3.3 * trim_pot) / 1024))

                # attendre une demi-seconde
                time.sleep(0.5)


if __name__ == "__main__":
        try:
                main()
        except KeyboardInterrupt:
                gpio.cleanup()


Aussi, c'est mieux d'utiliser:
# -*- coding: utf-8 -*-
Plutot que:
# -*- coding: latin-1 -*-

Tout va vers l'unicode.


Finalement, tu peux aussi utiliser try directement sur une partie du code, plutôt que sur une fonction main. Par exemple, ici j'utilise un try: dans un script tout simple sans main():
http://raspberry-python.blogspot.com/20 ... tml#codigo

François
Francois
http://raspberry-python.blogspot.com - http://www.3dFutureTech.info - @f_dion

jeek
Posts: 32
Joined: Sun Jul 22, 2012 6:43 am

Re: GPIO-Message d'erreur

Thu Nov 22, 2012 6:08 am

Merci de votre aide les amis,
J'ai essayé ton script, François mais lorsque je quitte avec CTRL + c j'ai le message d'erreur suivant :

Code: Select all

^CTraceback (most recent call last):
  File "./test4-0.py", line 98, in <module>
    gpio.cleanup()
NameError: name 'gpio' is not defined
Et évidement, comme gpio.cleanup() ne fonctionne pas, au lancement suivant j'ai les mêmes erreurs que d'habitude.
Je me demande si ce n'est pas dans ma configuration qu'il manque quelque chose comme une bibliothèque, ce qui fait que la commande gpio.cleanup() n'est pas reconnue.

J'utilise une version de Rasbian à jour et j'ai suivi ce tutorial :
http://mchobby.be/wiki/index.php?title=Pi-Python-Prepa
j'ai donc tapé les commandes suivantes

Code: Select all

sudo apt-get install python-dev
sudo apt-get install python-pip
sudo pip install feedparser
sudo easy_install -U distribute
sudo pip install RPi.GPIO

User avatar
fdion
Posts: 307
Joined: Sun Sep 16, 2012 2:33 pm
Location: North Carolina, USA
Contact: Website

Re: GPIO-Message d'erreur

Thu Nov 22, 2012 2:19 pm

J’étais sans accès a un Pi quand j'ai écrit le script, et pas le temps de faire un accès ssh par téléphonie 3G a un raspberry pi pour vérifier.

Le problème c'est que le code original de Adafruit importe Rpi.GPIO comme GPIO:

Code: Select all

import RPi.GPIO as GPIO
Mais moi j'utilise gpio plutôt que GPIO comme synonyme. En Python, tout en majuscules indique généralement une constante (ou bien un verbe HTTP dans certains frameworks).

Pour régler ton problème, utilise les majuscules:

Code: Select all

GPIO.cleanup
Plutot que gpio.cleanup() en minuscules.

Je pense que je vais commencer une série de tutoriels sur Python en français, sur mon blog (http://raspberry-python.blogspot.com) et commencer par certains principes de base qui aideront ceux qui veulent faire des modifs a du code existant, genre ce qu'il y a sur Adafruit, et les autres github, bitbucket et al.

François
Francois
http://raspberry-python.blogspot.com - http://www.3dFutureTech.info - @f_dion

jeek
Posts: 32
Joined: Sun Jul 22, 2012 6:43 am

Re: GPIO-Message d'erreur

Thu Nov 22, 2012 3:32 pm

Ooooooui !!! Ca marche !!!
Merci François tu as trouvé la solution.
Il me tarde de lire de nouveaux articles en français sur ton blog parce que la traduction automatique de google est une catastrophe (surtout pour les scripts qui se retrouvent en une seule ligne).

Pour ceux que ça intéresse je mets le script corrigé :

Code: Select all

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

import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
DEBUG = 1


# Lit les données SPI d'une puce MCP3008, 8 canaux disponibles (adcnum de 0 à 7)
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
        if((adcnum > 7) or (adcnum < 0)):
                return -1

        GPIO.output(cspin, True)

        GPIO.output(clockpin, False)  # met Clock à Low
        GPIO.output(cspin, False)     # met CS à Low (active le module MCP3008)

        commandout = adcnum  # numéro de channel
        commandout |= 0x18   # OR pour ajouter Start bit + signle-ended bit
                             # 0x18 = 24d = 00011000b
        commandout <<= 3      # décalage de 3 bits à gauche

        # Envoi des Bits sur le bus SPI
        for i in range(5):
                # faire un AND pour determiner l'état du bit de poids le plus
                # fort (0x80 = 128d = 10000000b)
                if(commandout & 0x80):  # faire un AND pour déterminer l'état du bit
                        GPIO.output(mosipin, True)
                else:
                        GPIO.output(mosipin, False)
                commandout <<= 1  # décalage de 1 bit sur la gauche

                # Envoi du bit mosipin avec signal d'horloge
                GPIO.output(clockpin, True)
                GPIO.output(clockpin, False)

        # lecture des bits renvoyés par le MCP3008
        # Lecture de 1  bit vide, 10 bits de données et un bit null
        adcout = 0
        for i in range(12):
                # Signal d'horloge pour que le MCP3008 place un bit
                GPIO.output(clockpin, True)
                GPIO.output(clockpin, False)
                # décalage de 1 bit vers la gauche
                adcout <<= 1
                # stockage du bit en fonction de la broche miso
                if(GPIO.input(misopin)):
                        adcout |= 0x1  # active le bit avec une opération OR

        # Mettre Chip Select à High (désactive le MCP3008)
        GPIO.output(cspin, True)

        # Le tout premier bit (celui de poids le plus faible, le dernier lut)
        # est null. Donc on l'elimine ce dernier bit en décalant vers la droite
        adcout >>= 1

        return adcout

# Broches connectées sur l'interface SPI du MCP3008 depuis le Cobbler
# (changer selon vos besoins)
SPICLK = 18
SPIMISO = 23
SPIMOSI = 24
SPICS = 25

# Initialisation de l'interface SPI
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPICS, GPIO.OUT)

# Potentiomètre 10KOhms raccordés sur le canal ADC #0
potentiometer_adc = 0


def main():
        while True:
                # Lecture analogique, retourne une valeur entre 0 et 1023
                # pour une valeur de tension entre 0 et VRef (3.3v)
                trim_pot = readadc(potentiometer_adc, SPICLK, SPIMOSI, SPIMISO, SPICS)

                print("Valeur: " + str(trim_pot))

                # convertir en tension
                print("tension: " + str((3.3 * trim_pot) / 1024))

                # attendre une demi-seconde
                time.sleep(0.5)


if __name__ == "__main__":
        try:
                main()
        except KeyboardInterrupt:
                GPIO.cleanup()

User avatar
fdion
Posts: 307
Joined: Sun Sep 16, 2012 2:33 pm
Location: North Carolina, USA
Contact: Website

Re: GPIO-Message d'erreur

Sun Nov 25, 2012 8:56 pm

Le lien pour les tutoriels sera ici: (je vais ajouter les liens de chaque tutoriels a cet article, donc faire un bookmark:
http://raspberry-python.blogspot.com/20 ... xpert.html

François
Francois
http://raspberry-python.blogspot.com - http://www.3dFutureTech.info - @f_dion

domeu
Authorised Reseller
Authorised Reseller
Posts: 18
Joined: Fri Mar 15, 2013 11:48 am
Location: Waterloo, Belgium
Contact: Website

Re: GPIO-Message d'erreur

Fri Mar 15, 2013 11:55 am

Merci pour l'information,

A l'occasion je mettrais le wiki à jour.

Dominique

Return to “Français”