lundi 24 juillet 2023

Contrôler un Raspberry Pi Pico avec une télécommande de téléviseur (Micropython)

Dans bien des situations, une télécommande à infrarouge constitue une bonne façon d'interagir avec le dispositif électronique que vous avez fabriqué. Dans cet article, je vous explique comment communiquer avec un Raspberry Pi Pico (programmé en Micropython) avec une télécommande à infrarouge conçue pour un téléviseur.


La télécommande

C'est généralement facile de trouver une vieille télécommande à infrarouge. Il y a quelques années,  il y en avait quatre sur ma table de salon: une pour le téléviseur, une pour le lecteur de DVD, une pour le lecteur de cassettes VHS, et une autre pour la chaîne stéréo... Au cours des années, les appareils ont été remplacés ou mis au rancart, mais la télécommande est demeurée fonctionnelle.


Lorsque vous appuyez sur un des boutons de la télécommande, une LED à infrarouge se met à clignoter. Puisqu'il s'agit d'infrarouge et non de lumière visible, vous ne pouvez pas percevoir ce clignotement à l'oeil nu. Par contre, si vous regardez la LED à travers la caméra de votre téléphone, vous devriez la voir s'allumer lorsque vous appuyez sur un des boutons (il s'agit d'une façon rapide et efficace de vérifier qu'une vieille télécommande fonctionne encore).


Ce signal infrarouge transporte un message. Ce qui vient compliquer les choses, c'est qu'il existe un grand nombre de protocoles (NEC, Sony. RC-5, RC-6, Samsung, Panasonic, etc), et la bibliothèque Micropython que nous allons utiliser ne supporte qu'un certain nombre de ces protocoles.

Le récepteur

Pour capter le signal optique émis par la télécommande et le transformer en un signal électrique pouvant être interprété par le Raspberry Pi Pico, vous aurez besoin d'un composant spécialement conçu à cette fin. Pour la rédaction de cet article, j'ai utilisé le TSOP4838 fabriqué par la compagnie Vishay. Une autre option consiste à récupérer le récepteur à l'intérieur d'un vieux téléviseur qui ne fonctionne plus (ce sera possiblement un autre modèle et vous devrez donc faire quelques recherches ou expérimentations).

Le TSOP4838 comporte 3 broches: OUT (le signal de sortie), GND et VCC. 

La façon la plus simple de brancher le TSOP4838 au Raspberry Pi Pico est celle-ci:

  • Broche OUT du  TSOP4838: Broche GP16 du Raspberry Pi Pico
  • Broche GND du TSOP4838: Broche GND du Raspberry Pi Pico
  • Broche VCC du TSOP4838: Broche 3,3 V du Raspberry Pi Pico

Pour améliorer la stabilité du circuit, on peut aussi ajouter une résistance de 100 Ω entre la broche VCC du TSOP4838 et la sortie 3,3 V du Raspberry Pi Pico, ainsi qu'un condensateur de 0,1 µF entre GND et VCC. J'ai testé les deux options sans constater la moindre différence dans le comportement du circuit.


Installation de la bibliothèque micropython_ir 

Nous utiliserons la bilbliothèque micropython_ir mise au point par Peter Hinch. Tout le répertoire "ir_rx" qui doit être copié dans la mémoire du Raspberry Pi Pico.



Identification du protocole utilisé par la télécommande

Pour écrire votre programme en Micropython, il est important de savoir quel est le protocole utilisé par votre télécommande. Si vous ne le connaissez pas, la bibliothèque micropython_ir vous offre deux façon de le découvrir:

Option 1, vous écrivez ceci dans la console REPL:

    from ir_rx.acquire import test
    test()

Option 2, vous écrivez ceci dans la console REPL:

    from ir_rx.test import test

... puis vous choisissez le protocole que vous désirez tester en écrivant test() pour tester le protocole NEC 8 bit, test(1) pour tester le protocole NEC 16 bits, etc.

Je dois dire que j'ai été un peu déçu par le manque d'efficacité de ces tests. L'option 2 s'interrompt généralement en affichant "unknown protocol" avant même que j'aie eu le temps d'appuyer sur un bouton de la télécommande.

