#!/usr/bin/env python3 """Dessine les schémas du dossier « schemas » : - branchement.svg : Raspberry Pi + 74AHCT125 + matrice + alimentation - branchement_sans_puce.svg : solution A sans puce (matrice en 4,4 V) - branchement_transistor.svg : solution B sans puce (transistor inverseur) - 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'', f' {titre}', ' ' '' '' '', f' '] 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'') 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'{s}') def fil(self, d, c, w=5): self.add(f'') def point(self, x, y, c, r=5): self.add(f'') def save(self, nom): self.out.append("") 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 _matrice_et_alimentation(s, tension="5.00 V"): """Partie commune à tous les montages : matrice vue de dos, sortie DOUT, alimentation d'établi + condensateur, connecteur DIN et sa fiche.""" # ---------- matrice (vue de dos) ---------- s.texte(60, 38, "Matrice WS2812B 8 × 32 — vue de dos (côté fils)", 20, "#222", gras=True) s.add('') s.rect(60, 55, 980, 245, "#141414", 6) s.rect(60, 55, 980, 245, "url(#pix)", 6) s.add('') 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('') s.add('') 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, tension, 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'') s.texte(x, 702, t, 11, "#555", "middle") s.add(f'') s.add(f'') 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") def _resistance_v(s, x, y, couleurs, valeur, sous_titre=None): """Résistance verticale de 40 de haut, centrée en x, du haut y à y + 40.""" s.rect(x - 9, y, 18, 40, "#e8d3a8", 6, "#a88a52") for i, c in enumerate(couleurs): s.rect(x - 9, y + 8 + i * 8, 18, 4, c) s.rect(x - 9, y + 32, 18, 3, "#c9a227") s.texte(x + 18, y + 16, valeur, 13, "#7a5a1e", gras=True) if sous_titre: s.texte(x + 18, y + 33, sous_titre, 12, "#7a5a1e") def _resistance_h(s, x, y, couleurs, valeur): """Résistance horizontale de 40 de large, centrée en y, de x à x + 40.""" s.rect(x, y - 9, 40, 18, "#e8d3a8", 6, "#a88a52") for i, c in enumerate(couleurs): s.rect(x + 8 + i * 8, y - 9, 4, 18, c) s.rect(x + 32, y - 9, 3, 18, "#c9a227") s.texte(x + 20, y - 15, valeur, 13, "#7a5a1e", "middle", True) ANNEAUX_330 = ["#e67e22", "#e67e22", "#8b4513"] # orange-orange-marron ANNEAUX_1K = ["#8b4513", "#1a1a1a", ROUGE] # marron-noir-rouge def _raspberry_pi(s, x0, pas=16, y=645): """Carte Raspberry Pi avec son connecteur 40 pattes. x0 = abscisse de la patte 2 ; renvoie un dictionnaire n° de patte → x.""" largeur = 19 * pas + 104 gauche = x0 - 52 s.rect(gauche, y, largeur, 230, "#1f7a3a", 12) s.rect(x0 - 13, y + 10, 19 * pas + 26, 42, "#143d20", 3) xs = {} for i in range(20): for n, yy in ((2 * i + 2, y + 21), (2 * i + 1, y + 39)): # bord : paires xs[n] = x0 + i * pas couleur = "#d4af37" if n in (2, 4): couleur = ROUGE elif n in (6, 14): couleur = NOIR elif n == 12: couleur = JAUNE_GPIO s.rect(xs[n] - 5, yy - 5, 10, 10, couleur, 1) s.texte(x0 - 9, y + 25, "2", 9, "#cde", "end") s.texte(x0 - 9, y + 43, "1", 9, "#cde", "end") s.texte(x0 + 19 * pas + 9, y + 25, "40", 9, "#cde") s.texte(x0 + 19 * pas + 9, y + 43, "39", 9, "#cde") centre = gauche + largeur / 2 s.texte(centre, y + 125, "Raspberry Pi", 24, "#fff", "middle", True) s.texte(centre, y + 149, "3B+, 4 ou Zero 2 W (pas le Pi 5)", 14, "#d8f0dd", "middle") s.texte(xs[12] + 3, y + 67, "patte 12 = GPIO 18", 12, "#ffe08a", "start", True) s.texte(xs[6] - 2, y + 67, "patte 6 = GND", 12, "#fff", "end", True) s.add(f'') s.texte(gauche + 56, y + 201, "pattes 2 et 4 (5 V) : NE PAS relier à la matrice", 12, "#ffd6d6") # alimentation USB du Pi droite = gauche + largeur s.rect(droite, y + 145, 18, 34, "#b8b8b8", 3) s.fil(f"M{droite + 18} {y + 162} H{droite + 30} V{y + 255}", "#555") s.texte(droite + 25, y + 273, "bloc secteur USB du Pi", 13, "#333", "end") s.texte(droite + 25, y + 290, "(5 V, 2,5 A ou plus)", 12, "#777", "end") return xs def _legende(s, fils, lignes_gnd, alerte, notes=()): s.rect(40, 470, 236, 140 + 28 * len(fils) + 18 * len(lignes_gnd) + 14 * len(notes), "#f8f9fa", 8, "#dee2e6") s.texte(56, 496, "Code couleur des fils", 15, "#222", gras=True) for i, (c, t) in enumerate(fils): y = 520 + i * 28 s.add(f'') s.texte(100, y + 5, t, 14) y = 520 + len(fils) * 28 + 10 for ligne in lignes_gnd: s.texte(56, y, ligne, 13, "#555") y += 18 y += 6 s.texte(56, y, alerte, 13, "#b00020", gras=True) y += 22 for ligne in notes: s.texte(56, y, ligne, 12, "#777") y += 14 FILS_5V = [(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")] def branchement(): s = Svg(1200, 940, "Branchement matrice WS2812B 8×32, Raspberry Pi, 74AHCT125 " "et alimentation d'établi") _matrice_et_alimentation(s) # ---------- 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('') 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) _resistance_v(s, 1080, 470, ANNEAUX_330, "330 Ω") 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 ---------- pattes = _raspberry_pi(s, broche_bas(2) - 80) # la patte 12 tombe sous « 1A » s.fil(f"M{broche_bas(2)} 528 V661", JAUNE_GPIO) # GPIO 18 → 1A s.fil(f"M780 585 V630 H{pattes[6]} V661", NOIR, 4) # GND (patte 6) ← rail _legende(s, FILS_5V, ["Tous les GND sont reliés :", "Pi ↔ puce ↔ fil blanc ↔ matrice", "↔ fil noir ↔ borne − de l'alim."], "Alim. réglée sur 5,0 V maxi !", ["Un pont = les fils se croisent", "sans se toucher."]) s.save("branchement.svg") def branchement_sans_puce(): """Solution A : pas d'adaptateur, la matrice est alimentée en 4,4 V.""" s = Svg(1200, 940, "Branchement sans 74AHCT125 (solution A) : matrice en 4,4 V, " "Raspberry Pi relié directement") _matrice_et_alimentation(s, "4.40 V") pattes_x0 = 832 # le Pi doit tenir dans la largeur du dessin # fil rouge de la fiche : isolé s.fil("M880 386 V420", ROUGE) s.rect(872, 418, 16, 16, "#f2c94c", 2) s.texte(864, 431, "fil rouge : NON branché, isolé (scotch)", 13, "#b00020", "end", True) # fil vert → 330 Ω → patte 12 ; fil blanc → patte 6 s.fil("M940 386 V440 H948 V470", VERT) _resistance_v(s, 948, 470, ANNEAUX_330, "330 Ω", "(300 à 500 Ω)") pattes = _raspberry_pi(s, pattes_x0, pas=14) s.fil(f"M948 510 V620 H{pattes[12]} V661", JAUNE_GPIO) s.fil(f"M910 386 V600 H{pattes[6]} V661", BLANC_FIL) # encadré d'explication s.rect(660, 455, 230, 120, "#fff8e1", 8, "#f2c94c", 2) for i, (t, gras) in enumerate([("Pourquoi 4,4 V ?", True), ("Le « 1 » doit dépasser 70 %", False), ("de la tension des LED :", False), ("0,7 × 4,4 V ≈ 3,1 V", True), ("→ les 3,3 V du Pi suffisent.", False)]): s.texte(675, 480 + i * 20, t, 13, "#7a5a00", gras=gras) _legende(s, [(ROUGE, "rouge = + 4,4 V"), (NOIR, "noir = GND (masse)"), (BLANC_FIL, "blanc = GND (masse)"), (VERT, "vert = données"), (JAUNE_GPIO, "jaune = données 3,3 V")], ["Tous les GND sont reliés :", "Pi ↔ fil blanc ↔ matrice", "↔ fil noir ↔ borne − de l'alim."], "Alim. réglée sur 4,4 V !", ["Entre 4,2 et 4,5 V.", "Fil de données : moins de 30 cm."]) s.save("branchement_sans_puce.svg") def branchement_transistor(): """Solution B : un transistor NPN (2N3904) en inverseur, matrice en 5 V.""" s = Svg(1200, 940, "Branchement sans 74AHCT125 (solution B) : transistor 2N3904 " "en adaptateur de niveau") _matrice_et_alimentation(s) s.rect(700, 425, 440, 190, "#f6f1e3", 8, "#d9cfb2", 2) s.texte(1132, 608, "plaque d'essai", 12, "#a8997a", "end") XC = 1030 # verticale du collecteur et de l'émetteur XB = 1013 # barre de base du transistor # rouge (5 V) → résistance de tirage 1 kΩ → nœud du collecteur s.fil(f"M880 386 V440 H{XC} V455", ROUGE) _resistance_v(s, XC, 455, ANNEAUX_1K, "1 kΩ", "tirage") # vert (DIN) ← nœud du collecteur s.fil(f"M940 386 V400 H1100 V505 H{XC}", VERT) s.fil(f"M{XC} 495 V520", VERT) s.point(XC, 505, VERT) # transistor NPN s.add(f'') s.add(f'') s.fil(f"M{XB} 534 L{XC} 520", "#333", 3) s.fil(f"M{XB} 546 L{XC} 560 V585", "#333", 3) s.add(f'') s.texte(XC + 10, 524, "C", 12, "#333", gras=True) s.texte(XC + 10, 570, "E", 12, "#333", gras=True) s.texte(XB - 4, 528, "B", 12, "#333", "end", True) s.texte(XC + 26, 545, "2N3904", 13, "#333", gras=True) s.texte(XC + 26, 561, "(NPN)", 12, "#555") # base ← 1 kΩ ← GPIO 18 pattes_x0 = 843 - 80 _resistance_h(s, 930, 540, ANNEAUX_1K, "1 kΩ") s.fil(f"M970 540 H{XB}", JAUNE_GPIO, 4) s.fil(f"M843 661 V540 {hop_h(910, 1)} H930", JAUNE_GPIO) # masses : blanc → rail → émetteur et Pi s.fil(f"M910 386 V585 H{XC}", BLANC_FIL) s.point(XC, 585, NOIR) s.point(910, 585, BLANC_FIL) pattes = _raspberry_pi(s, pattes_x0) s.fil(f"M910 585 V630 {hop_h(843, -1)} H{pattes[6]} V661", NOIR, 4) s.texte(712, 448, "fil rouge (5 V) : seulement", 11, ROUGE, gras=True) s.texte(712, 461, "vers la résistance de tirage", 11, ROUGE, gras=True) _legende(s, FILS_5V, ["Tous les GND sont reliés :", "Pi ↔ émetteur ↔ fil blanc", "↔ matrice ↔ borne − de l'alim."], "Dans matrice.py :", ["INVERSER_SIGNAL = True", "(le transistor inverse le signal)", "Vérifier l'ordre E-B-C du", "transistor sur sa datasheet !"]) s.save("branchement_transistor.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('') s.add('') 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'') 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 8 × 32 px", "(vertical), 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", ["adaptateur 3,3 → 5 V", "(ou matrice en 4,4 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'') s.texte(30, 36, "De Krita à la matrice", 22, "#222", gras=True) s.add('') 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() branchement_sans_puce() branchement_transistor() brochage() chaine() print("Schémas écrits dans", SORTIE)