Files
vitrine-pixels/8x32 PI/outils/schemas.py
T
2026-10-08 15:25:14 +02:00

317 lines
16 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Dessine les schémas du dossier « schemas » :
- branchement.svg : Raspberry Pi + 74AHCT125 + matrice + alimentation
- brochage_74ahct125.svg : la puce adaptatrice de niveau, patte par patte
- chaine_krita_matrice.svg : le trajet d'une animation, de Krita à la matrice
Usage : python3 outils/schemas.py"""
import os
ICI = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SORTIE = os.path.join(ICI, "schemas")
ROUGE, NOIR, BLANC_FIL, VERT = "#d62828", "#1a1a1a", "#bdbdbd", "#2a9d3a"
JAUNE_GPIO = "#e0a800"
class Svg:
def __init__(self, l, h, titre):
self.l, self.h = l, h
self.out = [f'<svg xmlns="http://www.w3.org/2000/svg" width="{l}" height="{h}" '
f'viewBox="0 0 {l} {h}" font-family="Helvetica, Arial, sans-serif">',
f' <title>{titre}</title>',
' <defs><marker id="fleche" viewBox="0 0 10 10" refX="8" refY="5" '
'markerWidth="7" markerHeight="7" orient="auto"><path d="M1 1 L9 5 L1 9 Z" '
'fill="context-stroke"/></marker>'
'<marker id="flecheg" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" '
'markerHeight="6" orient="auto"><path d="M1 1 L9 5 L1 9 Z" fill="#555"/></marker>'
'<marker id="flechec" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" '
'markerHeight="7" orient="auto"><path d="M1 1 L9 5 L1 9 Z" fill="#cfcfcf"/></marker>'
'</defs>',
f' <rect width="{l}" height="{h}" fill="#ffffff"/>']
def add(self, s):
self.out.append(" " + s)
def rect(self, x, y, w, h, fill, rx=0, stroke=None, sw=1):
st = f' stroke="{stroke}" stroke-width="{sw}"' if stroke else ""
self.add(f'<rect x="{x}" y="{y}" width="{w}" height="{h}" rx="{rx}" fill="{fill}"{st}/>')
def texte(self, x, y, s, taille=13, c="#333", ancre="start", gras=False, mono=False):
g = ' font-weight="bold"' if gras else ""
m = ' font-family="monospace"' if mono else ""
self.add(f'<text x="{x}" y="{y}" font-size="{taille}" fill="{c}" '
f'text-anchor="{ancre}"{g}{m}>{s}</text>')
def fil(self, d, c, w=5):
self.add(f'<path d="{d}" stroke="{c}" stroke-width="{w}" fill="none" '
'stroke-linecap="round" stroke-linejoin="round"/>')
def point(self, x, y, c, r=5):
self.add(f'<circle cx="{x}" cy="{y}" r="{r}" fill="{c}"/>')
def save(self, nom):
self.out.append("</svg>")
with open(os.path.join(SORTIE, nom), "w") as f:
f.write("\n".join(self.out) + "\n")
def hop_h(x_croise, sens=1, r=7):
"""Petit pont (demi-cercle) pour un fil horizontal qui en enjambe un autre.
sens = 1 : on va vers la droite ; -1 : vers la gauche."""
return (f"H{x_croise - sens * r} a{r} {r} 0 0 {1 if sens == 1 else 0} "
f"{2 * r * sens} 0")
# =============================================================================
# 1. BRANCHEMENT
# =============================================================================
def branchement():
s = Svg(1200, 940, "Branchement matrice WS2812B 8×32, Raspberry Pi, 74AHCT125 "
"et alimentation d'établi")
# ---------- matrice (vue de dos) ----------
s.texte(60, 38, "Matrice WS2812B 8 × 32 — vue de dos (côté fils)", 20, "#222", gras=True)
s.add('<pattern id="pix" x="60" y="55" width="30.625" height="30.625" '
'patternUnits="userSpaceOnUse"><rect x="9" y="9" width="12" height="12" rx="1" '
'fill="#2b2b2b"/></pattern>')
s.rect(60, 55, 980, 245, "#141414", 6)
s.rect(60, 55, 980, 245, "url(#pix)", 6)
s.add('<line x1="760" y1="150" x2="340" y2="150" stroke="#cfcfcf" stroke-width="3" '
'marker-end="url(#flechec)"/>')
s.texte(550, 135, "les données entrent par DIN et traversent les 256 LED", 15, "#e6e6e6", "middle")
for x, t in [(110, "5V"), (150, "GND"), (194, "DOUT"), (490, "5V"), (550, "GND"),
(880, "5V"), (910, "GND"), (940, "DIN")]:
s.texte(x, 268, t, 12, "#cfcfcf", "middle")
# ---------- sortie DOUT ----------
for x, c in [(110, ROUGE), (150, BLANC_FIL), (190, VERT)]:
s.fil(f"M{x} 282 V340", c)
s.rect(96, 340, 108, 24, "#222", 3)
s.texte(150, 390, "Sortie DOUT : ne rien brancher", 14, "#555", "middle")
s.texte(150, 408, "(sert à chaîner un 2e panneau)", 13, "#888", "middle")
# ---------- alimentation de la matrice (fils du milieu) ----------
s.fil("M490 282 V440 H530 V586", ROUGE, 6)
s.fil("M550 282 V420 H590 V586", NOIR, 6)
s.add('<line x1="490" y1="352" x2="506" y2="352" stroke="#777" stroke-width="2"/>')
s.add('<line x1="534" y1="352" x2="550" y2="352" stroke="#777" stroke-width="2"/>')
s.rect(506, 340, 28, 24, "#1f4e9c", 5)
s.rect(524, 340, 10, 24, "#c9d6ee")
s.texte(529, 356, "−", 13, "#1f4e9c", "middle", True)
s.texte(474, 340, "Condensateur 1000 µF", 14, "#1f4e9c", "end", True)
s.texte(474, 358, "bande « − » côté GND (fil noir)", 13, "#1f4e9c", "end")
s.texte(474, 375, "patte + côté 5V (fil rouge)", 13, "#1f4e9c", "end")
# ---------- alimentation d'établi ----------
s.rect(300, 500, 330, 210, "#e9ecef", 10, "#adb5bd", 2)
s.texte(465, 526, "Alimentation d'établi", 16, "#333", "middle", True)
s.rect(318, 540, 160, 96, "#1d2b1d", 4)
s.texte(398, 578, "5.00 V", 28, "#7dff7d", "middle", True, True)
s.texte(398, 618, "3.00 A", 20, "#ffb347", "middle", mono=True)
for x, t in [(345, "tension"), (420, "courant")]:
s.add(f'<circle cx="{x}" cy="672" r="16" fill="#666"/>')
s.texte(x, 702, t, 11, "#555", "middle")
s.add(f'<circle cx="530" cy="600" r="13" fill="{ROUGE}" stroke="#7a0f0f" stroke-width="2"/>')
s.add(f'<circle cx="590" cy="600" r="13" fill="{NOIR}" stroke="#000" stroke-width="2"/>')
s.texte(530, 637, "+", 15, ROUGE, "middle", True)
s.texte(590, 637, "−", 15, NOIR, "middle", True)
s.texte(560, 660, "bornes de", 12, "#555", "middle")
s.texte(560, 675, "sortie", 12, "#555", "middle")
# ---------- entrée DIN + fiche ----------
for x, c in [(880, ROUGE), (910, BLANC_FIL), (940, VERT)]:
s.fil(f"M{x} 282 V340", c)
s.rect(866, 340, 88, 22, "#222", 3)
s.rect(870, 364, 80, 22, "#3a3a3a", 3)
s.texte(966, 358, "connecteur DIN de la matrice", 13, "#555")
s.texte(966, 381, "+ fiche fournie (rouge / blanc / vert)", 13, "#555")
# ---------- plaque d'essai + 74AHCT125 ----------
s.rect(700, 425, 440, 190, "#f6f1e3", 8, "#d9cfb2", 2)
s.texte(1132, 608, "plaque d'essai", 12, "#a8997a", "end")
def broche_bas(n): # pattes 1 à 7 (rangée du bas), de gauche à droite
return 815 + (n - 1) * 28
def broche_haut(n): # pattes 14 à 8 (rangée du haut), de gauche à droite
return 815 + (14 - n) * 28
# fils de la fiche vers la plaque
s.fil(f"M880 386 V444 H{broche_haut(14)} V462", ROUGE) # 5V → VCC (14)
s.fil(f"M910 386 V454 {hop_h(broche_haut(14), -1)} H780 V585", BLANC_FIL) # GND → rail
s.fil(f"M940 386 V444 H1080 V470", VERT) # DIN → résistance
s.fil(f"M1080 510 V552 {hop_h(broche_bas(7), -1)} H{broche_bas(3)} V528", VERT)
# rail de masse
s.fil(f"M780 585 {hop_h(broche_bas(2), 1)} H{broche_bas(7)}", NOIR, 4)
s.fil(f"M{broche_bas(1)} 528 V585", NOIR, 4) # 1OE → GND
s.fil(f"M{broche_bas(7)} 528 V585", NOIR, 4) # GND (7)
for x in (780, broche_bas(1), broche_bas(7)):
s.point(x, 585, NOIR)
# la puce
s.rect(805, 470, 192, 50, "#222", 4)
s.add('<path d="M805 485 a10 10 0 0 1 0 20" fill="#555"/>')
s.texte(901, 500, "74AHCT125", 15, "#eee", "middle", True)
for n in range(1, 8):
s.rect(broche_bas(n) - 5, 520, 10, 8, "#b8b8b8")
s.texte(broche_bas(n), 515, str(n), 9, "#bbb", "middle")
for n in range(8, 15):
s.rect(broche_haut(n) - 5, 462, 10, 8, "#b8b8b8")
s.texte(broche_haut(n), 482, str(n), 9, "#bbb", "middle")
s.texte(broche_bas(1) - 10, 545, "1OE", 11, "#333", "end", True)
s.texte(broche_bas(2) + 6, 545, "1A", 11, JAUNE_GPIO, "start", True)
s.texte(broche_bas(3) + 6, 545, "1Y", 11, VERT, "start", True)
s.texte(broche_bas(7) + 8, 545, "GND", 11, "#333", "start", True)
# résistance 330 Ω
s.rect(1071, 470, 18, 40, "#e8d3a8", 6, "#a88a52")
for y, c in [(478, "#e67e22"), (486, "#e67e22"), (494, "#8b4513")]:
s.rect(1071, y, 18, 4, c)
s.rect(1071, 502, 18, 3, "#c9a227")
s.texte(1098, 486, "330 Ω", 13, "#7a5a1e", gras=True)
s.texte(966, 404, "fil rouge de la fiche : il alimente", 12, ROUGE, gras=True)
s.texte(966, 418, "la puce (patte 14 = VCC, 5 V)", 12, ROUGE, gras=True)
# ---------- Raspberry Pi ----------
s.rect(700, 645, 440, 230, "#1f7a3a", 12)
s.rect(750, 655, 336, 42, "#143d20", 3)
x0 = broche_bas(2) - 80 # x de la patte 2 → la patte 12 tombe sous « 1A »
for i in range(20):
for rang, y in ((0, 666), (1, 684)): # rangée du bord : pattes paires
n = 2 * i + 2 if rang == 0 else 2 * i + 1
couleur = "#d4af37"
if n in (2, 4):
couleur = ROUGE
elif n in (6, 14):
couleur = NOIR
elif n == 12:
couleur = JAUNE_GPIO
s.rect(x0 + i * 16 - 5, y - 5, 10, 10, couleur, 1)
s.texte(x0 - 9, 670, "2", 9, "#cde", "end")
s.texte(x0 - 9, 688, "1", 9, "#cde", "end")
s.texte(x0 + 19 * 16 + 9, 670, "40", 9, "#cde")
s.texte(x0 + 19 * 16 + 9, 688, "39", 9, "#cde")
# GPIO 18 (patte 12) → 1A (patte 2)
s.fil(f"M{broche_bas(2)} 528 V661", JAUNE_GPIO)
# GND (patte 6) ← rail
s.fil(f"M780 585 V630 H{x0 + 32} V661", NOIR, 4)
s.texte(920, 770, "Raspberry Pi", 24, "#fff", "middle", True)
s.texte(920, 794, "3B+, 4 ou Zero 2 W (pas le Pi 5)", 14, "#d8f0dd", "middle")
s.texte(x0 + 80, 712, "patte 12 = GPIO 18", 12, "#ffe08a", "start", True)
s.texte(x0 + 30, 712, "patte 6 = GND", 12, "#fff", "end", True)
s.add(f'<path d="M{x0 + 8} 833 L{x0 + 24} 849 M{x0 + 24} 833 L{x0 + 8} 849" '
f'stroke="#ffb3b3" stroke-width="3"/>')
s.texte(x0 + 34, 846, "pattes 2 et 4 (5 V) : NE PAS relier à la matrice", 12, "#ffd6d6")
# alimentation USB du Pi
s.rect(1140, 790, 18, 34, "#b8b8b8", 3)
s.fil("M1158 807 H1180 V900", "#555")
s.texte(1170, 918, "bloc secteur USB du Pi", 13, "#333", "end")
s.texte(1170, 935, "(5 V, 2,5 A ou plus)", 12, "#777", "end")
# ---------- légende ----------
s.rect(40, 470, 236, 300, "#f8f9fa", 8, "#dee2e6")
s.texte(56, 496, "Code couleur des fils", 15, "#222", gras=True)
for i, (c, t) in enumerate([(ROUGE, "rouge = + 5 V"), (NOIR, "noir = GND (masse)"),
(BLANC_FIL, "blanc = GND (masse)"), (VERT, "vert = données 5 V"),
(JAUNE_GPIO, "jaune = données 3,3 V")]):
y = 520 + i * 28
s.add(f'<line x1="56" y1="{y}" x2="90" y2="{y}" stroke="{c}" stroke-width="6" '
'stroke-linecap="round"/>')
s.texte(100, y + 5, t, 14)
s.texte(56, 670, "Tous les GND sont reliés :", 13, "#555")
s.texte(56, 688, "Pi ↔ puce ↔ fil blanc ↔ matrice", 13, "#555")
s.texte(56, 706, "↔ fil noir ↔ borne − de l'alim.", 13, "#555")
s.texte(56, 730, "Alim. réglée sur 5,0 V maxi !", 13, "#b00020", gras=True)
s.texte(56, 752, "Un pont = les fils se croisent", 12, "#777")
s.texte(56, 766, "sans se toucher.", 12, "#777")
s.save("branchement.svg")
# =============================================================================
# 2. BROCHAGE DU 74AHCT125
# =============================================================================
def brochage():
s = Svg(820, 470, "Brochage du 74AHCT125 (vu de dessus)")
s.texte(410, 36, "74AHCT125 vu de DESSUS (encoche à gauche)", 20, "#222", "middle", True)
s.rect(250, 150, 320, 110, "#222", 6)
s.add('<path d="M250 185 a20 20 0 0 1 0 40" fill="#555"/>')
s.add('<circle cx="275" cy="240" r="6" fill="#555"/>')
s.texte(410, 212, "74AHCT125", 24, "#eee", "middle", True)
bas = {1: ("1OE", "→ GND", "#333"), 2: ("1A", "← GPIO 18", JAUNE_GPIO),
3: ("1Y", "→ 330 Ω → DIN", VERT), 4: ("2OE", "", "#aaa"), 5: ("2A", "", "#aaa"),
6: ("2Y", "", "#aaa"), 7: ("GND", "→ GND", "#333")}
haut = {14: ("VCC", "← 5 V", ROUGE), 13: ("4OE", "", "#aaa"), 12: ("4A", "", "#aaa"),
11: ("4Y", "", "#aaa"), 10: ("3OE", "", "#aaa"), 9: ("3A", "", "#aaa"),
8: ("3Y", "", "#aaa")}
for n, (nom, role, c) in bas.items():
x = 280 + (n - 1) * 43
s.rect(x - 8, 260, 16, 26, "#b8b8b8")
s.texte(x, 252, str(n), 12, "#bbb", "middle")
s.texte(x, 306, nom, 14, c, "middle", True)
if role:
y = 338 + {1: 0, 2: 22, 3: 44, 7: 0}[n] * 1
s.add(f'<line x1="{x}" y1="312" x2="{x}" y2="{y - 13}" stroke="{c}" stroke-width="1.5"/>')
s.texte(x, y, role, 13, c, "middle", True)
for n, (nom, role, c) in haut.items():
x = 280 + (14 - n) * 43
s.rect(x - 8, 124, 16, 26, "#b8b8b8")
s.texte(x, 168, str(n), 12, "#bbb", "middle")
s.texte(x, 114, nom, 14, c, "middle", True)
if role:
s.texte(x, 92, role, 13, c, "middle", True)
s.texte(40, 445, "On n'utilise qu'une des 4 « portes » (la n° 1). Pattes en gris : non branchées "
"(on peut relier 4, 10 et 13 au 5 V pour les désactiver).", 13, "#555")
s.save("brochage_74ahct125.svg")
# =============================================================================
# 3. DE KRITA À LA MATRICE
# =============================================================================
def chaine():
s = Svg(1200, 330, "De Krita à la matrice : le trajet d'une animation")
etapes = [
("#7b3fa0", "1. Dessiner", ["Krita", "document 32 × 8 px", "pixel art, sans flou"]),
("#b5418f", "2. Exporter", ["GIF animé", "ou séquence de PNG", "(Rendu de l'animation)"]),
("#c9682a", "3. Vérifier", ["verifier_animation.py", "+ simulateur", "sur l'ordinateur"]),
("#b08900", "4. Déposer", ["dossier « animations »", "carte SD ou réseau", "(01_, 02_… = ordre)"]),
("#1f7a3a", "5. Lire", ["Raspberry Pi", "lecteur.py : gamma,", "luminosité, serpentin"]),
("#2f6fc4", "6. Afficher", ["74AHCT125 (3,3 → 5 V)", "puis 256 LED", "WS2812B"]),
]
larg, ecart = 170, 28
for i, (c, titre, lignes) in enumerate(etapes):
x = 30 + i * (larg + ecart)
s.rect(x, 60, larg, 190, "#ffffff", 12, c, 3)
s.rect(x, 60, larg, 46, c, 12)
s.rect(x, 90, larg, 16, c)
s.texte(x + larg / 2, 90, titre, 18, "#fff", "middle", True)
for j, t in enumerate(lignes):
s.texte(x + larg / 2, 140 + j * 26, t, 14 if j == 0 else 13,
"#222" if j == 0 else "#555", "middle", j == 0)
if i < len(etapes) - 1:
s.add(f'<line x1="{x + larg + 4}" y1="155" x2="{x + larg + ecart - 4}" y2="155" '
'stroke="#555" stroke-width="3" marker-end="url(#flecheg)"/>')
s.texte(30, 36, "De Krita à la matrice", 22, "#222", gras=True)
s.add('<path d="M115 270 V292 H1003 V270" stroke="#aaa" stroke-width="2" fill="none" '
'stroke-dasharray="6 5"/>')
s.texte(559, 316, "Étapes 1 à 4 : l'équipe design, sur n'importe quel ordinateur. "
"Étapes 5 et 6 : automatiques, dans la vitrine.", 14, "#555", "middle")
s.save("chaine_krita_matrice.svg")
if __name__ == "__main__":
os.makedirs(SORTIE, exist_ok=True)
branchement()
brochage()
chaine()
print("Schémas écrits dans", SORTIE)