Voici les objectifs :

  • animer les bonhommes de neige
  • animer le père-noël dans la cheminée
  • éclairer l'étoile de neige du sapin
  • et passer de la musique de Noël pendant l'animation.

Avant cela, nous allons construire un petit coffre contenant toute l'informatique. Le fichier PDF sera bientôt disponible.

1.Le choix du micrologiciel

Nous aurions pu choisir MicroPython pour notre montage. Mais, je n'ai pas trouvé de module son satisfaisant pour jouer du mp3. Je me suis rapproché de la société Adafruit qui a développé son propre micrologiciel pour ses modules. J'utilise le module son Adafruit MAX98357 I2S Class-D Mono Amp. C'est un petit amplificateur mono.

2.Installation de CircuitPython

Il existe plusieurs méthodes pour installer CircuitPython. Nous allons voir les deux méthodes.

2a.Téléchargement du fichier uf2

Utilisez le lien suivant https://circuitpython.org/downloads . Vous avez deux types Pi Pico, le Pico sans Wifi et le Pico avec le module Wifi. Nous utiliserons le premier.

 

Cliquez sur Pico et télécharger le fichier UF2 de la dernière version stable.

 

Pour installer CircuitPython, brancher le Pi Pico sur un port USB de votre ordinateur et appuyer en même temps sur le bouton BOOTSEL. Normalement, une fenêtre s'affiche comme ci-dessous.

 bootsel

Il suffira de copier le fichier dans le dossier qui a été ouvert lors de la connexion en USB.

Sélection 2131 

Une fois le fichier copié, le Pi Pico redémarre automatiquement avec CircuitPython. Si vous utilisez Thonny, l'invite de commande a changé, c'est celui de CircuitPython.

Sélection 2134

Il faudra indiquer à Thonny que vous utiliser CircuitPython. Cliquez sur le menu Tools -> Options. Cliquez sur l'onglet Interpreter et sélectionnez CircuitPython (generic)

Sélection 2139

Le Pi Pico fonctionne comme une clé USB, il se monte automatiquement et le nom du média s'appelle CIRCUITPY. Contrairement à MicroPython qui nous offre 1,4 Mo de stockage, nous n'aurons qu' 1 Mo de stockage.

Sélection 2133

2b.Utilisation du logiciel Thonny

 Avant de lancer le logiciel Thonny, brancher le Pi Pico sur un port USB de votre ordinateur et appuyer en même temps sur le bouton BOOTSEL. Normalement, une fenêtre s'affiche comme ci-dessous.

bootsel

Lancez le programme Thonny et cliquez sur le menu en bas à droite

menu python01

Choisissez Install CircuitPython

menu thonny

Une boîte de dialogue s'affiche et choisissez le modèle de Pi Pico. Dans notre exemple, nous prenons le Pi Pico sans Wifi : le Raspberry Pi * Pico/Pico H version 1.21.0

choix version

Une fois le système, cliquez sur Close. Une fois le fichier copié, le Pi Pico redémarre automatiquement avec CircuitPython. Pour vérifier le bon fonctionnement du Pi Pico, cliquez sur le bouton rouge qui va redémarrer le système.

invite thonny

En bas de la fenêtre console, vous devriez voir ce message :

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Press any key to enter the REPL. Use CTRL-D to reload.

Adafruit CircuitPython 8.2.9 on 2023-12-06; Raspberry Pi Pico with rp2040

soft reboot
]0;🐍REPL | 8.2.9\
Adafruit CircuitPython 8.2.9 on 2023-12-06; Raspberry Pi Pico with rp2040
>>> 

Comme précédemment, il faudra modifier l'interpreter de Thonny pour CircuitPython.

3.Le programme pas à pas

3a. les servomoteurs des bonhommes de neige

Premier montage avec une platine d'essai et des fils jumper permettant des modifications rapides. Le bouton et la LED sont réunis dans un bouton confectionné en Lego.

montage01

le schéma

cablage diorama noel01

Nous devrons installer la librairie adafruit_motor pour utiliser les servomoteurs. Téléchargez le bundle des librairies CircuitPython avec ce lien https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/latest. Récupérez le dossier adafruit_motor et le copiez-le dans le Pi Pico dans le dossier lib comme ci-dessous.

librairie moteur

Voici le premier code. Il diffère un peu de MicroPython. Le programme principal est composé d'une boucle infinie. La led du bouton clignote tant que l'on n'a pas appuyé sur le bouton. Une fois le bouton appuyé, on déclenche un scénario parmi les trois proposés grâce à la fonction random. A la fin du scénario, on revient à la boucle après une tempo de 3 secondes.

"""
CircuitPython diorama Noel 2023
deux servos bonhommes de neige
19/12/2023
"""

