Files
2026-10-08 14:36:28 +02:00

195 lines
8.4 KiB
Python
Raw Permalink 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 schemas/schema_electrique.svg : schéma de la maquette 3 x 3,
avec les symboles normalisés (résistances rectangulaires) et des fils colorés.
Usage : python3 outils/schema_electrique.py schemas/schema_electrique.svg"""
import sys
ROUGE, VERT, BLEU = "#d62828", "#2a9d3a", "#2f6fc4"
TEINTE = {ROUGE: "#fbd5d5", VERT: "#d3f0d8", BLEU: "#d6e3f7"}
LIGNE, BASE, MASSE, TEXTE = "#3a3a3a", "#c98a00", "#222222", "#333333"
LX = [170, 370, 570] # x de la diode rouge de chaque colonne
LY = [330, 480, 630] # y des anodes de chaque ligne
DX = 48 # écart entre les diodes R, G, B d'une LED
COULEURS = [("R", ROUGE, "220 Ω"), ("G", VERT, "150 Ω"), ("B", BLEU, "150 Ω")]
XT = 790 # centre des transistors
XD = {0: 900, 1: 930, 2: 960} # descentes D11, D12, D13
X_GND = 1000
Y_PIN = 170 # bas du bloc Arduino
out = []
A = out.append
def ligne(x1, y1, x2, y2, c, w=2.2):
A(f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="{c}" stroke-width="{w}" '
f'stroke-linecap="round"/>')
def chemin(d, c, w=2.2):
A(f'<path d="{d}" fill="none" stroke="{c}" stroke-width="{w}" stroke-linecap="round" '
f'stroke-linejoin="round"/>')
def point(x, y, c):
A(f'<circle cx="{x}" cy="{y}" r="4" fill="{c}"/>')
def texte(x, y, s, taille=13, ancre="middle", c=TEXTE, gras=False, rot=None, italique=False):
tr = f' transform="rotate({rot} {x} {y})"' if rot else ""
A(f'<text x="{x}" y="{y}" font-size="{taille}" text-anchor="{ancre}" fill="{c}"'
f'{" font-weight=\"bold\"" if gras else ""}{" font-style=\"italic\"" if italique else ""}'
f'{tr}>{s}</text>')
def resistance_v(x, y1, y2, c, valeur):
"""Résistance verticale entre y1 et y2 (rectangle de 50 px au milieu)."""
m = (y1 + y2) / 2
ligne(x, y1, x, m - 25, c)
ligne(x, m + 25, x, y2, c)
A(f'<rect x="{x - 7}" y="{m - 25}" width="14" height="50" rx="2" fill="#fff" '
f'stroke="{c}" stroke-width="2.2"/>')
texte(x + 19, m, valeur, 12, c=c, rot=-90)
def resistance_h(x1, x2, y, c, valeur):
m = (x1 + x2) / 2
ligne(x1, y, m - 25, y, c)
ligne(m + 25, y, x2, y, c)
A(f'<rect x="{m - 25}" y="{y - 7}" width="50" height="14" rx="2" fill="#fff" '
f'stroke="{c}" stroke-width="2.2"/>')
texte(m, y - 13, valeur, 12, c=c)
def diode(x, ya, c):
"""Diode verticale : anode en haut (ya), cathode en bas (ya + 32)."""
ligne(x, ya, x, ya + 8, c)
A(f'<path d="M{x - 9} {ya + 8} L{x + 9} {ya + 8} L{x} {ya + 22} Z" fill="{TEINTE[c]}" '
f'stroke="{c}" stroke-width="2" stroke-linejoin="round"/>')
ligne(x - 9, ya + 22, x + 9, ya + 22, c, 2.4)
ligne(x, ya + 22, x, ya + 32, LIGNE)
for dy in (0, 7): # lumière émise
x1, y1, x2, y2 = x + 9, ya + 15 + dy, x + 18, ya + 6 + dy
ligne(x1, y1, x2, y2, c, 1.4)
A(f'<path d="M{x2} {y2} l-5 1 l4 4 Z" fill="{c}"/>')
def masse(x, y):
ligne(x - 11, y, x + 11, y, MASSE, 2.4)
ligne(x - 7, y + 5, x + 7, y + 5, MASSE, 2.4)
ligne(x - 3, y + 10, x + 3, y + 10, MASSE, 2.4)
def transistor(r, yt):
"""NPN dessiné en miroir : base à droite, collecteur en haut à gauche,
émetteur en bas à gauche (vers la masse)."""
xb = XT + 8
A(f'<circle cx="{XT - 1}" cy="{yt}" r="25" fill="#fafafa" stroke="{TEXTE}" stroke-width="1.6"/>')
ligne(xb, yt - 13, xb, yt + 13, TEXTE, 3)
ligne(xb, yt - 6, XT - 12, yt - 20, LIGNE) # collecteur
ligne(xb, yt + 6, XT - 12, yt + 20, MASSE) # émetteur
A(f'<path d="M{XT - 12} {yt + 20} l3 -9 l5 7 Z" fill="{MASSE}"/>')
ligne(xb, yt, XT + 40, yt, BASE) # base
texte(XT - 44, yt - 2, f"T{r}", 14, gras=True)
texte(XT - 44, yt + 14, "BC337", 11, c="#666")
texte(XT + 22, yt + 18, "B", 10, c="#888")
texte(XT - 22, yt - 26, "C", 10, c="#888")
texte(XT - 26, yt + 28, "E", 10, c="#888")
W, H = 1080, 970
A(f'<svg xmlns="http://www.w3.org/2000/svg" width="{W}" height="{H}" viewBox="0 0 {W} {H}" '
f'font-family="Helvetica, Arial, sans-serif">')
A('<title>Schéma électrique de la maquette 3 x 3</title>')
A(f'<rect width="{W}" height="{H}" fill="#ffffff"/>')
texte(40, 38, "Maquette 3 × 3 : schéma électrique", 22, "start", "#111", True)
texte(40, 60, "9 LED RGB à cathode commune, allumées ligne par ligne (multiplexage)",
14, "start", "#666")
# ---------------------------------------------------------------- Arduino
A(f'<rect x="100" y="80" width="930" height="{Y_PIN - 80}" rx="10" fill="#e8f4f5" '
f'stroke="#00878f" stroke-width="2.4"/>')
texte(565, 112, "Arduino Uno", 20, gras=True, c="#00666d")
texte(565, 132, "alimenté par le câble USB", 12, c="#4d8f94")
broches = {}
for c in range(3):
for k, (_, coul, _) in enumerate(COULEURS):
broches[f"D{2 + 3 * c + k}"] = (LX[c] + DX * k - 22, coul)
for r in range(3):
broches[f"D{11 + r}"] = (XD[r], BASE)
broches["GND"] = (X_GND, MASSE)
for nom, (x, coul) in broches.items():
ligne(x, Y_PIN, x, Y_PIN + 20, coul)
texte(x, Y_PIN - 10, nom, 12, gras=True, c=coul if coul != BASE else "#9a6a00")
masse(X_GND, Y_PIN + 20)
# ---------------------------------------------------------------- colonnes (anodes)
for c in range(3):
for k, (_, coul, val) in enumerate(COULEURS):
xb = LX[c] + DX * k - 22
resistance_v(xb, Y_PIN + 20, 265, coul, val)
y_fin = LY[2] - 12
ligne(xb, 265, xb, y_fin, coul)
for r in range(3):
xd, ys = LX[c] + DX * k, LY[r] - 12
chemin(f"M{xb} {ys} H{xd} V{LY[r]}", coul)
if r < 2:
point(xb, ys, coul)
texte(LX[c] + DX, LY[2] + 100, f"colonne {c}", 14, c="#555", gras=True)
# ---------------------------------------------------------------- LED
for r in range(3):
for c in range(3):
x0 = LX[c]
A(f'<rect x="{x0 - 14}" y="{LY[r] - 4}" width="{2 * DX + 28}" height="40" rx="8" '
f'fill="#f2f2f2"/>')
texte(x0 + DX + 2, LY[r] - 22, f"L{r}C{c}", 11, c="#888", gras=True)
for r in range(3):
for c in range(3):
for k, (_, coul, _) in enumerate(COULEURS):
diode(LX[c] + DX * k, LY[r], coul)
# ---------------------------------------------------------------- lignes (cathodes)
bus_x = sorted(LX[c] + DX * k - 22 for c in range(3) for k in range(3))
for r in range(3):
y = LY[r] + 60
for c in range(3):
for k in range(3):
xd = LX[c] + DX * k
ligne(xd, LY[r] + 32, xd, y, LIGNE)
if not (c == 0 and k == 0):
point(xd, y, LIGNE)
# ligne horizontale avec des « ponts » là où elle croise une colonne
d = f"M{LX[0]} {y}"
if r < 2:
for xb in bus_x:
if LX[0] < xb < XT - 12:
d += f" H{xb - 6} a6 6 0 0 1 12 0"
d += f" H{XT - 12} V{y + 40 - 20}"
chemin(d, LIGNE)
texte(XT - 56, y - 8, f"ligne {r}", 13, "end", c="#555", gras=True)
yt = y + 40
transistor(r, yt)
ligne(XT - 12, yt + 20, XT - 12, yt + 36, MASSE)
masse(XT - 12, yt + 36)
resistance_h(XT + 40, XD[r], yt, BASE, "1 kΩ")
ligne(XD[r], yt, XD[r], Y_PIN + 20, BASE)
# ---------------------------------------------------------------- légende
ly = 840
A(f'<rect x="40" y="{ly - 26}" width="{W - 80}" height="136" rx="10" fill="#fafafa" stroke="#e2e2e2"/>')
texte(60, ly, "Légende", 15, "start", "#111", True)
items = [
(lambda x, y: (ligne(x, y, x + 30, y, ROUGE), ligne(x + 34, y, x + 64, y, VERT),
ligne(x + 68, y, x + 98, y, BLEU)),
"colonnes : anodes R, G, B (D2 à D10)"),
(lambda x, y: ligne(x, y, x + 98, y, LIGNE), "lignes : cathodes communes"),
(lambda x, y: ligne(x, y, x + 98, y, BASE), "commande des lignes (D11 à D13)"),
(lambda x, y: masse(x + 49, y - 6), "masse (GND) : symboles tous reliés"),
(lambda x, y: point(x + 49, y, LIGNE), "point = fils connectés"),
(lambda x, y: chemin(f"M{x} {y} H{x + 43} a6 6 0 0 1 12 0 H{x + 98}", LIGNE),
"pont = croisement sans contact"),
]
for i, (dessin, legende) in enumerate(items):
col, lig = i % 3, i // 3
x, y = (60, 400, 700)[col], ly + 30 + lig * 32
dessin(x, y)
texte(x + 110, y + 4, legende, 12, "start")
texte(60, ly + 98, "Un pixel s'allume quand sa ligne est active (D11, D12 ou D13 à HIGH : le "
"transistor relie les cathodes à la masse) et que sa couleur l'est aussi (D2 à D10).",
12, "start", "#555", italique=True)
A("</svg>")
with open(sys.argv[1], "w") as f:
f.write("\n".join(out))