better 3x3 doc

This commit is contained in:
bach
2026-10-08 14:36:28 +02:00
parent 3a0addaa55
commit 32e617f67b
9 changed files with 4303 additions and 0 deletions
+194
View File
@@ -0,0 +1,194 @@
#!/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))