import board
import digitalio
import pwmio
from time import sleep
from adafruit_motor import servo
import time
import random

# create a PWMOut object on Pin GP4 and GP5
pwm1 = pwmio.PWMOut(board.GP4, duty_cycle=2 ** 15, frequency=50)
pwm2 = pwmio.PWMOut(board.GP5, duty_cycle=2 ** 15, frequency=50)

# Create servo object
# initialisation servo
my1_servo = servo.Servo(pwm1)o
my2_servo = servo.Servo(pwm2)

# initialisation LED Bouton
led_button = digitalio.DigitalInOut(board.GP16)
led_button.direction = digitalio.Direction.OUTPUT

# initialisation bouton
button = digitalio.DigitalInOut(board.GP17)
button.switch_to_input(pull=digitalio.Pull.DOWN)

# LED bouton allumé
led_button.value = True
# Positionnement des servos
my2_servo.angle = 1
my1_servo.angle = 6

# Boucle principale
while True:
    if button.value:
        led_button.value = False
        choix = random.randint(0, 2)
        if choix == 0:
            j = 0
            for i in range(35):
                my1_servo.angle = 58
                sleep(0.25)
                my2_servo.angle = 1
                sleep(0.25)
                my1_servo.angle = 6
                sleep(0.25)
                my2_servo.angle = 50
                sleep(0.25)
        elif choix == 1:
            for i in range(35):
                my1_servo.angle = 58
                sleep(0.25)
                my1_servo.angle = 6
                sleep(0.25)
                my2_servo.angle = 1
                sleep(0.25)
                my2_servo.angle = 50
                sleep(0.25)
        else:
            for i in range(35):
                my1_servo.angle = 58
                my2_servo.angle = 1
                sleep(0.5)
                my1_servo.angle = 6
                my2_servo.angle = 50
                sleep(0.5)
        #temporisation de 3 secondes
        sleep(3)
    else:
        led_button.value = True
        sleep(0.2)
        led_button.value = False
        sleep(0.2)

 3b. Le Père Noël et le sapin

Continuons avec le troisième servomoteur qui actionne le Père Noël dans la cheminée et l'éclairage de l'étoile dans le sapin. On rajoute quelques connexions à notre montage

montage02

le schéma

cablage diorama noel02

Première modification du code, on rajoute le troisième servo et l'on active la fonction PWM pour la LED du sapin.

"""
CircuitPython diorama Noel 2023
deux servos bonhommes de neige
un servo pour le Père Noël
Lumière sapin de Noël
19/12/2023
"""

import board
import digitalio
import pwmio
from time import sleep
from adafruit_motor import servo
import time
import random

# create a PWMOut object on Pin GP4 and GP5
pwm1 = pwmio.PWMOut(board.GP4, duty_cycle=2 ** 15, frequency=50)
pwm2 = pwmio.PWMOut(board.GP5, duty_cycle=2 ** 15, frequency=50)
pwm3 = pwmio.PWMOut(board.GP8, duty_cycle=2 ** 15, frequency=50)

# Create servo object
# initialisation servo
my1_servo = servo.Servo(pwm1)
my2_servo = servo.Servo(pwm2)
my3_servo = servo.Servo(pwm3)

# led sapin
ledsapin = pwmio.PWMOut(board.GP6, frequency=1000, duty_cycle=0, variable_frequency=True)


# initialisation LED Bouton
led_button = digitalio.DigitalInOut(board.GP16)
led_button.direction = digitalio.Direction.OUTPUT

# initialisation bouton
button = digitalio.DigitalInOut(board.GP17)
button.switch_to_input(pull=digitalio.Pull.DOWN)

# LED bouton allumé
led_button.value = True

# Positionnement des servos
my2_servo.angle = 1
my1_servo.angle = 6
my3_servo.angle = 0

# Extinction du sapin
ledsapin.duty_cycle = 0

# Boucle principale
while True:
    if button.value:
        led_button.value = False
        choix = random.randint(0, 2)
        if choix == 0:
            j = 0
            for i in range(35):
                my3_servo.angle = 51
                ledsapin.duty_cycle = i * 1870
                my1_servo.angle = 58
                sleep(0.25)
                my2_servo.angle = 1
                sleep(0.25)
                my1_servo.angle = 6
                sleep(0.25)
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.25)
        elif choix == 1:
            for i in range(35):
                my3_servo.angle = 51
                ledsapin.duty_cycle = 65535
                my1_servo.angle = 58
                sleep(0.25)
                ledsapin.duty_cycle = 0
                my1_servo.angle = 6
                sleep(0.25)
                ledsapin.duty_cycle = 65535
                my2_servo.angle = 1
                sleep(0.25)
                ledsapin.duty_cycle = 0
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.25)
        else:
            for i in range(35):
                my3_servo.angle = 51
                duty = random.randint(0, 100)
                ledsapin.duty_cycle = int((duty/100)*65535)
                my1_servo.angle = 58
                my2_servo.angle = 1
                sleep(0.5)
                duty = random.randint(0, 100)
                ledsapin.duty_cycle = int((duty/100)*65535)
                my1_servo.angle = 6
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.5)
        ledsapin.duty_cycle = 0
        #temporisation de 3 secondes
        sleep(3)
    else:
        led_button.value = True
        sleep(0.2)
        led_button.value = False
        sleep(0.2)

