8x32 PI
This commit is contained in:
@@ -0,0 +1,265 @@
|
||||
# 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 à 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.
|
||||
|
||||
```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 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 :
|
||||
|
||||
```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`).
|
||||
Reference in New Issue
Block a user