- Interface web (serveur_web.py, Flask, gabarits dans web/) : dépôt de GIF, PNG animés et séquences de PNG, aperçus animés, ordre de lecture, activer / désactiver, corbeille, « jouer maintenant » et « suivante ». Service systemd vitrine-web, activé par installer.sh. - Lecteur : réagit aux demandes de la page web (post-it dans /run/vitrine-pixels), écrit l'animation en cours, éteint la matrice proprement sur SIGTERM. - Matrice posée debout : réglage ROTATION (90 = image 8 × 32) dans matrice.py ; images couchées tournées automatiquement ; exemples, animations codées, aperçus et page web adaptés au format vertical. - Compatibilité Raspbian 11 Bullseye : partition /boot, Pillow 8.1, Flask 1.1. - Doc : nouveau guide INTERFACE_WEB.md ; README, GUIDE_KRITA, MODE_VITRINE, CODER_EN_PYTHON mis à jour (format 8 × 32, adresses Wi-Fi / câble du Pi). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
269 lines
11 KiB
Markdown
269 lines
11 KiB
Markdown
# 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`](../matrice_8x32/matrice_8x32.ino)) et veulent continuer
|
||
sur le Raspberry Pi. Le fichier de travail est
|
||
[`mes_animations.py`](mes_animations.py) : **les mêmes animations que sur
|
||
l'Arduino, traduites en Python**. Ouvrez les deux côte à côte !
|
||
|
||
---
|
||
|
||
## Sommaire
|
||
|
||
1. [Lancer un programme](#1-lancer-un-programme)
|
||
2. [Python pour qui connaît l'Arduino](#2-python-pour-qui-connaît-larduino)
|
||
3. [Les outils de dessin](#3-les-outils-de-dessin)
|
||
4. [Exercices](#4-exercices)
|
||
5. [Mélanger code et images](#5-mélanger-code-et-images)
|
||
6. [Transformer son code en GIF](#6-transformer-son-code-en-gif)
|
||
7. [Comment est construit le moteur](#7-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 :
|
||
|
||
```python
|
||
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`](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 à 7) et de la ligne `y` (0 à 31), matrice debout. 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 8 × 32 (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` (8) et `HAUTEUR` (32) quand la matrice est
|
||
debout (`ROTATION = 90` dans `matrice.py`) ; 32 et 8 quand elle est couchée.
|
||
Écrivez vos animations avec `LARGEUR` et `HAUTEUR` plutôt qu'avec des
|
||
nombres : elles marcheront dans les deux sens.
|
||
|
||
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.
|
||
|
||
```python
|
||
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 :
|
||
|
||
```python
|
||
from PIL import Image
|
||
|
||
def anim_logo_qui_defile():
|
||
# Remplacez par le chemin d'une image de 8 × 32 exportée depuis Krita.
|
||
logo = Image.open("animations/logo.png").convert("RGB")
|
||
for i in range(100):
|
||
effacer()
|
||
# On « colle » le logo deux fois, l'un au-dessus de l'autre, décalé
|
||
# de i pixels : ce qui sort en bas rentre en haut (défilement en boucle).
|
||
toile.paste(logo, (0, i % HAUTEUR - HAUTEUR))
|
||
toile.paste(logo, (0, i % HAUTEUR))
|
||
montrer()
|
||
attendre(60)
|
||
```
|
||
|
||
Ici `toile` est l'image de 8 × 32 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 :
|
||
|
||
```bash
|
||
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 :
|
||
|
||
```bash
|
||
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`](matrice.py) est découpé comme le programme
|
||
Arduino, et commenté partie par partie :
|
||
|
||
1. **Réglages** : taille, broche GPIO, luminosité, limite de courant,
|
||
orientation, gamma.
|
||
2. **Couleurs** : les noms, et `teinte()` (l'équivalent de `CHSV`).
|
||
3. **`XY()`** : la même fonction que sur l'Arduino, qui transforme une
|
||
position (x, y) en numéro de LED dans le serpentin.
|
||
4. **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 (comme
|
||
`setMaxPowerInVoltsAndMilliamps` de FastLED).
|
||
5. **Les écrans** : trois « classes » qui savent toutes `afficher()`,
|
||
`attendre()` et `eteindre()` :
|
||
- `MatriceReelle` : envoie les couleurs aux LED avec `rpi_ws281x` ;
|
||
- `Simulateur` : dessine 256 ronds dans une fenêtre `tkinter` ;
|
||
- `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.
|
||
6. **Outils de dessin** : `pixel()`, `effacer()`, `montrer()`…, qui
|
||
travaillent sur la `toile`.
|
||
|
||
Et [`lecteur.py`](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`](outils/generer_exemples.py)).
|
||
- **Une page web** sur le Pi pour choisir l'animation depuis son téléphone
|
||
(bibliothèque `flask`).
|