3c. Le son

Nous ajoutons le module son MAX98357. C'est un petit module ampli alimenté en 5 v. Nous ajouterons un mini haut-parleur.

montage03

le schéma

cablage diorama noel03 

Nous rajouterons un fichier mp3 dans le Pi Pico comme ci-dessous

pico son

Voici la deuxième modification du code. J'ai ajouté une fonction playmp3, simple à première vue, mais qui servira surtout pour le dernier montage.

"""
CircuitPython diorama Noel 2023
deux servos bonhommes de neige
un servo pour le Père Noël
Lumière sapin de Noël
gestion du son
19/12/2023
"""

import board
import digitalio
import pwmio
from time import sleep
from adafruit_motor import servo
import time
import random
# bibliotèque son
import audiomp3
import audiobusio


# create a PWMOut object on Pin GP4 and GP5
pwm1 = pwmio.PWMOut(board.GP4, duty_cycle=2 ** 15, frequency=50)
pwm2 = pwmio.PWMOut(board.GP5, duty_cycle=2 ** 15, frequency=50)
pwm3 = pwmio.PWMOut(board.GP8, duty_cycle=2 ** 15, frequency=50)

# Create servo object
# initialisation servo
my1_servo = servo.Servo(pwm1)
my2_servo = servo.Servo(pwm2)
my3_servo = servo.Servo(pwm3)

# led sapin
ledsapin = pwmio.PWMOut(board.GP6, frequency=1000, duty_cycle=0, variable_frequency=True)


# initialisation LED Bouton
led_button = digitalio.DigitalInOut(board.GP16)
led_button.direction = digitalio.Direction.OUTPUT

# initialisation bouton
button = digitalio.DigitalInOut(board.GP17)
button.switch_to_input(pull=digitalio.Pull.DOWN)

# LED bouton allumé
led_button.value = True

# Positionnement des servos
my2_servo.angle = 1
my1_servo.angle = 6
my3_servo.angle = 0

# Extinction du sapin
ledsapin.duty_cycle = 0

#initialisation carte audio
audio = audiobusio.I2SOut(board.GP0, board.GP1, board.GP2)

def playmp3():
    name_mp3 = audiomp3.MP3Decoder(open("son.mp3", "rb"))
    audio.play(name_mp3)


# Boucle principale
while True:
    if button.value:
        led_button.value = False
        playmp3()
        choix = random.randint(0, 2)
        if choix == 0:
            j = 0
            for i in range(35):
                my3_servo.angle = 51
                ledsapin.duty_cycle = i * 1870
                my1_servo.angle = 58
                sleep(0.25)
                my2_servo.angle = 1
                sleep(0.25)
                my1_servo.angle = 6
                sleep(0.25)
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.25)
        elif choix == 1:
            for i in range(35):
                my3_servo.angle = 51
                ledsapin.duty_cycle = 65535
                my1_servo.angle = 58
                sleep(0.25)
                ledsapin.duty_cycle = 0
                my1_servo.angle = 6
                sleep(0.25)
                ledsapin.duty_cycle = 65535
                my2_servo.angle = 1
                sleep(0.25)
                ledsapin.duty_cycle = 0
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.25)
        else:
            for i in range(35):
                my3_servo.angle = 51
                duty = random.randint(0, 100)
                ledsapin.duty_cycle = int((duty/100)*65535)
                my1_servo.angle = 58
                my2_servo.angle = 1
                sleep(0.5)
                duty = random.randint(0, 100)
                ledsapin.duty_cycle = int((duty/100)*65535)
                my1_servo.angle = 6
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.5)
        ledsapin.duty_cycle = 0
        #temporisation de 3 secondes
        sleep(3)
    else:
        led_button.value = True
        sleep(0.2)
        led_button.value = False
        sleep(0.2)

3d. La banque son avec le module SD

Le Pi Pico permet de stocker des fichiers, mais le stockage devient vite insuffisant lorsque l'on veut utiliser de nombreux fichiers sons. Nous allons ajouter un module lecteur de carte SDRam comme ci-dessous.

montage04

le schéma complet

cablage diorama noel04

Et voici le code complet. On a ajouté l'initialisation du module SD ainsi que le montage du système de fichier. La fonction playmp3 s'est enrichie de 13 sons choisis aléatoirement.

