Ligne 1 : |
Ligne 1 : |
| {{MicroPython-Hack-Prepare-NAV}} | | {{MicroPython-Hack-Prepare-NAV}} |
| | | |
− | == Ce que nous faisons ==
| + | {{MicroPython-Hack-Analogique-core}} |
− | '''.: Mesure de tension analogique :.'''
| |
− | | |
− | {{bloc-etroit|text=En plus de ses broches digitales, PyBoard dispose aussi de 16 broches qui peuvent être utilisées comme entrées analogiques. Ces entrées acceptent une tension (de 0 à 3.3 volts) et la converti en un nombre entier allant de 0 (0 volts) à 4095 (3.3 volts) avec une résolution de 12 bits. Un dispositif très utile qui exploite ces entrées est le potentiomètre (aussi appelé résistance variable). | |
− | | |
− | Lorsque les broches extérieures du potentiomètre sont alimentées avec 3.3volts, la broche du milieu permet de lire une valeur entre 0 et 3.3 volts, valeur dépendant de l'angle avec lequel le potentiomètre est tourné (ex : 1.65 volts à mi-course). Nous pouvons alors utiliser la valeur retournée comme une variable de notre programme.
| |
− | | |
− | Vous pouvez facilement identifier les broches analogiques sur le diagramme car elles sont marquées comme '''ADC'''.
| |
− | | |
− | {{MPImage|pybv10-pinout.jpg|640px}}
| |
− | | |
− | }}
| |
− | | |
− | == Le montage ==
| |
− | === Le matériel nécessaire ===
| |
− | {{ARDX-composant-begin}}
| |
− | | |
− | {{ARDX-composant
| |
− | |label=Fils
| |
− | |label2=
| |
− | |img=ARDX-fils.png
| |
− | |pl=34
| |
− | }}
| |
− | | |
− | {{ARDX-composant
| |
− | |label=Résistance de 100 Ohms (brun-noir-brun)
| |
− | |label2=x1
| |
− | |img=ARDX-R100.png
| |
− | |pl=45
| |
− | }}
| |
− | | |
− | {{ARDX-composant
| |
− | |label=LED (ou DEL)
| |
− | |label2=x1
| |
− | |img=ARDX-LED-verte.png
| |
− | |pl=66
| |
− | }}
| |
− | | |
− | {{ARDX-composant
| |
− | |label=Potentiomètre 10K Ohms
| |
− | |label2=x1
| |
− | |img=ARDX-Pot.png
| |
− | |pl=33
| |
− | }}
| |
− | | |
− | {{ARDX-composant-end}}
| |
− | Tous ces éléments sont disponibles sur [http://shop.mchobby.be shop.mchobby.be].
| |
− | | |
− | === Schéma ===
| |
− | [[Fichier:Hack-Analogique-schema.jpg]]
| |
− | | |
− | === Montage ===
| |
− | [[Fichier:MicroPython-Hack-Analogique-montage.jpg|800px]]
| |
− | | |
− | == Le code ==
| |
− | === Lecture analogique simple ===
| |
− | Voici un petit bout de code que vous pouvez tester en mode REPL.
| |
− | | |
− | Ce programme lit et affiche 10 fois l'entrée analogique à raison d'une fois par seconde.
| |
− | | |
− | <nowiki>pot = pyb.ADC( 'X19' ) # résolution par défaut 12 bits (valeur de 0 à 4096)
| |
− | for i in range( 0, 10 ):
| |
− | print( pot.read() )
| |
− | pyb.delay( 1000 )</nowiki>
| |
− | | |
− | Vous obtiendrez un résultat similaire à celui-ci (en bougeant le potentiomètre bien entendu).
| |
− | | |
− | <nowiki>4092
| |
− | 4095
| |
− | 4090
| |
− | 4093
| |
− | 3265
| |
− | 3266
| |
− | 3265
| |
− | 3264
| |
− | 3265
| |
− | 3265
| |
− | </nowiki>
| |
− | | |
− | === Potentiomètre vers PWM ===
| |
− | Le programme suivant lit la valeur sur l'entrée analogique et module la luminosité de la LED en fonction de la position du potentiomètre.
| |
− | | |
− | Vous pouvez le saisir en mode REPL (ce serait un peu long) ou simplement le placer dans le fichier {{fname|main.py}}.
| |
− | | |
− | Tournez le potentiomètre pour modifier la luminosité de la LED.
| |
− | | |
− | <nowiki># Lecture analogique pour controler la puissance d'une LED PWM.
| |
− | # ATTENTION: échantillonnage 12 Bits (valeur de 0 à 4096)
| |
− | from pyb import Timer, delay
| |
− | | |
− | adc = pyb.ADC(pyb.Pin.board.X19) # Créer ADC sur la broche X19
| |
− | | |
− | # Creer un timer à une fréquence de 5 Hz (le timer 5)
| |
− | # Créer un canal (channel) PWM avec le Timer.
| |
− | tim = pyb.Timer( 5, freq=100)
| |
− | tchannel = tim.channel(1, Timer.PWM, pin=pyb.Pin.board.X1, pulse_width=0)
| |
− | | |
− | # Minimum et Maximum de largeur d'impulsion correspondant au minimum
| |
− | # et maximum de luminosité
| |
− | max_width = 150000
| |
− | min_width = 8000
| |
− | | |
− | # fonction qui permet de passer d'un range de valeur (in_) à une autre
| |
− | # (out_) en appliquant une règle de trois.
| |
− | def arduino_map(x, in_min, in_max, out_min, out_max):
| |
− | return int( (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min )
| |
− | | |
− | while True:
| |
− | # Lectures analogiques
| |
− | ivalue = adc.read()
| |
− |
| |
− | # Transformer une valeur analogique (0 à 4096) en largeur d'impulsion (20000 à 2000000)
| |
− | pulse_width = arduino_map( ivalue, 0, 4096, min_width, max_width )
| |
− |
| |
− | # Modifier le signal PWM
| |
− | tchannel.pulse_width( pulse_width )
| |
− |
| |
− | delay( 100 )
| |
− | </nowiki>
| |
− | | |
− | == Cela ne fonctionne pas? ==
| |
− | Il y a 3 choses à essayer.
| |
− | | |
− | === Fonctionne sporadiquement ===
| |
− | Cela est souvent dû à une connexion imparfaite des broches du potentiomètre.
| |
− | | |
− | Cela peut généralement être résolu en tapotant un peu sur le potentiomètre.
| |
− | | |
− | === Cela ne fonctionne pas! ===
| |
− | Assurez-vous de ne pas avoir accidentellement connecté le fil du potentiomètre sur la broche X9 au lieu de la broche X19 (la série de broche à l'opposé au port micro USB)
| |
− | | |
− | === Toujours en panne? ===
| |
− | Essayez de démonter et remonter le circuit, parfois cela fonctionne mieux.
| |
− | | |
− | == Faire encore mieux ==
| |
− | | |
− | === Seuil d'allumage (threshold) ===
| |
− | Vous voulez parfois activer une sortie lorsqu'une valeur a atteint un certain seuil.
| |
− | | |
− | Dans cet exemple de programme, nous avons fait le choix délibéré d'utiliser un seuil en pourcentage. Nous aurions pu choisir la valeur 1843 produite par le convertisseur digital -> analogique.
| |
− | | |
− | 1843 représente quand même 1843 / 4096 * 100 = 44.99% de la valeur maximale retournée par le convertisseur.
| |
− | | |
− | Si je vous dis, "mettez le potentiomètre à la valeur 1843!" ou "mettez le potentiomètre à 45%" vous remarquerez que la seconde expression est naturellement transposable en action physique.
| |
− | | |
− | Nous allons donc:
| |
− | # Réutiliser la fonction magique {{fname|arduino_map}} pour transformer la valeur du convertisseur analogique digital (0-4096) en valeur de 0 à 100.
| |
− | # Comparer la valeur obtenue à un seuil exprimé en "pourcentage", voyez la variable {{fname|seuil_pc}}
| |
− | | |
− | Pour faire cela avec un potentiomètre, changez le code de votre programme comme suit :
| |
− | | |
− | <nowiki># Lecture analogique pour contrôler allumer une LED sur base d'un seuil.
| |
− | # ATTENTION: échantillonnage 12 Bits (valeur de 0 à 4096)
| |
− | from pyb import Timer, delay
| |
− | | |
− | adc = pyb.ADC(pyb.Pin.board.X19) # Créer ADC sur la broche X19
| |
− | led = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.OUT_PP ) # Créer la sortie pour la LED
| |
− | led.low() # Led éteinte
| |
− | seuil_pc = 45 # seuil à 45%
| |
− | | |
− | # fonction qui permet de passer d'un range de valeur (in_) à une autre
| |
− | # (out_) en appliquant une règle de trois.
| |
− | def arduino_map(x, in_min, in_max, out_min, out_max):
| |
− | return int( (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min )
| |
− | | |
− | while True:
| |
− | # Lectures analogiques
| |
− | ivalue = adc.read()
| |
− |
| |
− | # Transformer une valeur analogique (0 à 4096) en pourcent (0 à 100)
| |
− | position_pc = arduino_map( ivalue, 0, 4096, 0, 100 )
| |
− |
| |
− | # Activer la sortie si plus grand que seuil
| |
− | if position_pc > seuil_pc:
| |
− | led.high()
| |
− | else:
| |
− | led.low()
| |
− |
| |
− | delay( 100 )</nowiki>
| |
− | | |
− | Cela allumera la LED lorsque la valeur sera supérieure à 45% de la course du potentiomètre, vous pouvez adapter la sensibilité en modifiant la valeur du seuil (la variable {{fname|seuil_pc}}) avec une valeur entre 0 et 100.
| |
− | | |
− | === Optimisation ===
| |
− | Dans le point précédent, nous avons activé la LED à l'aide d'un bloc {{fname|if... else}} afin de préserver la lisibilité.
| |
− | | |
− | <nowiki> # Activer la sortie si plus grand que seuil
| |
− | if position_pc > seuil_pc:
| |
− | led.high()
| |
− | else:
| |
− | led.low()</nowiki>
| |
− | | |
− | Le fait est que l'expression {{fname|position_pc > seuil_pc}} est soit vraie/{{fname|True}}, soit fausse/{{fname|False}}.
| |
− | | |
− | Il est donc possible de remplacer le bloc {{fname|if... else}} et {{fname|led.high()}}/{{fname|led.low()}} par une seule ligne de code:
| |
− | | |
− | <nowiki>led.value( position_pc > seuil_pc )</nowiki>
| |
− | | |
− | === Encore moins de code! ===
| |
− | Bien que l'on perte beaucoup en lisibilité, le bloc {{fname|while}} de notre programme peut être réduit à deux ligne... si si
| |
− | | |
− | <nowiki>from pyb import Timer, delay
| |
− | | |
− | adc = pyb.ADC(pyb.Pin.board.X19) # Créer ADC sur la broche X19
| |
− | led = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.OUT_PP ) # Créer la sortie pour la LED
| |
− | led.low() # Led éteinte
| |
− | seuil_pc = 45 # seuil à 45%
| |
− | | |
− | def arduino_map(x, in_min, in_max, out_min, out_max):
| |
− | return int( (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min )
| |
− | | |
− | while True:
| |
− | led.value( arduino_map( adc.read(), 0, 4096, 0, 100 ) > seuil_pc )
| |
− | delay( 100 )</nowiki>
| |
− | | |
− | === Contrôler un servo ===
| |
− | C'est vraiment un bel exemple qui regroupe ensemble une série de montages ensembles.
| |
− | | |
− | Raccordez le Servo moteur sur X2 comme [MicroPython-Hack-servo nous l'avons dans ce tutoriel], nous allons ensuite saisir le programme suivant pour contrôler la position du servo moteur à partir de la position du potentiomètre.
| |
− | | |
− | <nowiki># Lecture analogique pour contrôler allumer une LED sur base d'un seuil.
| |
− | # ATTENTION: échantillonnage 12 Bits (valeur de 0 à 4096)
| |
− | from pyb import Timer, delay
| |
− | | |
− | adc = pyb.ADC(pyb.Pin.board.X19) # Créer ADC sur la broche X19
| |
− | servo = pyb.Servo(2) # Servo moteur sur X2
| |
− | | |
− | # fonction qui permet de passer d'un range de valeur (in_) à une autre
| |
− | # (out_) en appliquant une règle de trois.
| |
− | def arduino_map(x, in_min, in_max, out_min, out_max):
| |
− | return int( (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min )
| |
− | | |
− | while True:
| |
− | # Lectures analogiques
| |
− | ivalue = adc.read()
| |
− |
| |
− | # Transformer une valeur analogique (0 à 4096) en angle entre -90° à +90°
| |
− | angle = arduino_map( ivalue, 0, 4096, -90, 90 )
| |
− |
| |
− | # Activer la sortie si plus grand que seuil
| |
− | servo.angle( angle )
| |
− |
| |
− | delay( 100 )</nowiki>
| |
− | | |
− | Chargez sur votre PyBoard dans le fichier {{fname|main.py}}, éjectez le lecteur de la Pyboard puis appuyez sur le bouton "Reset" de votre carte.
| |
− | | |
− | Regardez l'axe du Servo tourner lorsque vous tournez le potentiomètre.
| |
− | | |
− | === Parasites, lecture multiple et moyenne ===
| |
− | Il est également possible de réaliser des lectures en rafale et de les stocker dans un tableau.
| |
− | | |
− | Cela permet d'effectuer une moyenne sur plusieurs lectures, une façon d'amortir l'implication d'une valeur parasite. Vous aurez en effet remarqué que la valeur varie sensiblement d'une lecture à l'autre même si vous ne bougez pas le potentiomètre.
| |
− | | |
− | Cela est provoqué par les différentes perturbations comme:
| |
− | * Le bruit sur l'alimentation (surtout USB),
| |
− | * Les connexion imparfaites (surtout sur les breadboard)
| |
− | * La longueur des fils... qui sont sensibles au perturbation électromagnétique.<small><br />blindez les et/ou utiliser une paire torsadée</small>
| |
− | | |
− | La fonction {{fname|ADC.read_timed(buffer, frequence)}} permet de faire de multiples captures sur une entrée et remplir un tableau. Il faut cependant faire attention au type de tableau passé en entrée... sinon vous passez en échantillonnage 8bits (avec des valeurs lue de 0 à 255).
| |
− | | |
− | ==== Lecture en échantillonnage 8 Bits ====
| |
− | Dans l'exemple suivant, issu de la doc officielle, les valeurs retournées varient entre 0 et 255. En effet, en passant un {{fname|bytearray}} à la fonction {{fname|read_timed()}} nous indiquons aussi que l'espace de stockage est un tableau de Byte (d'Octet)... et un Byte/Octet est stocké sur 8 bits. Par conséquent, le convertisseur anamogique/digital passe en résolution 8 bits!!!
| |
− | | |
− | <nowiki># Lecture analogique avec moyenne.
| |
− | # ATTENTION: échantillonnage 8 Bits (valeur de 0 à 255)
| |
− | | |
− | adc = pyb.ADC(pyb.Pin.board.X19) # Créer ADC sur la broche X19
| |
− | buf = bytearray(100) # Créer une mémoire tampon (buffer)
| |
− | # de 100 octets/bytes
| |
− | adc.read_timed(buf, 10) # Lectures analogiques à la fréquence
| |
− | # de 10Hz, stockage directement dans
| |
− | # le Buffer
| |
− | # Cela prendra 10 secondes pour
| |
− | # être complètement achevé.
| |
− | | |
− | for val in buf: # Affichage de toutes les valeurs
| |
− | print(val)
| |
− |
| |
− | # calcul de la moyenne
| |
− | print( 'Moyenne: %s' % (sum(buf)/len(buf)) )</nowiki>
| |
− | | |
− | ==== Lecture en échantillonnage 12 bits ====
| |
− | Si vous avez été attentif au point précédent, vous savez maintenant qu'il faut faire attention à la création de la mémoire tampon (''buffer'') pour pouvoir réaliser des lectures multiples en 12bit.
| |
− | | |
− | Voici la marche à suivre pour garder un échantillonnage 12 bits (valeurs de 0 à 4095):
| |
− | | |
− | <nowiki>import pyb, array
| |
− | # Utiliser une constante pour identifier la broche
| |
− | adc = pyb.ADC( pyb.Pin.board.X19 )
| |
− | # Créer et initialize un Buffer (mémoire tempon) capable de recevoir
| |
− | # des valeurs 12bits.
| |
− | buf = array.array('H')
| |
− | for i in range(10): buf.append( 0 )
| |
− | # Passez votre curiosité dans la structure du tableau
| |
− | # print( buf )
| |
− | # vous aurez une réponse comme celle-ci:
| |
− | # array('H', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
| |
− | | |
− | | |
− | # Faire une lecture de valeur analogique dans le buffer
| |
− | # à une fréquence de 10 Hertz (cela prendra 10 secondes)
| |
− | adc.read_timed(buf, 10)
| |
− | # Afficher les valeurs
| |
− | for valeur in buf:
| |
− | print( valeur )
| |
− | # calcul de la moyenne
| |
− | print( 'Moyenne: %s' % (sum(buf)/len(buf)) )</nowiki>
| |
− | | |
− | == Internet ==
| |
− | Voici quelques ressources utiles.
| |
− | * [http://forum.micropython.org/viewtopic.php?t=399#p2321 Améliorer la stabilité de la lecture analogique] (''Anglais, MicroPython Forum'')
| |
− | * [http://docs.micropython.org/en/v1.5.1/library/pyb.ADC.html Classe ADC] (''Anglais, MycroPython documentation'')
| |
| | | |
| {{MicroPython-Hack-MCH-TRAILER}} | | {{MicroPython-Hack-MCH-TRAILER}} |