10 KiB
Coder ses animations en Python
Krita sert à dessiner des animations image par image. Le code sert à les calculer : du hasard, des mouvements continus, des formules, des réactions à un capteur… des choses très longues, voire impossibles, à dessiner à la main.
Ce guide s'adresse à ceux qui ont joué avec le code Arduino
(matrice_8x32.ino) et veulent continuer
sur le Raspberry Pi. Le fichier de travail est
mes_animations.py : les mêmes animations que sur
l'Arduino, traduites en Python. Ouvrez les deux côte à côte !
Sommaire
- Lancer un programme
- Python pour qui connaît l'Arduino
- Les outils de dessin
- Exercices
- Mélanger code et images
- Transformer son code en GIF
- Comment est construit le moteur
1. Lancer un programme
Pas de téléversement en Python : on lance le fichier directement.
| Où | Commande |
|---|---|
| Sur son ordinateur, avec le simulateur | python3 mes_animations.py --simulateur (Windows : py au lieu de python3) |
| Sur le Pi, sur la vraie matrice | sudo ~/vitrine-env/bin/python mes_animations.py |
Ctrl + C (ou fermer la fenêtre du simulateur) pour arrêter.
Sur le Pi, si le lecteur tourne déjà en mode vitrine, arrêtez-le d'abord :
sudo systemctl stop vitrine-pixels. Un seul programme à la fois peut parler à la matrice.
Pour éditer le fichier : sur l'ordinateur, n'importe quel éditeur de
texte (le plus confortable : Thonny, https://thonny.org, conçu pour
apprendre Python, ou VS Code). Sur le Pi : nano mes_animations.py.
2. Python pour qui connaît l'Arduino
| Arduino (C++) | Python | |
|---|---|---|
| Fin d'instruction | ; obligatoire |
rien |
| Bloc (dans une boucle, une fonction…) | entre { } |
décalé de 4 espaces après un : |
| Commentaire | // texte |
# texte |
| Variable | int x = 3; |
x = 3 |
| Fonction | void anim() { … } |
def anim(): + bloc décalé |
| Boucle « pour » | for (int x = 0; x < 32; x++) { … } |
for x in range(32): |
| Compte à rebours | for (int y = 7; y > 0; y--) |
for y in range(7, 0, -1): |
| Condition | if (x > 3) { … } else { … } |
if x > 3: … else: … |
| « et », « ou », « non » | &&, ||, ! |
and, or, not |
| Vrai / faux | true / false |
True / False (majuscule !) |
| Tableau | int t[3] = {1, 2, 3}; |
t = [1, 2, 3] (une « liste ») |
| Couleur | CRGB(255, 0, 0) |
(255, 0, 0) (un « tuple ») |
| Couleur par teinte | CHSV(160, 255, 255) |
teinte(160) |
| Hasard | random(32) |
random.randrange(32) |
| Attendre 100 ms | delay(100); |
attendre(100) |
| Afficher | FastLED.show(); |
montrer() |
| Boucle principale | void loop() { … } |
while True: + bloc décalé |
Le piège n° 1 de Python : l'indentation. Les espaces en début de ligne ne sont pas décoratifs, ils sont la structure du programme :
for x in range(32):
pixel(x, 0, ROUGE) # dans la boucle : exécuté 32 fois
montrer() # dans la boucle aussi
attendre(1000) # APRÈS la boucle : exécuté une fois
Utilisez toujours 4 espaces (Thonny et VS Code le font tout seuls avec la touche Tab). Ne mélangez jamais espaces et tabulations.
Le message d'erreur est votre ami. Python indique le fichier, la ligne et la nature de l'erreur, tout en bas :
File "mes_animations.py", line 72
attendre(20
^
SyntaxError: '(' was never closed
3. Les outils de dessin
Définis dans matrice.py, disponibles dans mes_animations.py
grâce à la ligne from matrice import *.
| Outil | Effet |
|---|---|
pixel(x, y, couleur) |
colore le pixel de la colonne x (0 à 31) et de la ligne y (0 à 7). En dehors : ignoré |
lire_pixel(x, y) |
renvoie la couleur actuelle d'un pixel |
effacer() |
éteint toute la toile |
effacer(couleur) |
remplit toute la toile d'une couleur |
assombrir(25) |
assombrit toute la toile de 25 % (pour les traînées) |
montrer() |
affiche la toile. Rien n'apparaît tant qu'on ne l'appelle pas ! |
montrer(image) |
affiche une image Pillow de 32 × 8 (voir partie 5) |
attendre(100) |
attend 100 millisecondes |
teinte(t) |
couleur de l'arc-en-ciel : 0 rouge, 32 orange, 64 jaune, 96 vert, 128 cyan, 160 bleu, 192 violet, 224 rose |
teinte(t, saturation, valeur) |
idem, avec saturation (0 = blanc) et valeur (0 = noir), de 0 à 255 |
Couleurs nommées : NOIR, BLANC, ROUGE, ORANGE, JAUNE, VERT,
CYAN, BLEU, VIOLET, MAGENTA, ROSE.
Dimensions : LARGEUR (32), HAUTEUR (8).
Le point (0, 0) est en haut à gauche, comme dans Krita.
4. Exercices
Pour chaque exercice, écrivez une nouvelle fonction def anim_…(): dans
mes_animations.py et ajoutez son nom dans playlist(). Testez dans le
simulateur.
1. Le point qui traverse. Un pixel blanc va de gauche à droite sur la
ligne 3, puis revient. (Indice : deux boucles for, la seconde avec
range(31, -1, -1).)
2. Le balayage. Une colonne entière (8 pixels) balaie la matrice de
gauche à droite. (Indice : une boucle sur x, et dedans une boucle sur y.)
3. Le dégradé fixe. Remplissez la matrice d'un arc-en-ciel immobile, de
teinte(0) à gauche à teinte(255) à droite. Puis faites-le défiler.
(Comparez avec anim_arc_en_ciel.)
4. La balle qui rebondit. Un pixel avance d'un pas en x et en y à
chaque image, et change de sens quand il touche un bord.
def anim_balle():
x, y = 0, 0 # position
dx, dy = 1, 1 # vitesse (pas par image)
for image in range(300):
effacer()
pixel(x, y, ORANGE)
montrer()
attendre(40)
x = x + dx
y = y + dy
if x <= 0 or x >= LARGEUR - 1:
dx = -dx # rebond sur un bord gauche/droite
if y <= 0 or y >= HAUTEUR - 1:
dy = -dy # rebond en haut/en bas
Variante : laissez une traînée en remplaçant effacer() par assombrir(30).
5. Le ciel étoilé. Des pixels blancs apparaissent au hasard, très
faiblement, puis s'allument et s'éteignent doucement. (Indice : assombrir
et random.randrange.)
6. Le feu. Le bas de la matrice est orange vif, des « flammes » montent
au hasard en s'assombrissant et en tirant vers le rouge. (Indice : partez
de anim_pluie, et faites monter au lieu de descendre.)
7. Le dessin en lettres. Modifiez DESSIN dans mes_animations.py pour
faire défiler votre propre motif. Créez-en un deuxième, et faites-les défiler
l'un derrière l'autre.
5. Mélanger code et images
Le code peut lire les images de l'équipe Krita et les transformer. On utilise Pillow, la bibliothèque d'images :
from PIL import Image
def anim_logo_qui_defile():
# Remplacez par le chemin d'une image de 32 × 8 exportée depuis Krita.
logo = Image.open("animations/logo.png").convert("RGB")
for i in range(100):
effacer()
# On « colle » le logo deux fois, côte à côte, décalé de i pixels :
# ce qui sort à droite rentre à gauche (défilement en boucle).
toile.paste(logo, (i % LARGEUR - LARGEUR, 0))
toile.paste(logo, (i % LARGEUR, 0))
montrer()
attendre(60)
Ici toile est l'image de 32 × 8 sur laquelle dessinent pixel() et
effacer(). Tout ce que sait faire Pillow (coller, retourner, changer les
couleurs, écrire du texte…) fonctionne dessus. Documentation :
https://pillow.readthedocs.io.
6. Transformer son code en GIF
Une animation codée peut devenir un fichier GIF, que le lecteur jouera en vitrine avec les dessins de l'équipe Krita :
python3 mes_animations.py --enregistrer animations/10_mes_animations.gif
Au lieu d'afficher, le moteur enregistre chaque image montrée par
montrer(), avec la durée de l'attendre() qui suit. La playlist est jouée
une seule fois, puis le GIF est écrit. Vérifiez-le ensuite :
python3 outils/verifier_animation.py animations/10_mes_animations.gif
Attention au hasard : un GIF enregistre une version de l'animation. Si votre animation utilise
random, elle sera identique à chaque passage dans le GIF, alors qu'en direct elle change à chaque fois.
7. Comment est construit le moteur
Pour les curieux, matrice.py est découpé comme le programme
Arduino, et commenté partie par partie :
-
Réglages : taille, broche GPIO, luminosité, limite de courant, orientation, gamma.
-
Couleurs : les noms, et
teinte()(l'équivalent deCHSV). -
XY(): la même fonction que sur l'Arduino, qui transforme une position (x, y) en numéro de LED dans le serpentin. -
Gamma et courant :
preparer_valeurs()corrige les couleurs avec une table calculée au démarrage, applique la luminosité, estime le courant et assombrit l'image si elle consomme trop (commesetMaxPowerInVoltsAndMilliampsde FastLED). -
Les écrans : trois « classes » qui savent toutes
afficher(),attendre()eteteindre():MatriceReelle: envoie les couleurs aux LED avecrpi_ws281x;Simulateur: dessine 256 ronds dans une fenêtretkinter;Enregistreur: accumule les images dans un GIF.
Le reste du programme ne sait pas lequel il utilise : c'est le principe d'une interface commune. Ajouter un 4e écran (une page web, une deuxième matrice…) ne demanderait pas de toucher aux animations.
-
Outils de dessin :
pixel(),effacer(),montrer()…, qui travaillent sur latoile.
Et lecteur.py n'est qu'une boucle : lister le dossier,
charger chaque fichier en liste de couples (image, durée), et les montrer
l'un après l'autre.
Idées pour aller plus loin
- Un bouton branché sur une broche GPIO pour passer à l'animation
suivante (bibliothèque
gpiozero, déjà installée sur Raspberry Pi OS). - Un capteur de présence (PIR) : la matrice s'anime quand quelqu'un passe devant la vitrine.
- L'heure ou la météo en texte défilant (la police 5 × 7 est dans
outils/generer_exemples.py). - Une page web sur le Pi pour choisir l'animation depuis son téléphone
(bibliothèque
flask).