"""
CircuitPython diorama Noel 2023
deux servos bonhommes de neige
un servo pour le Père Noël
Lumière sapin de Noël
gestion du son
gestion carte SD
19/12/2023
"""

import board
import digitalio
import pwmio
from time import sleep
from adafruit_motor import servo
import time
import random
# bibliothèque son
import audiomp3
import audiobusio
# bibliothèque storage
import busio
import sdcardio
import storage

# create objet sdcardio
MOSI = board.GP11
MISO = board.GP12
clk = board.GP10
cs = board.GP15

spi = busio.SPI(clk, MOSI=MOSI, MISO=MISO)

sd = sdcardio.SDCard(spi, cs)

# montage carte SD
vfs = storage.VfsFat(sd)
storage.mount(vfs, '/sd')

# create a PWMOut object on Pin GP4 and GP5
pwm1 = pwmio.PWMOut(board.GP4, duty_cycle=2 ** 15, frequency=50)
pwm2 = pwmio.PWMOut(board.GP5, duty_cycle=2 ** 15, frequency=50)
pwm3 = pwmio.PWMOut(board.GP8, duty_cycle=2 ** 15, frequency=50)

# Create servo object
# initialisation servo
my1_servo = servo.Servo(pwm1)
my2_servo = servo.Servo(pwm2)
my3_servo = servo.Servo(pwm3)

# led sapin
ledsapin = pwmio.PWMOut(board.GP6, frequency=1000, duty_cycle=0, variable_frequency=True)


# initialisation LED Bouton
led_button = digitalio.DigitalInOut(board.GP16)
led_button.direction = digitalio.Direction.OUTPUT

# initialisation bouton
button = digitalio.DigitalInOut(board.GP17)
button.switch_to_input(pull=digitalio.Pull.DOWN)

# LED bouton allumé
led_button.value = True

# Positionnement des servos
my2_servo.angle = 1
my1_servo.angle = 6
my3_servo.angle = 0

# Extinction du sapin
ledsapin.duty_cycle = 0

#initialisation carte audio
audio = audiobusio.I2SOut(board.GP0, board.GP1, board.GP2)

def playmp3():
    choix = random.randint(0, 12)
    if choix == 0:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son01.mp3", "rb"))
    elif choix == 1:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son02.mp3", "rb"))
    elif choix == 2:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son03.mp3", "rb"))
    elif choix == 3:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son04.mp3", "rb"))
    elif choix == 4:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son05.mp3", "rb"))
    elif choix == 5:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son06.mp3", "rb"))
    elif choix == 6:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son07.mp3", "rb"))
    elif choix == 7:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son08.mp3", "rb"))
    elif choix == 8:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son09.mp3", "rb"))
    elif choix == 9:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son10.mp3", "rb"))
    elif choix == 10:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son11.mp3", "rb"))
    elif choix == 11:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son12.mp3", "rb"))
    elif choix == 12:
        name_mp3 = audiomp3.MP3Decoder(open("/sd/son13.mp3", "rb"))
    audio.play(name_mp3)

# Boucle principale
while True:
    if button.value:
        led_button.value = False
        playmp3()
        choix = random.randint(0, 2)
        if choix == 0:
            j = 0
            for i in range(35):
                my3_servo.angle = 51
                ledsapin.duty_cycle = i * 1870
                my1_servo.angle = 58
                sleep(0.25)
                my2_servo.angle = 1
                sleep(0.25)
                my1_servo.angle = 6
                sleep(0.25)
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.25)
        elif choix == 1:
            for i in range(35):
                my3_servo.angle = 51
                ledsapin.duty_cycle = 65535
                my1_servo.angle = 58
                sleep(0.25)
                ledsapin.duty_cycle = 0
                my1_servo.angle = 6
                sleep(0.25)
                ledsapin.duty_cycle = 65535
                my2_servo.angle = 1
                sleep(0.25)
                ledsapin.duty_cycle = 0
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.25)
        else:
            for i in range(35):
                my3_servo.angle = 51
                duty = random.randint(0, 100)
                ledsapin.duty_cycle = int((duty/100)*65535)
                my1_servo.angle = 58
                my2_servo.angle = 1
                sleep(0.5)
                duty = random.randint(0, 100)
                ledsapin.duty_cycle = int((duty/100)*65535)
                my1_servo.angle = 6
                my2_servo.angle = 50
                my3_servo.angle = 0
                sleep(0.5)
        ledsapin.duty_cycle = 0
        #temporisation de 3 secondes
        sleep(3)
    else:
        led_button.value = True
        sleep(0.2)
        led_button.value = False
        sleep(0.2)

 Ce tuto est terminé, j'espère qu'il vous a plu.