L'option 1 me retourne beaucoup de messages d'erreurs, mais lorsque je sélectionne le protocole qui correspond à ma télécommande, des lignes montrant les valeurs hexadécimales de Data, Addr et Ctrl sont affichées (je suggère de maintenir le bouton enfoncé un certain temps, ça permet d'afficher plusieurs lignes consécutives qui sont plus faciles à repérer parmi les lignes qui affichent une erreur).

Ainsi, parmi les télécommandes que j'ai testées, j'en ai trouvé une qui fonctionne selon le protocole "Sony 20 bits", et une autre qui utilise le protocole "Samsung". Comme je le disais plus haut, plusieurs protocoles ne sont pas supportés pour l'instant. Par exemple, ma télécommande Hitachi qui m'avait été bien utile dans certains projets Arduino ne peut pas être utilisée avec micropython_ir.


Exemples de scripts

Une fois que vous connaissez le protocole utilisé par votre télécommande, c'est assez facile d'écrire un programme qui accomplira une action différente selon le bouton qui est enfoncé.

Voici, par exemple, un script qui affiche dans la console les valeurs hexadécimales associées aux boutons de ma télécommande Samsung. Les valeurs de Data et de Addr me permettent de savoir quel bouton de la télécommande a été enfoncé, et je peux ensuite modifier ce programme pour que le Raspberry Pi Pico effectue la tâche qui correspond à ce bouton (allumer une LED, faire tourner un robot vers la droite, etc.).

-

-

Le script ci-dessous est identique, mais pour ma télécommande Sony.

-

-


À lire également:

Yves Pelletier

vendredi 21 juillet 2023

Peser des objets avec le Raspberry Pi Pico (Micropython)

Ce projet consiste à mettre au point une balance constituée d'une cellule de charge, d'une module HX-711 et d'un Raspberry Pi Pico programmé en Micropython.


La cellule de charge (load cell), ou capteur de force, est un morceau de métal sur lequel quatre jauges de déformations on été collées: ces jauges sont des résistances qui varient lorsque la cellule de charge se déforme. Vous devez vous procurer une cellule de charge dont la charge (masse) maximale correspond à vos besoins. Il est possible d'acheter un kit comportant la cellule de charge, une paire de plaques de plexiglas et un module HX-711,


Ces quatre jauges sont branchées ensemble de façon à former un pont de Wheatstone.  Le module HX711 amplifie la très faible variation de signal engendrée par la très subtile déformation de la cellule de charge, et la convertit en un signal numérique qui pourra ensuite être traité par le Raspberry Pi Pico.

Connexion de la cellule de charge au module HX711

Le module HX711 comporte 6 connecteurs servant à brancher la cellule de charge (E+, E-, A-, A+, B-, B+), et quatre connecteurs servant à l'alimentation et à la communication avec un microcontrôleur (GND, DT, SCK, VCC).


J'ai branché ma cellule de charge au module HX711 de la façon suivante:

  • Fil rouge: E+
  • Fil noir: E-
  • Fil blanc: A-
  • Fil vert: A+

E+ et E- sont des sorties (signal d'excitation du pont de Wheatstone), alors que A+ et A- sont des entrées.  Je n'ai pas eu besoin de B- ni de B+.


Connexions du module HX711 au Raspberry Pi Pico

Voici comment j'ai branché le module HX711 au Raspberry Pi Pico

  • GND du HX711: une des broches GND du Pico
  • DT du HX711: GP15 du Pico *
  • SCK du HX711 : GP14 du Pico *
  • VCC du HX711: sortie 3,3 V du Pico
* Vous pouvez choisir n'importe quelle broche du Raspberry Pi Pico pour le branchement de DT et SCK, puisqu'on les définit à l'intérieur du programme.



Installation de la bibliothèque hx711-pico-mpy

Daniel Robertson a créé un pilote en micropython spécialement pour l'utilisation d'un module HX-711 avec un Raspberry Pi Pico: il est disponible ici sur Github. Afin d'utiliser ce pilote, il faut installer dans le Raspberry Pi Pico le fichier intitulé hx711.py.


Script en Micropython

Voici un script minimaliste (en micropython) qui affiche la masse dans la console, de façon répétitive.

-

-

Le pilote hx711.py s'occupe de la prise de mesure et notre script n'a donc qu'à utiliser la méthode get_value() chaque fois qu'on désire qu'une mesure soit prise. La valeur obtenue, toutefois, est un nombre entier qui n'est pas nul lorsque le plateau de la balance est vide, et qui ne correspond à aucune unité de mesure de masse.

Pour afficher la masse en gramme, notre programme doit faire un calcul à partir de la valeur retournée par get_value(); c'est ce qui est fait à la ligne 28. Les valeurs numériques utilisées pour cette conversion (aux lignes 18 et 19) sont spécifiques à la cellule de charge que j'ai utilisée, et doivent être modifiées pour chaque cellule de charge (même lorsqu'elles sont du même modèle). Cette calibration n'est pas très difficile à faire, il s'agit de récupérer le résultat brut de get_value() lorsqu'une masse connue se trouve sur le plateau de la balance.

Dans mon cas, les valeurs obtenues étaient très fluctuantes si je tentais d'afficher les dixièmes de grammes, c'est pourquoi j'ai arrondi au gramme près.

Bien entendu, l'ajout d'un afficheur OLED vous permettra de transformer le montage en une véritable balance autonome. De plus, le zéro a tendance à se désajuster légèrement d'une utilisation à l'autre; l'ajout d'un bouton "tare" serait certainement pertinent.

À lire également:


Yves Pelletier

mardi 18 juillet 2023

Matrice de LEDs RGB 16 X 16 WS2812B et Raspberry Pi Pico (Micropython)

Ce projet consiste à utiliser un Raspberry Pi Pico programmé en Micropython afin de contrôler une matrice de forme carrée comportant 256 LEDs RGB de type Neopixel (contrôleur WS2812B).


Connexions

Le verso de la matrice de LEDs comporte 8 connecteurs mais ils ne sont pas tous nécessaires. Le groupe de 3 fils du côté gauche de la photo (dont un fil porte la mention DOUT) ne sont utiles que lorsque vous désirez brancher plusieurs matrices à la queue-leu-leu.


Si vous n'en utilisez qu'une seule (256 LEDs, c'est déjà pas mal!) vous n'avez besoin que de 4 connexions:

Les deux fils situés au centre (un noir et un rouge) servent à l'alimentation des LEDs. Il faut une tension continue de 5 V, et l'alimentation doit être capable de fournir quelques ampères.

Dans le groupe de trois fils qu'on voit à droite sur la photo, le fil blanc (GND) doit être branché à une des broches GND du Raspberry Pi Pico, alors que le fil vert (DIN), qui transmettra l'information servant à contrôler la couleur et l'intensité de chaque LED sera branché à une broche du Raspberry Pi Pico de votre choix, que nous définirons à l'intérieur de notre programme en Micropython (j'ai utilisé la broche GP15 du Raspberry Pi Pico).

Installation de la bibliothèque NeoPixel

Pour réaliser ce projet, j'ai utilisé le pilote pi_pico_neopixel. Le fichier neopixel.py doit être copié dans le Raspberry Pi Pico.


Exemple 1: lignes mouvantes


Dans ce premier script en micropython, les 16 LEDs d'une même ligne s'allument avec la même couleur, et la couleur est différente pour chaque ligne. Un effet d'animation provoque un déplacement des lignes.


-

-

Le constructeur (ligne 18) requiert 3 paramètres: le nombre de LEDs (dans mon cas, il y en a 256), le numéro d'ID de la machine d'état PIO utilisée par la bibliothèque, et le numéro de la broche du Raspberry Pi Pico à laquelle nous avons branché la matrice de LEDs (dans mon cas, c'était la broche GP15).

pixels = Neopixel(nombre_de_LEDs, 1, broche)

Lorsqu'on veut régler les paramètres d'une seule LED, on utilise la méthode set_pixel. Pour cet exemple, toutefois, il était plus pratique d'utiliser la méthode set_pixel_line, qui permet de régler un groupe de LEDs adjacentes, à la condition qu'elles soient toutes de la même couleur.

set_pixel_line(numéro de la première LED, numéro de la dernière LED, couleur RGB)

Sur une matrice bidimensionnelle, la numérotation des LEDs est un peu problématique car la matrice est constituée d'un ruban linéaire disposé en zigag. Par exemple, les LEDs de la première ligne sont numérotées de 0 à 15 en allant de la gauche vers la droite. Celles de la deuxième ligne sont numérotés de 16 à 31, mais en allant de la droite vers la gauche.

Pour cet exemple, puisque toutes les LEDs situées sur une même ligne ont la même couleur, il s'agit d'assigner la couleur rouge aux LEDs 0 à 15, la couleur orange aux LEDs 16 à 31, etc.

La couleur RGB est une liste de 3 nombres entiers situés entre 0 et 255: le premier nombre indique la quantité de rouge, le deuxième indique la quantité de vert, et le troisième indique la quantité de bleu.

Finalement, pour que vos nouveaux réglages soient visibles, il est important de terminer avec la méthode show (ligne 31).

Exemple 2: promeneurs aléatoires


Dans ce deuxième exemple: 6 points de couleurs différentes se déplacent au hasard. À chaque itération, le "promeneur" peut bouger vers une position adjacente, mais bien sûr il ne peut pas sortir des limites de la matrice.


-

-

Chacun des 6 promeneurs est décrit par 2 caractéristiques: sa couleur et sa position (lignes 34 à 39).

Cette fois, il est essentiel de désigner les positions au moyen de coordonnées x et y (numéro de la colonne et numéro de la ligne): la fonction xy_a_nombre calcule le numéro de la LED à partir de ces deux coordonnées.


À lire aussi

J'ai également écrit un article sur l'utilisation de cette matrice de LEDs avec une carte Arduino, et un autre avec les cartes ESP32 et ESP8266.

Mes autres articles concernant la programmation du Raspberry Pi Pico en Micropython se trouvent dans la dernière moitié de cette page.


Yves Pelletier

samedi 15 juillet 2023

Utilisation d'un codeur rotatif avec le Raspberry Pi Pico (Micropython)

À première vue, un codeur rotatif (rotary encoder) ressemble à un potentiomètre: il s'agit d'un bouton que l'utilisateur peut tourner afin de contrôler un appareil (modifier le volume sonore, par exemple).

Contrairement au potentiomètre, toutefois, le codeur rotatif produit un signal purement numérique. Deux interrupteurs s'ouvrent et se ferment à mesure qu'on tourne le bouton. Ces deux interrupteurs sont placés en quadrature, c'est à dire qu'ils sont décalés dans le temps l'un par rapport à l'autre, ce qui permet de déduire le sens de la rotation du bouton.


Connexions du codeur rotatif au Rasberry Pi Pico

Pour la rédaction de ce tuto, j'ai utilisé un codeur rotatif de type KY-040: il s'agit d'un petit module qui comporte, en plus du codeur rotatif lui-même, des résistances de tirage 10 kΩ. Le module comporte 5 connecteurs: CLK et DT (clock et data) sont les deux interrupteurs en quadrature actionnés par la rotation du bouton, alors que SW (switch) est l'interrupteur qui est actionné lorsqu'on pousse sur le bouton. Les entrées + et GND servent à l'alimentation du module.

J'ai branché le codeur rotatif au Raspbery Pi Pico de la façon suivante:

  • Broche GND du codeur rotatif: une des broches GND du Raspberry Pi Pico
  • Broche + du codeur rotatif: sortie 3,3 V du Raspberry Pi Pico
  • Broche SW du codeur rotatif: broche GP15 du Raspberry Pi Pico *
  • Broche DT du codeur rotatif: broche GP 14 du Raspberry Pi Pico *
  • Broche CLK du codeur rotatif: broche GP 13 du Raspberry Pi Pico *
* Ces 3 broches seront définies dans notre programme en micropython, et vous pouvez donc les remplacer par d'autres broches au besoin.


Installation de la bibliothèque micropython "Rotary"

Mike Teachman a produit un excellent pilote Micropython pour l'utilisation d'un codeur rotatif

Deux fichiers de ce dépôt gitHub doivent être installés sur votre Raspberry Pi Pico: 
  • rotary.py 
  • rotary_irq_rp2.py

Script en micropython #1

-
-

Lorsque vous exécutez le programme ci-dessus avec Thonny, la console affiche la valeur du codeur chaque fois qu'elle change (donc lorsque vous tournez le bouton). L'état du bouton poussoir s'affiche également lorsque son état change (0 quand il est enfoncé, 1 quand il est relâché).



Le constructeur RotaryIRQ (lignes 17 à 22) comporte plusieurs arguments qui nous permettent de personnaliser le comportement de l'encodeur rotatif:
  • pin_num_clk : numéro de la broche du Raspberry Pi Pico reliée à la sortie CLK de l'encodeur.
  • pin_num_dt : numéro de la broche du Raspberry Pi Pico reliée à la sortie DT de l'encodeur.
  • min_val : valeur minimale générée par l'encodeur (par défaut: 0)
  • max_val : valeur maximale générée par l'encodeur (par défaut: 10)
  • incr : de quel incrément la valeur change à chaque 'click' pendant la rotation de l'encodeur. (par défaut: 1)
  • reverse: booléen indiquant pour quel sens de rotation les valeurs augmentent. À "False", la valeur augmente quand on tourne dans le sens antihoraire. À "True", la valeur augmente quand on tourne dans le sens horaire.
  • range_mode: détermine comment l'encodeur se comportera lorsque les limites min_val et max_val sont dépassées. Les trois valeurs possibles sont RotaryIRQ.RANGE_UNBOUNDED (aucune limite), RotaryIRQ.RANGE_BOUNDED (la valeur plafonne au résultat maximum lorsqu'on tente de le dépasser) et RotaryIRQ.RANGE_WRAP (la valeur retourne au minimum lorsqu'on dépasse le maximum).
  • pull_up: booléen qu'on règle à True pour activer les résistances pull-up internes du Raspberry Pi Pico si notre codeur rotatif ne comporte pas de résistances pull-up (ce qui n'est pas notre cas).
  • half_step: booléen qu'on peut régler à True pour activer la détection des demi-pas.
  • invert: booléen qu'on peut régler à True pour inverser les broches DT et CLK.
La seule contrainte un peu gênante que j'ai trouvée au pilote de Mike Teachman, c'est que la valeur initiale du codeur rotatif est nécessairement la valeur minimale. On peut imaginer des cas où il serait plus pertinent qu'au démarrage du programme, la valeur se situe à mi-chemin entre le minimum et le maximum, mais ça ne semble pas avoir été prévu.

Le pilote ne gère pas le signal généré par la sortie SW du module KY-040 (qui indique si l'utilisateur a enfoncé le bouton), mais c'est facile de le prendre en charge nous-mêmes dans notre script. Contrairement aux sorties CLK et DT, la sortie SW n'est munie d'aucune résistance de tirage, c'est pourquoi on active la résistance pull up interne de la broche 15 (ligne 26).

Script en micropython #2

-
-

Dans ce deuxième exemple, le codeur rotatif contrôle la luminosité de la LED embarquée du Raspberry Pi Pico. Cette LED est donc alimentée par un signal modulé en largeur d'impulsion (PWM). Les valeurs limites du codeur rotatif sont réglées à un minimum de 0 (rapport cyclique de 0%, LED complètement éteinte) et à un maximum de 65535 (rapport cyclique de 100%, LED allumée à pleine intensité). De plus, l'incrément a été réglé à 4000 pour qu'il ne soit pas nécessaire de faire accomplir au bouton des centaines de tours avant de commencer à constater un résultat...

Lorsque vous exécutez ce script, la LED devrait être éteinte au départ, mais elle devient de plus en plus brillante à mesure que vous tournez le bouton dans le sens horaire.

À lire également:

Ce blog comporte aussi un article sur l'utilisation d'un codeur rotatif avec une carte Arduino, et avec une carte STM 32 Nucleo programmée avec mbed.

Mes autres articles concernant la programmation du Raspberry Pi Pico en Micropython se trouvent dans la dernière moitié de cette page.


Yves Pelletier