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
+293
View File
@@ -0,0 +1,293 @@
# Maquette 3 × 3 : matrice de LED RGB multiplexée
Workshop « Vitrine pixels » : on fabrique un petit écran de **9 pixels** de
couleur, soudé sur une plaque à pastilles et piloté par un Arduino.
C'est la maquette d'apprentissage avant la grande matrice 7 × 39.
![Implantation sur plaque à pastilles](schemas/implantation_plaque.svg)
> **Le principe à retenir** : on n'allume jamais les 9 LED en même temps.
> On allume **une ligne à la fois**, très vite (environ 333 fois par seconde),
> et l'œil voit une image fixe. C'est le **multiplexage**. Tout est expliqué
> en détail dans les commentaires de [`matrice_3x3.ino`](matrice_3x3.ino).
---
## Sommaire
1. [Le matériel](#1-le-matériel)
2. [Reconnaître les composants](#2-reconnaître-les-composants)
3. [Le schéma électrique](#3-le-schéma-électrique)
4. [Le montage sur plaque à pastilles](#4-le-montage-sur-plaque-à-pastilles)
5. [Souder, étape par étape](#5-souder-étape-par-étape)
6. [Relier à l'Arduino](#6-relier-à-larduino)
7. [Téléverser le programme et tester](#7-téléverser-le-programme-et-tester)
8. [Ça ne marche pas ?](#8-ça-ne-marche-pas-)
9. [Le fichier Fritzing](#9-le-fichier-fritzing)
---
## 1. Le matériel
| Quoi | Combien | Remarque |
|---|---|---|
| Arduino Uno + câble USB | 1 | |
| LED RGB 5 mm **à cathode commune** | 9 | 4 pattes ; vérifier « common cathode » à l'achat |
| Transistor **BC337** (NPN) | 3 | ou 2N2222 / S8050 : **attention, pattes dans un autre ordre** (voir 2) |
| Résistance **220 Ω** | 3 | pour le rouge |
| Résistance **150 Ω** | 6 | pour le vert et le bleu |
| Résistance **1 kΩ** | 3 | pour les bases des transistors |
| Plaque à pastilles (pas 2,54 mm) | 1 | au moins **32 × 34 trous** |
| Fil nu étamé (ou chutes de pattes de résistances) | ~1 m | pour les liaisons côté soudures |
| Fil isolé fin (monobrin) | ~50 cm | pour les 3 lignes de cathodes |
| Fils souples avec embout mâle (« Dupont ») | 13 | vers l'Arduino : 9 rouges/verts/bleus, 3 jaunes, 1 noir |
| Fer à souder, étain, pince coupante, pince plate | | |
---
## 2. Reconnaître les composants
### La LED RGB à cathode commune
Elle contient 3 petites LED (rouge, verte, bleue) qui partagent la même
patte « moins » : la **cathode commune**, qui est **la patte la plus longue**.
```
___
/ \ Ordre des pattes le plus courant :
| |
|_____| R K G B
| | | | │ │ │ └ bleu
| | | | │ │ └──── vert
R K | | │ └──────── cathode (la plus longue)
G B └──────────── rouge (souvent côté du méplat)
```
> ⚠️ L'ordre peut changer selon le fabricant. **Testez une LED avant de
> souder** : cathode au GND de l'Arduino, et chaque autre patte, l'une après
> l'autre, au 5V **à travers une résistance de 220 Ω** (jamais sans résistance !).
### Le transistor BC337
C'est un **interrupteur électronique** : quand un petit courant entre par la
**base (B)**, il laisse passer un gros courant entre le **collecteur (C)** et
l'**émetteur (E)**. Ici, chaque transistor allume ou éteint une ligne de LED.
Face plate vers vous, pattes vers le bas, de gauche à droite : **C – B – E**.
> ⚠️ Le **2N2222** et le **S8050** ont l'ordre inverse : **E – B – C**.
> Si vous les utilisez, tournez-les d'un demi-tour (face plate vers le haut
> de la plaque).
### Les résistances
Elles freinent le courant pour protéger les LED et l'Arduino. On lit leur
valeur avec les anneaux de couleur :
| Valeur | Anneaux | Rôle |
|---|---|---|
| 220 Ω | rouge – rouge – marron | LED rouges |
| 150 Ω | marron – vert – marron | LED vertes et bleues |
| 1 kΩ | marron – noir – rouge | bases des transistors |
Une résistance n'a pas de sens : on peut la souder dans les deux sens.
---
## 3. Le schéma électrique
![Schéma électrique](schemas/schema_electrique.svg)
Comment le lire :
- **À gauche, l'Arduino**. Ses broches **D2 à D10** envoient la couleur,
ses broches **D11 à D13** choisissent la ligne allumée.
- **Les 9 lignes verticales** : chaque broche D2 à D10 passe par une
résistance, puis rejoint **les anodes d'une même couleur dans une même
colonne** de la matrice. Par exemple, D2 alimente le rouge des 3 LED de la
colonne de gauche.
- **Les 3 lignes horizontales** relient **les cathodes d'une même ligne**
de LED, puis vont au **collecteur** d'un transistor.
- **À droite, les transistors** : leur base est commandée par D11, D12 ou D13
(à travers 1 kΩ), et leur émetteur est relié au **GND** (la masse).
Un pixel s'allume quand **sa ligne est active** (transistor passant) **et**
que **sa colonne envoie de la couleur**. C'est le croisement des deux qui
choisit le pixel.
| Broche Arduino | Rôle |
|---|---|
| D2, D3, D4 | rouge, vert, bleu de la **colonne 0** (gauche) |
| D5, D6, D7 | rouge, vert, bleu de la **colonne 1** (milieu) |
| D8, D9, D10 | rouge, vert, bleu de la **colonne 2** (droite) |
| D11, D12, D13 | **lignes** 0 (haut), 1, 2 (bas), par les transistors T0, T1, T2 |
| GND | masse : émetteurs des 3 transistors |
---
## 4. Le montage sur plaque à pastilles
Le plan en haut de cette page montre la plaque **des deux côtés** :
- **À gauche, côté composants** : ce qu'on voit quand la plaque est posée
devant soi, composants vers le haut.
- **À droite, côté soudures** : la plaque **retournée**. ⚠️ C'est une image
**en miroir** : ce qui était à gauche se retrouve à droite. Les numéros de
colonnes aident à s'y retrouver.
Les trous sont repérés par **colonne** (de 1 à 32, de gauche à droite côté
composants) et **ligne** (de 1 à 34, de haut en bas).
### L'idée du câblage
- **Les colonnes de couleur** (anodes) sont des **fils nus verticaux**, côté
soudures. Comme les 3 LED d'une colonne sont alignées, leurs pattes R
tombent dans la même colonne de trous : un fil nu droit les relie toutes,
puis rejoint la résistance.
- **Les lignes de cathodes** croisent les colonnes : on ne peut pas les faire
en fil nu du même côté (ça ferait un court-circuit !). On les fait donc en
**fil isolé, côté composants**, qui passe **par-dessus**.
- Chaque fil isolé arrive dans **le trou juste à côté** de la patte à
relier ; on fait la liaison côté soudures avec une goutte d'étain ou un
bout de fil nu.
### Où va chaque composant
| Composant | Trous (colonne, ligne) |
|---|---|
| Résistances 220 Ω (rouge) | col. 3, 9, 15 : lignes 3 → 7 |
| Résistances 150 Ω (vert) | col. 5, 11, 17 : lignes 3 → 7 |
| Résistances 150 Ω (bleu) | col. 6, 12, 18 : lignes 8 → 12 |
| LED de la ligne 0 (haut) | ligne 19 ; colonnes 3-6, 9-12, 15-18 (pattes R K G B) |
| LED de la ligne 1 | ligne 25 ; mêmes colonnes |
| LED de la ligne 2 (bas) | ligne 31 ; mêmes colonnes |
| Transistors T0, T1, T2 | lignes 20, 26, 32 ; colonnes 22 (C), 23 (B), 24 (E) |
| Résistances 1 kΩ (bases) | lignes 21, 27, 33 ; colonnes 23 → 27 |
> **Pourquoi des LED espacées de 6 trous (15 mm) ?** Pour laisser de la place
> aux fils et aux doigts. La matrice finale aura un pas de 10 mm. Pour tester
> la diffusion de la lumière à 10 mm, on peut refaire une version au pas de
> 4 trous (10,16 mm), mais le câblage est beaucoup plus serré.
---
## 5. Souder, étape par étape
**On soude des composants les plus bas aux plus hauts** : la plaque reste
stable quand on la retourne.
1. **Les fils nus** (côté soudures) : les 9 colonnes de couleur, le bus de
masse (colonne 31) et les petits ponts. Suivez le plan de droite.
2. **Les 12 résistances**, couchées à plat contre la plaque (le long des
colonnes pour les 9 résistances de couleur, le long des lignes pour les 1 kΩ).
Vérifiez les couleurs : 220 Ω pour le rouge, 150 Ω pour le vert et le bleu,
1 kΩ pour les bases.
3. **Les 3 transistors**, face plate vers le bas de la plaque.
Ne chauffez pas plus de 3 secondes par patte.
4. **Les 9 LED** : patte la plus longue (K) en 2e position.
**Testez chaque LED avant** (voir partie 2).
5. **Les 3 fils isolés** des cathodes (côté composants).
6. **Les 13 fils vers l'Arduino** (voir partie 6).
Conseils de soudure :
- Le fer chauffe **la pastille et la patte en même temps**, puis on apporte
l'étain. Une bonne soudure est brillante et en forme de petit volcan.
- Après chaque étape, **vérifiez qu'aucune goutte d'étain ne relie deux
pastilles voisines** par erreur, surtout entre les colonnes de couleur
voisines (G et B ne sont qu'à un trou d'écart !).
- Coupez les pattes qui dépassent **après** avoir soudé. Gardez les chutes :
elles font d'excellents fils nus.
---
## 6. Relier à l'Arduino
| Fil | Trou sur la plaque (col., ligne) | Broche Arduino |
|---|---|---|
| 🔴 rouge colonne 0 | 3, 2 | D2 |
| 🟢 vert colonne 0 | 5, 2 | D3 |
| 🔵 bleu colonne 0 | 6, 2 | D4 |
| 🔴 rouge colonne 1 | 9, 2 | D5 |
| 🟢 vert colonne 1 | 11, 2 | D6 |
| 🔵 bleu colonne 1 | 12, 2 | D7 |
| 🔴 rouge colonne 2 | 15, 2 | D8 |
| 🟢 vert colonne 2 | 17, 2 | D9 |
| 🔵 bleu colonne 2 | 18, 2 | D10 |
| 🟡 ligne 0 | 28, 21 | D11 |
| 🟡 ligne 1 | 29, 27 | D12 |
| 🟡 ligne 2 | 30, 33 | D13 |
| ⚫ masse | 31, 18 | GND (à côté de D13) |
![Vue Fritzing de la plaque reliée à l'Arduino](schemas/plaque_fritzing.png)
> Pas besoin d'alimentation externe : 9 LED à 15 mA, une seule ligne à la fois,
> c'est au maximum ~135 mA. Le port USB suffit.
---
## 7. Téléverser le programme et tester
1. Installez l'**IDE Arduino** et la bibliothèque **TimerOne**
(Outils → Gérer les bibliothèques… → « TimerOne » → Installer).
2. Ouvrez [`matrice_3x3.ino`](matrice_3x3.ino).
3. Outils → Type de carte → **Arduino Uno** ; Outils → Port → le bon port.
4. **Téléverser**.
La première animation, `animTestPixels`, allume **chaque pixel l'un après
l'autre**, en rouge, puis en vert, puis en bleu, de gauche à droite et de haut
en bas. C'est le test de câblage : notez tout pixel qui ne s'allume pas, ou
pas au bon endroit, ou pas dans la bonne couleur.
Ensuite, les animations s'enchaînent : aplats de couleur, chenille, damier,
balayages, scintillement. Pour créer les vôtres, lisez les parties 5 et 6 du
programme.
---
## 8. Ça ne marche pas ?
| Symptôme | Cause probable | Solution |
|---|---|---|
| **Rien ne s'allume** | Fil de masse (GND) absent | Vérifier le fil noir et le bus de masse (col. 31) |
| | Transistors à l'envers | Vérifier C-B-E (BC337) ou E-B-C (2N2222) |
| **Une ligne entière reste éteinte** | Transistor mal soudé ou à l'envers | Vérifier T0, T1 ou T2 et sa résistance de base |
| | Fil isolé de cathode mal soudé | Vérifier le pont entre la patte K et le fil |
| **Une couleur manque sur toute une colonne** | Résistance ou fil nu de colonne mal soudé | Suivre la colonne côté soudures |
| | Mauvais fil sur l'Arduino | Comparer avec le tableau de la partie 6 |
| **Un seul pixel ne marche pas** | LED mal soudée, ou grillée | Ressouder, ou tester la LED seule |
| **Couleurs mélangées** (rouge à la place du bleu…) | Ordre des pattes de la LED différent | Tester la LED (partie 2) ; corriger dans le code (`pinsCouleur`) |
| **Deux couleurs s'allument ensemble** | Pont d'étain entre deux colonnes voisines | Chauffer et retirer l'étain en trop (tresse à dessouder) |
| **Légers reflets sur des pixels éteints** (« fantômes ») | Normal si très faible | Le code éteint déjà les lignes avant de changer les couleurs |
| **L'image clignote** | `DUREE_LIGNE_US` trop grand | Revenir à 1000 dans le code |
| **La petite LED « L » de l'Arduino scintille** | Normal : elle est sur la broche 13 (ligne 2) | Rien à faire |
---
## 9. Le fichier Fritzing
[`matrice_3x3.fzz`](matrice_3x3.fzz) s'ouvre avec
[Fritzing](https://fritzing.org) (version 1.0 ou plus récente). Il contient :
- la vue **Schéma** : le même circuit que la partie 3, avec les symboles
de Fritzing ([aperçu](schemas/schema_fritzing.png)) ;
- la vue **Platine d'essai** : la plaque à pastilles reliée à l'Arduino.
Les fils gris sont les liaisons en fil nu (côté soudures), les fils noirs
sur la plaque sont les fils isolés des cathodes.
La vue **Circuit imprimé** n'est pas utilisée (pièces non placées).
Les scripts du dossier [`outils/`](outils/) régénèrent le fichier Fritzing,
le plan d'implantation et le schéma électrique si on modifie le montage :
```bash
python3 outils/gen_fzz.py matrice_3x3.fzz
```
```bash
python3 outils/render_plaque.py schemas/implantation_plaque.svg
```
```bash
python3 outils/schema_electrique.py schemas/schema_electrique.svg
```
Binary file not shown.
+489
View File
@@ -0,0 +1,489 @@
#!/usr/bin/env python3
"""Génère matrice_3x3.fzz : maquette 3x3 sur plaque à pastilles (vue platine)
+ schéma électrique (vue schéma). Coordonnées en px Fritzing (90 dpi)."""
import math, sys, zipfile, os
from xml.sax.saxutils import escape
PARTS = "/usr/share/fritzing/fritzing-parts/core/"
P = 9.0 # pas 0,1 pouce
# ---------------------------------------------------------------- modèle
instances = [] # dict: id, module, path, title, props, views{view:{...}}
idx = [1000]
def nid():
idx[0] += 1
return idx[0]
conns = {} # (inst_id, view, connector) -> list of (other_id, other_connector, other_layer)
def link(view, a, ca, la, b, cb, lb):
conns.setdefault((a, view, ca), []).append((b, cb, lb))
conns.setdefault((b, view, cb), []).append((a, ca, la))
# ---------------------------------------------------------------- géométries des pièces
LED = dict(module="d4d5af9700923b8a114f57961f29a8a0ColorLEDModuleID",
path=PARTS + "led-rgb-4pin-cathode_v5.fzp",
legs={"connector0": (1.35, 40.6875), "connector1": (10.35, 40.6875),
"connector2": (19.35, 40.6875), "connector3": (28.35, 40.6875)},
size=(0.33 * 90, 0.4521 * 90))
NPN = dict(module="2244EBEC10e", path=PARTS + "transistor_signal_NPN_TO92_CBE.fzp",
# connector2 = C (gauche), connector1 = B, connector0 = E (droite)
legs={"connector2": (1.35, 30.101), "connector1": (10.326, 30.101),
"connector0": (19.309, 30.101)},
size=(0.22954 * 90, 0.3344583 * 90))
RES = dict(module="ResistorModuleID", path=PARTS + "resistor.fzp",
legs={"connector0": (2.619, 4.5405), "connector1": (36.0063, 4.5405)},
size=(0.42917 * 90, 0.0971 * 90))
ARDUINO = dict(module="arduino_Uno_Rev3(fix)", path=PARTS + "arduino_Uno_Rev3(fix).fzp",
size=(2.94961 * 90, 2.1 * 90))
ARD_PIN = { # broche -> (connector id, x, y) dans le repère de la carte (non tournée)
"D2": ("connector63", 229.47, 9.0), "D3": ("connector64", 220.46, 9.0),
"D4": ("connector65", 211.46, 9.0), "D5": ("connector66", 202.46, 9.0),
"D6": ("connector67", 193.46, 9.0), "D7": ("connector68", 184.47, 9.0),
"D8": ("connector51", 170.06, 9.0), "D9": ("connector52", 161.06, 9.0),
"D10": ("connector53", 152.06, 9.0), "D11": ("connector54", 143.06, 9.0),
"D12": ("connector55", 134.06, 9.0), "D13": ("connector56", 125.06, 9.0),
"GND": ("connector57", 116.06, 9.0),
}
def rot_matrix(deg, w, h):
"""Rotation autour du centre (w/2, h/2), au format QTransform de Fritzing."""
cx, cy = w / 2, h / 2
a = math.radians(deg)
c, s = round(math.cos(a), 9), round(math.sin(a), 9)
m11, m12, m21, m22 = c, s, -s, c
m31 = cx - (m11 * cx + m21 * cy)
m32 = cy - (m12 * cx + m22 * cy)
return (m11, m12, m21, m22, m31, m32)
def apply(m, x, y):
m11, m12, m21, m22, m31, m32 = m
return (m11 * x + m21 * y + m31, m12 * x + m22 * y + m32)
def inv_apply(m, u, v):
m11, m12, m21, m22, m31, m32 = m
u, v = u - m31, v - m32
det = m11 * m22 - m12 * m21
return ((m22 * u - m21 * v) / det, (-m12 * u + m11 * v) / det)
# ---------------------------------------------------------------- vue platine (plaque à pastilles)
COLS, ROWS = 32, 34
BOARD = dict(id=nid(), module=f"{COLS}.{ROWS}PerfboardModuleID",
path=":/resources/parts/core/perfboard.fzp", title="Plaque à pastilles",
props={"size": f"{COLS}.{ROWS}"}, views={})
BOARD["views"]["breadboardView"] = dict(layer="breadboardbreadboard", x=0, y=0, z=1.5)
instances.append(BOARD)
def hole(c, r):
return (9 + P * c, 9 + P * r)
def hole_id(c, r):
return f"connector{r * 1000 + c}"
def add_part(spec, title, bb_pos, bb_rot=0, props=None, sch=None, legs_to=None):
"""legs_to : {connector: (col, row)} trous de la plaque où arrivent les pattes."""
inst = dict(id=nid(), module=spec["module"], path=spec["path"], title=title,
props=props or {}, views={}, legs={})
w, h = spec["size"]
m = rot_matrix(bb_rot, w, h) if bb_rot else None
inst["views"]["breadboardView"] = dict(layer="breadboard", x=bb_pos[0], y=bb_pos[1],
z=2.5, m=m)
if legs_to:
for con, (c, r) in legs_to.items():
sx, sy = spec["legs"][con]
hx, hy = hole(c, r)
u, v = hx - bb_pos[0], hy - bb_pos[1]
lx, ly = inv_apply(m, u, v) if m else (u, v)
inst["legs"][con] = ((sx, sy), (lx - sx, ly - sy))
link("breadboardView", inst["id"], con, "breadboard", BOARD["id"],
hole_id(c, r), "breadboardbreadboard")
inst["sch"] = sch
inst["holes"] = legs_to or {}
instances.append(inst)
return inst
def place_on_holes(spec, title, holes, rot=0, lift=1.0, props=None):
"""Place la pièce pour que ses pattes soient au-dessus des trous, puis plie les
pattes vers les trous. lift = longueur de patte visible, en pas de 0,1 po."""
cons = list(holes)
# centre des trous visés, centre des départs de pattes
hx = sum(hole(*holes[c])[0] for c in cons) / len(cons)
hy = sum(hole(*holes[c])[1] for c in cons) / len(cons)
sx = sum(spec["legs"][c][0] for c in cons) / len(cons)
sy = sum(spec["legs"][c][1] for c in cons) / len(cons)
w, h = spec["size"]
m = rot_matrix(rot, w, h) if rot else None
tx, ty = apply(m, sx, sy) if m else (sx, sy)
if rot == 0:
pos = (hx - tx, hy - ty - lift * P)
else:
pos = (hx - tx, hy - ty)
return add_part(spec, title, pos, rot, props, legs_to=holes)
wires = []
board_wires = [] # (trou a, trou b, couleur) pour le plan d'implantation
def bb_wire(a, b, color, title=None):
"""Fil entre deux trous de la plaque (a, b = (col, row))."""
(x1, y1), (x2, y2) = hole(*a), hole(*b)
board_wires.append((a, b, color))
w = dict(id=nid(), title=title or f"Fil{len(wires) + 1}", view="breadboardView",
x=x1, y=y1, dx=x2 - x1, dy=y2 - y1, color=color, flags=64,
layer="breadboardWire", z=(1.8 if color == NU else 3.5))
for k, (c, r) in enumerate((a, b)):
link("breadboardView", w["id"], f"connector{k}", "breadboardWire",
BOARD["id"], hole_id(c, r), "breadboardbreadboard")
wires.append(w)
return w
ARD_POS = (40.0, -280.0)
ARD_M = rot_matrix(180, *ARDUINO["size"])
ARD = dict(id=nid(), module=ARDUINO["module"], path=ARDUINO["path"], title="Arduino Uno",
props={}, views={}, legs={})
ARD["views"]["breadboardView"] = dict(layer="breadboardbreadboard", x=ARD_POS[0],
y=ARD_POS[1], z=1.6, m=ARD_M)
instances.append(ARD)
def ard_pin_xy(name):
_, px, py = ARD_PIN[name]
u, v = apply(ARD_M, px, py)
return (ARD_POS[0] + u, ARD_POS[1] + v)
def ard_wire(pin, hole_cr, color):
x1, y1 = ard_pin_xy(pin)
x2, y2 = hole(*hole_cr)
w = dict(id=nid(), title=f"Fil {pin}", view="breadboardView", x=x1, y=y1,
dx=x2 - x1, dy=y2 - y1, color=color, flags=64, layer="breadboardWire")
link("breadboardView", w["id"], "connector0", "breadboardWire", ARD["id"],
ARD_PIN[pin][0], "breadboardbreadboard")
link("breadboardView", w["id"], "connector1", "breadboardWire", BOARD["id"],
hole_id(*hole_cr), "breadboardbreadboard")
wires.append(w)
# couleurs de fils Fritzing
NU = "#a8a8a8" # fil nu étamé, côté soudure
ROUGE, VERT, BLEU = "#cc1414", "#47cc79", "#418dd9"
NOIR, JAUNE, ORANGE = "#404040", "#ffe24d", "#ff7033"
# --- implantation -------------------------------------------------------------
PAS = 6 # pas entre LED, en trous (6 × 2,54 = 15,24 mm)
X0, Y_LED = 2, (18, 24, 30) # LED (ligne r, colonne c) : pattes R K G B
COUL = {"R": 0, "G": 2, "B": 3} # décalage de la patte dans la LED
PIN_ANODE = {(c, k): f"D{2 + 3 * c + i}" for c in range(3) for i, k in enumerate("RGB")}
RES_VAL = {"R": "220Ω", "G": "150Ω", "B": "150Ω"}
COUL_FIL = {"R": ROUGE, "G": VERT, "B": BLEU}
ard_jobs = [] # (broche, trou, couleur) routés à la fin
leds = {}
for r in range(3):
for c in range(3):
x = X0 + PAS * c
leds[(r, c)] = place_on_holes(
LED, f"LED L{r}C{c}",
{"connector0": (x, Y_LED[r]), "connector1": (x + 1, Y_LED[r]),
"connector2": (x + 2, Y_LED[r]), "connector3": (x + 3, Y_LED[r])},
lift=0.6)
res_anode = {}
for c in range(3):
for k, off in COUL.items():
col = X0 + PAS * c + off
top, bot = (2, 6) if k in "RG" else (7, 11)
res_anode[(c, k)] = place_on_holes(
RES, f"R {k}{c}", {"connector0": (col, top), "connector1": (col, bot)},
rot=90, props={"resistance": RES_VAL[k]})
bb_wire((col, 1), (col, top), NU)
ard_jobs.append((PIN_ANODE[(c, k)], (col, 1), COUL_FIL[k]))
bb_wire((col, bot), (col, Y_LED[0]), NU)
bb_wire((col, Y_LED[0]), (col, Y_LED[1]), NU)
bb_wire((col, Y_LED[1]), (col, Y_LED[2]), NU)
XC, XB, XE = 21, 22, 23 # pattes C, B, E
X_GND = 30
trans, res_base = {}, {}
for r in range(3):
y = Y_LED[r] + 1
for c in range(3):
xk = X0 + PAS * c + 1
bb_wire((xk, Y_LED[r]), (xk, y), NU)
bb_wire((X0 + 1, y), (X0 + 1 + PAS, y), NOIR)
bb_wire((X0 + 1 + PAS, y), (X0 + 1 + 2 * PAS, y), NOIR)
bb_wire((X0 + 1 + 2 * PAS, y), (XC - 1, y), NOIR)
bb_wire((XC - 1, y), (XC, y), NU)
trans[r] = place_on_holes(NPN, f"T{r} (BC337)",
{"connector2": (XC, y), "connector1": (XB, y),
"connector0": (XE, y)}, lift=0.6)
res_base[r] = place_on_holes(RES, f"Rb{r}",
{"connector0": (XB, y + 1), "connector1": (XB + 4, y + 1)},
lift=0.0, props={"resistance": "1kΩ"})
bb_wire((XB, y), (XB, y + 1), NU)
xw = XB + 5 + r
bb_wire((XB + 4, y + 1), (xw, y + 1), NU)
ard_jobs.append((f"D{11 + r}", (xw, y + 1), JAUNE))
bb_wire((XE, y), (X_GND, y), NU)
yg = Y_LED[0] - 1
bb_wire((X_GND, yg), (X_GND, Y_LED[0] + 1), NU)
bb_wire((X_GND, Y_LED[0] + 1), (X_GND, Y_LED[1] + 1), NU)
bb_wire((X_GND, Y_LED[1] + 1), (X_GND, Y_LED[2] + 1), NU)
ard_jobs.append(("GND", (X_GND, yg), NOIR))
# routage des fils Arduino : descente, palier horizontal, descente (fils coudés)
def chain(points, color, pin, hole_cr):
ids = []
for i in range(len(points) - 1):
(x1, y1), (x2, y2) = points[i], points[i + 1]
w = dict(id=nid(), title=f"Fil {pin}", view="breadboardView", x=x1, y=y1,
dx=x2 - x1, dy=y2 - y1, color=color, flags=64, layer="breadboardWire")
wires.append(w)
ids.append(w["id"])
link("breadboardView", ids[0], "connector0", "breadboardWire", ARD["id"],
ARD_PIN[pin][0], "breadboardbreadboard")
link("breadboardView", ids[-1], "connector1", "breadboardWire", BOARD["id"],
hole_id(*hole_cr), "breadboardbreadboard")
for a_, b_ in zip(ids, ids[1:]):
link("breadboardView", a_, "connector1", "breadboardWire", b_, "connector0",
"breadboardWire")
header_y = ard_pin_xy("D2")[1]
jobs = [(pin, h, col, ard_pin_xy(pin)[0], hole(*h)[0]) for pin, h, col in ard_jobs]
droite = sorted([j for j in jobs if j[4] > j[3] + 0.5], key=lambda j: j[3])
gauche = sorted([j for j in jobs if j[4] < j[3] - 0.5], key=lambda j: -j[3])
niveau = {}
for groupe in (droite, gauche):
n = len(groupe)
for i, j in enumerate(groupe): # le plus à l'extérieur descend le plus bas
niveau[j[0]] = n - i
for pin, h, col, xp, xh in jobs:
yp = header_y
if pin in niveau:
yl = header_y + 18 + 9 * niveau[pin]
chain([(xp, yp), (xp, yl), (xh, yl), hole(*h)], col, pin, h)
else:
chain([(xp, yp), hole(*h)], col, pin, h)
# ---------------------------------------------------------------- vue schéma
K = 90 / 96 # px Inkscape -> px Fritzing (SVG en pouces)
SCH = { # terminaux dans le repère du symbole (px Fritzing)
"LED": {"connector0": (5.126, 35.457), "connector2": (23.172, 35.457),
"connector3": (41.297, 35.457), "connector1": (23.225, 1.5)},
"NPN": {"connector1": (0.4375, 18.4375), "connector2": (18.4375, 0.4375),
"connector0": (18.4375, 36.4375)},
"RES": {"connector0": (0.4375, 3.87), "connector1": (36.4375, 3.87)},
"RES_SIZE": (0.409722 * 90, 0.086 * 90),
}
def ard_sch(name):
con = ARD_PIN[name][0]
if name == "GND":
return (72.0, 207.0)
n = {"D2": 0, "D3": 1, "D4": 2, "D5": 3, "D6": 4, "D7": 5, "D8": 6, "D9": 7,
"D10": 8, "D11": 9, "D12": 10, "D13": 11}[name]
return (135.0, 54.0 + 9 * n)
def set_sch(inst, pos, rot=0, size=None):
m = rot_matrix(rot, *size) if rot else None
inst["views"]["schematicView"] = dict(layer="schematic", x=pos[0], y=pos[1], z=2.5, m=m)
inst["sch_pos"], inst["sch_m"] = pos, m
def place_sch(inst, table, con, target, rot=0, size=None):
"""Place le symbole pour que le terminal `con` tombe sur `target`."""
m = rot_matrix(rot, *size) if rot else None
lx, ly = SCH[table][con]
if m:
lx, ly = apply(m, lx, ly)
set_sch(inst, (target[0] - lx, target[1] - ly), rot, size)
def term(inst, table, con):
lx, ly = SCH[table][con]
if inst.get("sch_m"):
lx, ly = apply(inst["sch_m"], lx, ly)
return (inst["sch_pos"][0] + lx, inst["sch_pos"][1] + ly)
ends = {} # point arrondi -> [(wire_id, connector)]
def sch_poly(points, start=None, end=None):
ids = []
for (x1, y1), (x2, y2) in zip(points, points[1:]):
w = dict(id=nid(), title="Fil", view="schematicView", x=x1, y=y1, dx=x2 - x1,
dy=y2 - y1, color="#404040", flags=128, layer="schematicTrace",
mils="9.7222", z=5.5)
wires.append(w)
ids.append(w["id"])
for a_, b_ in zip(ids, ids[1:]):
link("schematicView", a_, "connector1", "schematicTrace", b_, "connector0",
"schematicTrace")
if start:
link("schematicView", ids[0], "connector0", "schematicTrace", start[0]["id"],
start[1], "schematic")
else:
ends.setdefault((round(points[0][0], 2), round(points[0][1], 2)), []).append(
(ids[0], "connector0"))
if end:
link("schematicView", ids[-1], "connector1", "schematicTrace", end[0]["id"],
end[1], "schematic")
else:
ends.setdefault((round(points[-1][0], 2), round(points[-1][1], 2)), []).append(
(ids[-1], "connector1"))
A_POS = (0.0, 450.0)
ARD["views"]["schematicView"] = dict(layer="schematic", x=A_POS[0], y=A_POS[1], z=2.5)
def apin(name):
x, y = ard_sch(name)
return (A_POS[0] + x, A_POS[1] + y)
ARDP = lambda name: (ARD, ARD_PIN[name][0])
MX, MY, PASS = 225.0, 60.0, 90.0
BUS_OFF = {"R": -27.0, "G": -18.0, "B": -9.0}
PROF = {"R": 9.0, "G": 18.0, "B": 27.0}
LEDCON = {"R": "connector0", "G": "connector2", "B": "connector3"}
RES_TOP = {"R": 315.0, "G": 360.0, "B": 405.0}
for (r, c), led in leds.items():
set_sch(led, (MX + PASS * c, MY + PASS * r))
for c in range(3):
for k in "RGB":
bx = MX + PASS * c + BUS_OFF[k]
res = res_anode[(c, k)]
# patte 1 (connector0) côté Arduino, en bas ; patte 2 côté LED, en haut
place_sch(res, "RES", "connector1", (bx, RES_TOP[k]), rot=270, size=SCH["RES_SIZE"])
top, bot = term(res, "RES", "connector1"), term(res, "RES", "connector0")
pin = PIN_ANODE[(c, k)]
px, py = apin(pin)
sch_poly([(px, py), (bx, py), bot], start=ARDP(pin), end=(res, "connector0"))
# bus : résistance -> jonctions des lignes 2, 1, 0
pts = [top] + [(bx, MY + PASS * r + 35.457 + PROF[k]) for r in (2, 1, 0)]
for i, (a_, b_) in enumerate(zip(pts, pts[1:])):
sch_poly([a_, b_], start=(res, "connector1") if i == 0 else None)
for r in range(3):
led = leds[(r, c)]
tx, ty = term(led, "LED", LEDCON[k])
jy = MY + PASS * r + 35.457 + PROF[k]
sch_poly([(tx, ty), (tx, jy), (bx, jy)], start=(led, LEDCON[k]))
XT = 545.0
XV = {0: 462.0, 1: 471.0, 2: 480.0}
X_GND_S, Y_GND_S = XT + 45.0, 690.0
for r in range(3):
yrl = MY + PASS * r + 1.5 - 9.0
ks = [term(leds[(r, c)], "LED", "connector1") for c in range(3)]
for c in range(3):
sch_poly([ks[c], (ks[c][0], yrl)], start=(leds[(r, c)], "connector1"))
t = trans[r]
set_sch(t, (XT, yrl + 18.0 - 0.4375))
cpt, bpt, ept = term(t, "NPN", "connector2"), term(t, "NPN", "connector1"), term(t, "NPN", "connector0")
sch_poly([(ks[0][0], yrl), (ks[1][0], yrl)])
sch_poly([(ks[1][0], yrl), (ks[2][0], yrl)])
sch_poly([(ks[2][0], yrl), (cpt[0], yrl), cpt], end=(t, "connector2"))
rb = res_base[r]
# patte 1 (connector0) côté base, patte 2 côté Arduino
place_sch(rb, "RES", "connector0", (bpt[0] - 9.0, bpt[1]), rot=180, size=SCH["RES_SIZE"])
rbase, rard = term(rb, "RES", "connector0"), term(rb, "RES", "connector1")
sch_poly([rbase, bpt], start=(rb, "connector0"), end=(t, "connector1"))
pin = f"D{11 + r}"
px, py = apin(pin)
sch_poly([(px, py), (XV[r], py), (XV[r], rard[1]), rard], start=ARDP(pin), end=(rb, "connector1"))
sch_poly([ept, (X_GND_S, ept[1])], start=(t, "connector0"))
yE = ept[1]
if r == 0:
y_e0 = yE
else:
sch_poly([(X_GND_S, prev_e), (X_GND_S, yE)])
prev_e = yE
gx, gy = apin("GND")
sch_poly([(X_GND_S, prev_e), (X_GND_S, Y_GND_S), (gx, Y_GND_S), (gx, gy)], end=ARDP("GND"))
for pt, lst in ends.items():
for i in range(len(lst)):
for j in range(i + 1, len(lst)):
link("schematicView", lst[i][0], lst[i][1], "schematicTrace", lst[j][0],
lst[j][1], "schematicTrace")
# ---------------------------------------------------------------- écriture XML
def fmt(v):
return f"{v:.4f}".rstrip("0").rstrip(".") if isinstance(v, float) else str(v)
def connects_xml(inst_id, view, con, indent):
out = []
for (oid, ocon, olayer) in conns.get((inst_id, view, con), []):
out.append(f'{indent}<connect connectorId="{ocon}" modelIndex="{oid}" layer="{olayer}"/>')
return "\n".join(out)
def part_xml(inst):
L = []
L.append(f'<instance moduleIdRef="{escape(inst["module"])}" modelIndex="{inst["id"]}" '
f'path="{escape(inst["path"])}">')
for k, v in inst["props"].items():
L.append(f' <property name="{k}" value="{escape(v)}"/>')
L.append(f' <title>{escape(inst["title"])}</title>')
L.append(' <views>')
for view, g in inst["views"].items():
L.append(f' <{view} layer="{g["layer"]}">')
if g.get("m"):
m11, m12, m21, m22, m31, m32 = g["m"]
L.append(f' <geometry z="{g["z"]}" x="{fmt(g["x"])}" y="{fmt(g["y"])}">')
L.append(f' <transform m11="{fmt(m11)}" m12="{fmt(m12)}" m13="0" '
f'm21="{fmt(m21)}" m22="{fmt(m22)}" m23="0" m31="{fmt(m31)}" '
f'm32="{fmt(m32)}" m33="1"/>')
L.append(' </geometry>')
else:
L.append(f' <geometry z="{g["z"]}" x="{fmt(g["x"])}" y="{fmt(g["y"])}"/>')
cons = sorted({c for (i, v, c) in conns if i == inst["id"] and v == view}
| (set(inst.get("legs", {})) if view == "breadboardView" else set()))
if cons:
L.append(' <connectors>')
for con in cons:
L.append(f' <connector connectorId="{con}" layer="{g["layer"]}">')
if view == "breadboardView" and con in inst.get("legs", {}):
(sx, sy), (lx, ly) = inst["legs"][con]
L.append(f' <geometry x="{fmt(sx)}" y="{fmt(sy)}"/>')
L.append(' <leg><point x="0" y="0"/><bezier/>'
f'<point x="{fmt(lx)}" y="{fmt(ly)}"/><bezier/></leg>')
else:
L.append(' <geometry x="0" y="0"/>')
L.append(' <connects>')
L.append(connects_xml(inst["id"], view, con, " "))
L.append(' </connects>')
L.append(' </connector>')
L.append(' </connectors>')
L.append(f' </{view}>')
L.append(' </views>')
L.append('</instance>')
return "\n".join(L)
def wire_xml(w):
view, layer = w["view"], w["layer"]
L = [f'<instance moduleIdRef="WireModuleID" modelIndex="{w["id"]}" '
f'path=":/resources/parts/core/wire.fzp">',
f' <title>{escape(w["title"])}</title>', ' <views>',
f' <{view} layer="{layer}">',
f' <geometry z="{w.get("z", 3.5)}" x="{fmt(w["x"])}" y="{fmt(w["y"])}" x1="0" y1="0" '
f'x2="{fmt(w["dx"])}" y2="{fmt(w["dy"])}" wireFlags="{w["flags"]}"/>',
f' <wireExtras mils="{w.get("mils", "22.2222")}" color="{w["color"]}" '
f'opacity="1" banded="0"/>',
' <connectors>']
for k in ("connector0", "connector1"):
L.append(f' <connector connectorId="{k}" layer="{layer}">')
L.append(' <geometry x="0" y="0"/>')
L.append(' <connects>')
L.append(connects_xml(w["id"], view, k, " "))
L.append(' </connects>')
L.append(' </connector>')
L += [' </connectors>', f' </{view}>', ' </views>', '</instance>']
return "\n".join(L)
def build(out_path, ino_path=None):
head = '''<?xml version="1.0" encoding="UTF-8"?>
<module fritzingVersion="1.0.5" icon=".png">
<views>
<view name="breadboardView" backgroundColor="#ffffff" gridSize="0.1in" showGrid="1" alignToGrid="1" viewFromBelow="0" colorWiresByLength="0"/>
<view name="schematicView" backgroundColor="#ffffff" gridSize="0.1in" showGrid="1" alignToGrid="1" viewFromBelow="0"/>
<view name="pcbView" backgroundColor="#333333" gridSize="0.05in" showGrid="1" alignToGrid="1" viewFromBelow="0"/>
</views>
<instances>
'''
body = "\n".join(part_xml(i) for i in instances) + "\n" + "\n".join(wire_xml(w) for w in wires)
xml = head + body + "\n</instances>\n</module>\n"
name = os.path.splitext(os.path.basename(out_path))[0]
with zipfile.ZipFile(out_path, "w", zipfile.ZIP_DEFLATED) as z:
z.writestr(name + ".fz", xml)
if ino_path:
z.write(ino_path, os.path.basename(ino_path))
if __name__ == "__main__" and sys.argv[1] != "/dev/null":
build(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None)
print(len(instances), "pièces,", len(wires), "fils")
+200
View File
@@ -0,0 +1,200 @@
#!/usr/bin/env python3
"""Plan d'implantation vu de dessus : côté composants + côté soudures (miroir)."""
import runpy, sys
OUT = sys.argv[1]
sys.argv = ["x", "/dev/null"]
g = runpy.run_path(sys.path[0] + "/gen_fzz.py", run_name="gen")
COLS, ROWS = g["COLS"], g["ROWS"]
NU = g["NU"]
leds, res_anode, res_base, trans = g["leds"], g["res_anode"], g["res_base"], g["trans"]
board_wires, ard_jobs = g["board_wires"], g["ard_jobs"]
PX = 16 # pas d'affichage
MARGE_X, MARGE_Y = 44, 120
PANNEAU = COLS * PX + 2 * MARGE_X
LARG = 2 * PANNEAU + 40
HAUT = MARGE_Y + ROWS * PX + 270
out = []
A = out.append
def xy(c, r, panneau):
if panneau == 1: # côté soudures : plaque retournée gauche/droite
c = COLS - 1 - c
return (panneau * (PANNEAU + 40) + MARGE_X + c * PX + PX / 2, MARGE_Y + r * PX + PX / 2)
def txt(x, y, s, size=11, anchor="middle", fill="#333", weight="normal", rot=None):
tr = f' transform="rotate({rot} {x:.1f} {y:.1f})"' if rot else ""
A(f'<text x="{x:.1f}" y="{y:.1f}" font-size="{size}" text-anchor="{anchor}" '
f'fill="{fill}" font-weight="{weight}"{tr}>{s}</text>')
A(f'<svg xmlns="http://www.w3.org/2000/svg" width="{LARG}" height="{HAUT}" '
f'viewBox="0 0 {LARG} {HAUT}" font-family="Helvetica, Arial, sans-serif">')
A('<title>Implantation de la matrice 3x3 sur plaque à pastilles</title>')
A(f'<rect width="{LARG}" height="{HAUT}" fill="#ffffff"/>')
for pan, titre, sous in ((0, "Côté composants (vu de dessus)",
"on pose les composants et les fils isolés"),
(1, "Côté soudures (plaque retournée)",
"on soude et on relie avec du fil nu. Attention : image en miroir !")):
x0 = pan * (PANNEAU + 40) + MARGE_X
txt(x0, 34, titre, 18, "start", "#222", "bold")
txt(x0, 54, sous, 13, "start", "#666")
# plaque
A(f'<rect x="{x0 - 8}" y="{MARGE_Y - 8}" width="{COLS * PX + 16}" height="{ROWS * PX + 16}" '
f'rx="6" fill="#e3c58f" stroke="#b8975c"/>')
# numéros de colonnes et de lignes (comptés à partir de 1)
for c in range(COLS):
x, _ = xy(c, 0, pan)
if (c + 1) % 5 == 0 or c == 0:
txt(x, MARGE_Y + ROWS * PX + 22, str(c + 1), 10, fill="#8a6d3b")
for r in range(ROWS):
_, y = xy(0, r, pan)
if (r + 1) % 5 == 0 or r == 0:
txt(x0 - 14, y + 4, str(r + 1), 10, fill="#8a6d3b")
# pastilles
for c in range(COLS):
for r in range(ROWS):
x, y = xy(c, r, pan)
A(f'<circle cx="{x:.1f}" cy="{y:.1f}" r="4.6" fill="#c9a063"/>'
f'<circle cx="{x:.1f}" cy="{y:.1f}" r="1.8" fill="#fff8ec"/>')
# ---------------------------------------------------------------- côté composants
def contour_led(inst, pan, plein):
hs = list(inst["holes"].values())
xs = [xy(c, r, pan)[0] for c, r in hs]
cx, cy = sum(xs) / 4, xy(*hs[0], pan)[1]
if plein:
A(f'<circle cx="{cx:.1f}" cy="{cy:.1f}" r="{PX * 1.0:.1f}" fill="#ffffff" '
f'fill-opacity="0.85" stroke="#555" stroke-width="1.5"/>')
for (c, r), lettre, coul in zip(hs, "RKGB", ("#cc1414", "#222", "#2a9d3a", "#2f6fc4")):
x, y = xy(c, r, pan)
A(f'<circle cx="{x:.1f}" cy="{y:.1f}" r="2.6" fill="{coul}"/>')
txt(x, y - 6, lettre, 9, fill=coul, weight="bold")
else:
A(f'<circle cx="{cx:.1f}" cy="{cy:.1f}" r="{PX * 1.0:.1f}" fill="none" '
f'stroke="#9a7b4a" stroke-dasharray="3 3"/>')
def contour_res(inst, pan, plein, valeur):
(c1, r1), (c2, r2) = inst["holes"].values()
(xa, ya), (xb, yb) = xy(c1, r1, pan), xy(c2, r2, pan)
if plein:
A(f'<line x1="{xa:.1f}" y1="{ya:.1f}" x2="{xb:.1f}" y2="{yb:.1f}" stroke="#8c8c8c" '
f'stroke-width="2"/>')
vertical = abs(xa - xb) < 1
L = 0.55 * (abs(ya - yb) if vertical else abs(xa - xb))
mx, my = (xa + xb) / 2, (ya + yb) / 2
w, h = (9, L) if vertical else (L, 9)
style = ('fill="#e8d3a8" stroke="#a88a52"' if plein
else 'fill="none" stroke="#9a7b4a" stroke-dasharray="3 3"')
A(f'<rect x="{mx - w / 2:.1f}" y="{my - h / 2:.1f}" width="{w:.1f}" height="{h:.1f}" '
f'rx="3" {style}/>')
if plein:
txt(mx + (0 if vertical else 0), my + (3 if not vertical else 3), valeur, 8,
fill="#5a4310", weight="bold", rot=(-90 if vertical else None))
def contour_npn(inst, pan, plein, nom):
hs = inst["holes"]
xc, y = xy(*hs["connector2"], pan)
xe, _ = xy(*hs["connector0"], pan)
cx = (xc + xe) / 2
R = PX * 1.25
# demi-cercle, face plate vers le bas de la plaque
d = f'M{cx - R:.1f} {y + 5:.1f} A{R:.1f} {R:.1f} 0 0 1 {cx + R:.1f} {y + 5:.1f} Z'
if plein:
A(f'<path d="{d}" fill="#2b2b2b" fill-opacity="0.9"/>')
for con, lettre in (("connector2", "C"), ("connector1", "B"), ("connector0", "E")):
x, yy = xy(*hs[con], pan)
A(f'<circle cx="{x:.1f}" cy="{yy:.1f}" r="2.6" fill="#ddd"/>')
txt(x, yy - 6, lettre, 9, fill="#fff", weight="bold")
txt(cx, y - R + 2, nom, 10, fill="#222", weight="bold")
else:
A(f'<path d="{d}" fill="none" stroke="#9a7b4a" stroke-dasharray="3 3"/>')
def composants(pan, plein):
for k, inst in res_anode.items():
contour_res(inst, pan, plein, inst["props"]["resistance"].replace("Ω", ""))
for r, inst in res_base.items():
contour_res(inst, pan, plein, "1k")
for inst in leds.values():
contour_led(inst, pan, plein)
for r, inst in trans.items():
contour_npn(inst, pan, plein, f"T{r}")
# fils isolés (côté composants)
for a, b, coul in board_wires:
if coul == NU:
continue
(xa, ya), (xb, yb) = xy(*a, 0), xy(*b, 0)
A(f'<line x1="{xa:.1f}" y1="{ya:.1f}" x2="{xb:.1f}" y2="{yb:.1f}" stroke="{coul}" '
f'stroke-width="5" stroke-linecap="round"/>')
composants(0, True)
# arrivées des fils de l'Arduino
for pin, (c, r), coul in ard_jobs:
x, y = xy(c, r, 0)
A(f'<circle cx="{x:.1f}" cy="{y:.1f}" r="5.5" fill="none" stroke="{coul}" stroke-width="3"/>')
if r <= 2: # entrées en haut de la plaque : étiquette verticale au-dessus
A(f'<line x1="{x:.1f}" y1="{y - 6:.1f}" x2="{x:.1f}" y2="{MARGE_Y - 26:.1f}" '
f'stroke="{coul}" stroke-width="2"/>')
txt(x + 4, MARGE_Y - 30, pin, 11, "start", coul if coul != "#ffe24d" else "#b39b00",
"bold", rot=-90)
else:
txt(x + 9, y + 4, pin, 11, "start", "#222", "bold")
# ---------------------------------------------------------------- côté soudures
composants(1, False)
for a, b, coul in board_wires:
(xa, ya), (xb, yb) = xy(*a, 1), xy(*b, 1)
if coul == NU:
A(f'<line x1="{xa:.1f}" y1="{ya:.1f}" x2="{xb:.1f}" y2="{yb:.1f}" stroke="#7d7d7d" '
f'stroke-width="4" stroke-linecap="round"/>')
soudures = set()
for inst in list(leds.values()) + list(res_anode.values()) + list(res_base.values()) + list(trans.values()):
soudures.update(inst["holes"].values())
for a, b, coul in board_wires:
soudures.update((a, b))
for _, h, _ in ard_jobs:
soudures.add(h)
for c, r in soudures:
x, y = xy(c, r, 1)
A(f'<circle cx="{x:.1f}" cy="{y:.1f}" r="4.4" fill="#bfbfbf" stroke="#6f6f6f"/>')
for a, b, coul in board_wires: # bouts des fils isolés qui traversent
if coul != NU:
for h in (a, b):
x, y = xy(*h, 1)
A(f'<circle cx="{x:.1f}" cy="{y:.1f}" r="2.2" fill="{coul}"/>')
for pin, h, coul in ard_jobs:
x, y = xy(*h, 1)
A(f'<circle cx="{x:.1f}" cy="{y:.1f}" r="2.2" fill="{coul}"/>')
# ---------------------------------------------------------------- légende
ly = MARGE_Y + ROWS * PX + 56
txt(MARGE_X, ly, "Légende", 15, "start", "#222", "bold")
items = [
('<circle cx="{x}" cy="{y}" r="9" fill="#fff" stroke="#555" stroke-width="1.5"/>',
"LED RGB vue de dessus : pattes R, K (cathode, la plus longue), G, B"),
('<rect x="{xm}" y="{ym}" width="22" height="9" rx="3" fill="#e8d3a8" stroke="#a88a52"/>',
"Résistance (valeur en ohms : 220, 150, 1k = 1000)"),
('<path d="M{xl} {y4} A11 11 0 0 1 {xr} {y4} Z" fill="#2b2b2b"/>',
"Transistor BC337, face plate vers le bas : pattes C, B, E de gauche à droite"),
('<line x1="{xl}" y1="{y}" x2="{xr}" y2="{y}" stroke="#404040" stroke-width="5" stroke-linecap="round"/>',
"Fil isolé, côté composants (cathodes des lignes)"),
('<line x1="{xl}" y1="{y}" x2="{xr}" y2="{y}" stroke="#7d7d7d" stroke-width="4" stroke-linecap="round"/>',
"Fil nu (ou patte repliée), côté soudures"),
('<circle cx="{x}" cy="{y}" r="5.5" fill="none" stroke="#cc1414" stroke-width="3"/>',
"Arrivée d'un fil vers l'Arduino (D2 à D13, GND)"),
]
for i, (forme, texte) in enumerate(items):
col, lig = i % 2, i // 2
bx = MARGE_X + col * (LARG / 2)
by = ly + 30 + lig * 30
A(forme.format(x=bx + 11, y=by - 4, xm=bx, ym=by - 8, xl=bx, xr=bx + 22, y4=by + 2))
txt(bx + 34, by, texte, 12, "start", "#333")
txt(MARGE_X, ly + 140, "Pas entre LED : 6 trous = 15,24 mm. Les numéros de colonnes et de "
"lignes sont ceux du côté composants ; côté soudures, gauche et droite sont inversées.",
12, "start", "#666")
txt(MARGE_X, ly + 160, "Correspondance avec le code : colonne c de la matrice = LED Lr Cc ; "
"ligne r = transistor Tr (broche D11 + r).", 12, "start", "#666")
A("</svg>")
with open(OUT, "w") as f:
f.write("\n".join(out))
+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))
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 KiB

+501
View File
@@ -0,0 +1,501 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1080" height="970" viewBox="0 0 1080 970" font-family="Helvetica, Arial, sans-serif">
<title>Schéma électrique de la maquette 3 x 3</title>
<rect width="1080" height="970" fill="#ffffff"/>
<text x="40" y="38" font-size="22" text-anchor="start" fill="#111" font-weight="bold">Maquette 3 × 3 : schéma électrique</text>
<text x="40" y="60" font-size="14" text-anchor="start" fill="#666">9 LED RGB à cathode commune, allumées ligne par ligne (multiplexage)</text>
<rect x="100" y="80" width="930" height="90" rx="10" fill="#e8f4f5" stroke="#00878f" stroke-width="2.4"/>
<text x="565" y="112" font-size="20" text-anchor="middle" fill="#00666d" font-weight="bold">Arduino Uno</text>
<text x="565" y="132" font-size="12" text-anchor="middle" fill="#4d8f94">alimenté par le câble USB</text>
<line x1="148" y1="170" x2="148" y2="190" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<text x="148" y="160" font-size="12" text-anchor="middle" fill="#d62828" font-weight="bold">D2</text>
<line x1="196" y1="170" x2="196" y2="190" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<text x="196" y="160" font-size="12" text-anchor="middle" fill="#2a9d3a" font-weight="bold">D3</text>
<line x1="244" y1="170" x2="244" y2="190" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<text x="244" y="160" font-size="12" text-anchor="middle" fill="#2f6fc4" font-weight="bold">D4</text>
<line x1="348" y1="170" x2="348" y2="190" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<text x="348" y="160" font-size="12" text-anchor="middle" fill="#d62828" font-weight="bold">D5</text>
<line x1="396" y1="170" x2="396" y2="190" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<text x="396" y="160" font-size="12" text-anchor="middle" fill="#2a9d3a" font-weight="bold">D6</text>
<line x1="444" y1="170" x2="444" y2="190" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<text x="444" y="160" font-size="12" text-anchor="middle" fill="#2f6fc4" font-weight="bold">D7</text>
<line x1="548" y1="170" x2="548" y2="190" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<text x="548" y="160" font-size="12" text-anchor="middle" fill="#d62828" font-weight="bold">D8</text>
<line x1="596" y1="170" x2="596" y2="190" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<text x="596" y="160" font-size="12" text-anchor="middle" fill="#2a9d3a" font-weight="bold">D9</text>
<line x1="644" y1="170" x2="644" y2="190" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<text x="644" y="160" font-size="12" text-anchor="middle" fill="#2f6fc4" font-weight="bold">D10</text>
<line x1="900" y1="170" x2="900" y2="190" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<text x="900" y="160" font-size="12" text-anchor="middle" fill="#9a6a00" font-weight="bold">D11</text>
<line x1="930" y1="170" x2="930" y2="190" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<text x="930" y="160" font-size="12" text-anchor="middle" fill="#9a6a00" font-weight="bold">D12</text>
<line x1="960" y1="170" x2="960" y2="190" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<text x="960" y="160" font-size="12" text-anchor="middle" fill="#9a6a00" font-weight="bold">D13</text>
<line x1="1000" y1="170" x2="1000" y2="190" stroke="#222222" stroke-width="2.2" stroke-linecap="round"/>
<text x="1000" y="160" font-size="12" text-anchor="middle" fill="#222222" font-weight="bold">GND</text>
<line x1="989" y1="190" x2="1011" y2="190" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="993" y1="195" x2="1007" y2="195" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="997" y1="200" x2="1003" y2="200" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="148" y1="190" x2="148" y2="202.5" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<line x1="148" y1="252.5" x2="148" y2="265" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<rect x="141" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#d62828" stroke-width="2.2"/>
<text x="167" y="227.5" font-size="12" text-anchor="middle" fill="#d62828" transform="rotate(-90 167 227.5)">220 Ω</text>
<line x1="148" y1="265" x2="148" y2="618" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M148 318 H170 V330" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="148" cy="318" r="4" fill="#d62828"/>
<path d="M148 468 H170 V480" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="148" cy="468" r="4" fill="#d62828"/>
<path d="M148 618 H170 V630" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="196" y1="190" x2="196" y2="202.5" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="196" y1="252.5" x2="196" y2="265" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<rect x="189" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#2a9d3a" stroke-width="2.2"/>
<text x="215" y="227.5" font-size="12" text-anchor="middle" fill="#2a9d3a" transform="rotate(-90 215 227.5)">150 Ω</text>
<line x1="196" y1="265" x2="196" y2="618" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M196 318 H218 V330" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="196" cy="318" r="4" fill="#2a9d3a"/>
<path d="M196 468 H218 V480" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="196" cy="468" r="4" fill="#2a9d3a"/>
<path d="M196 618 H218 V630" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="244" y1="190" x2="244" y2="202.5" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<line x1="244" y1="252.5" x2="244" y2="265" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<rect x="237" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#2f6fc4" stroke-width="2.2"/>
<text x="263" y="227.5" font-size="12" text-anchor="middle" fill="#2f6fc4" transform="rotate(-90 263 227.5)">150 Ω</text>
<line x1="244" y1="265" x2="244" y2="618" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M244 318 H266 V330" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="244" cy="318" r="4" fill="#2f6fc4"/>
<path d="M244 468 H266 V480" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="244" cy="468" r="4" fill="#2f6fc4"/>
<path d="M244 618 H266 V630" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<text x="218" y="730" font-size="14" text-anchor="middle" fill="#555" font-weight="bold">colonne 0</text>
<line x1="348" y1="190" x2="348" y2="202.5" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<line x1="348" y1="252.5" x2="348" y2="265" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<rect x="341" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#d62828" stroke-width="2.2"/>
<text x="367" y="227.5" font-size="12" text-anchor="middle" fill="#d62828" transform="rotate(-90 367 227.5)">220 Ω</text>
<line x1="348" y1="265" x2="348" y2="618" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M348 318 H370 V330" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="348" cy="318" r="4" fill="#d62828"/>
<path d="M348 468 H370 V480" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="348" cy="468" r="4" fill="#d62828"/>
<path d="M348 618 H370 V630" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="396" y1="190" x2="396" y2="202.5" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="396" y1="252.5" x2="396" y2="265" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<rect x="389" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#2a9d3a" stroke-width="2.2"/>
<text x="415" y="227.5" font-size="12" text-anchor="middle" fill="#2a9d3a" transform="rotate(-90 415 227.5)">150 Ω</text>
<line x1="396" y1="265" x2="396" y2="618" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M396 318 H418 V330" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="396" cy="318" r="4" fill="#2a9d3a"/>
<path d="M396 468 H418 V480" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="396" cy="468" r="4" fill="#2a9d3a"/>
<path d="M396 618 H418 V630" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="444" y1="190" x2="444" y2="202.5" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<line x1="444" y1="252.5" x2="444" y2="265" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<rect x="437" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#2f6fc4" stroke-width="2.2"/>
<text x="463" y="227.5" font-size="12" text-anchor="middle" fill="#2f6fc4" transform="rotate(-90 463 227.5)">150 Ω</text>
<line x1="444" y1="265" x2="444" y2="618" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M444 318 H466 V330" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="444" cy="318" r="4" fill="#2f6fc4"/>
<path d="M444 468 H466 V480" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="444" cy="468" r="4" fill="#2f6fc4"/>
<path d="M444 618 H466 V630" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<text x="418" y="730" font-size="14" text-anchor="middle" fill="#555" font-weight="bold">colonne 1</text>
<line x1="548" y1="190" x2="548" y2="202.5" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<line x1="548" y1="252.5" x2="548" y2="265" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<rect x="541" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#d62828" stroke-width="2.2"/>
<text x="567" y="227.5" font-size="12" text-anchor="middle" fill="#d62828" transform="rotate(-90 567 227.5)">220 Ω</text>
<line x1="548" y1="265" x2="548" y2="618" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M548 318 H570 V330" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="548" cy="318" r="4" fill="#d62828"/>
<path d="M548 468 H570 V480" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="548" cy="468" r="4" fill="#d62828"/>
<path d="M548 618 H570 V630" fill="none" stroke="#d62828" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="596" y1="190" x2="596" y2="202.5" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="596" y1="252.5" x2="596" y2="265" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<rect x="589" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#2a9d3a" stroke-width="2.2"/>
<text x="615" y="227.5" font-size="12" text-anchor="middle" fill="#2a9d3a" transform="rotate(-90 615 227.5)">150 Ω</text>
<line x1="596" y1="265" x2="596" y2="618" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M596 318 H618 V330" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="596" cy="318" r="4" fill="#2a9d3a"/>
<path d="M596 468 H618 V480" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="596" cy="468" r="4" fill="#2a9d3a"/>
<path d="M596 618 H618 V630" fill="none" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="644" y1="190" x2="644" y2="202.5" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<line x1="644" y1="252.5" x2="644" y2="265" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<rect x="637" y="202.5" width="14" height="50" rx="2" fill="#fff" stroke="#2f6fc4" stroke-width="2.2"/>
<text x="663" y="227.5" font-size="12" text-anchor="middle" fill="#2f6fc4" transform="rotate(-90 663 227.5)">150 Ω</text>
<line x1="644" y1="265" x2="644" y2="618" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M644 318 H666 V330" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="644" cy="318" r="4" fill="#2f6fc4"/>
<path d="M644 468 H666 V480" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="644" cy="468" r="4" fill="#2f6fc4"/>
<path d="M644 618 H666 V630" fill="none" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<text x="618" y="730" font-size="14" text-anchor="middle" fill="#555" font-weight="bold">colonne 2</text>
<rect x="156" y="326" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="220" y="308" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L0C0</text>
<rect x="356" y="326" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="420" y="308" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L0C1</text>
<rect x="556" y="326" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="620" y="308" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L0C2</text>
<rect x="156" y="476" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="220" y="458" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L1C0</text>
<rect x="356" y="476" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="420" y="458" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L1C1</text>
<rect x="556" y="476" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="620" y="458" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L1C2</text>
<rect x="156" y="626" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="220" y="608" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L2C0</text>
<rect x="356" y="626" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="420" y="608" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L2C1</text>
<rect x="556" y="626" width="124" height="40" rx="8" fill="#f2f2f2"/>
<text x="620" y="608" font-size="11" text-anchor="middle" fill="#888" font-weight="bold">L2C2</text>
<line x1="170" y1="330" x2="170" y2="338" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M161 338 L179 338 L170 352 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="161" y1="352" x2="179" y2="352" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="170" y1="352" x2="170" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="179" y1="345" x2="188" y2="336" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M188 336 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="179" y1="352" x2="188" y2="343" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M188 343 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="218" y1="330" x2="218" y2="338" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M209 338 L227 338 L218 352 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="209" y1="352" x2="227" y2="352" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="218" y1="352" x2="218" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="227" y1="345" x2="236" y2="336" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M236 336 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="227" y1="352" x2="236" y2="343" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M236 343 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="266" y1="330" x2="266" y2="338" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M257 338 L275 338 L266 352 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="257" y1="352" x2="275" y2="352" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="266" y1="352" x2="266" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="275" y1="345" x2="284" y2="336" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M284 336 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="275" y1="352" x2="284" y2="343" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M284 343 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="370" y1="330" x2="370" y2="338" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M361 338 L379 338 L370 352 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="361" y1="352" x2="379" y2="352" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="370" y1="352" x2="370" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="379" y1="345" x2="388" y2="336" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M388 336 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="379" y1="352" x2="388" y2="343" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M388 343 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="418" y1="330" x2="418" y2="338" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M409 338 L427 338 L418 352 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="409" y1="352" x2="427" y2="352" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="418" y1="352" x2="418" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="427" y1="345" x2="436" y2="336" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M436 336 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="427" y1="352" x2="436" y2="343" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M436 343 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="466" y1="330" x2="466" y2="338" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M457 338 L475 338 L466 352 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="457" y1="352" x2="475" y2="352" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="466" y1="352" x2="466" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="475" y1="345" x2="484" y2="336" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M484 336 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="475" y1="352" x2="484" y2="343" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M484 343 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="570" y1="330" x2="570" y2="338" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M561 338 L579 338 L570 352 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="561" y1="352" x2="579" y2="352" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="570" y1="352" x2="570" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="579" y1="345" x2="588" y2="336" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M588 336 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="579" y1="352" x2="588" y2="343" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M588 343 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="618" y1="330" x2="618" y2="338" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M609 338 L627 338 L618 352 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="609" y1="352" x2="627" y2="352" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="618" y1="352" x2="618" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="627" y1="345" x2="636" y2="336" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M636 336 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="627" y1="352" x2="636" y2="343" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M636 343 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="666" y1="330" x2="666" y2="338" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M657 338 L675 338 L666 352 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="657" y1="352" x2="675" y2="352" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="666" y1="352" x2="666" y2="362" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="675" y1="345" x2="684" y2="336" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M684 336 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="675" y1="352" x2="684" y2="343" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M684 343 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="170" y1="480" x2="170" y2="488" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M161 488 L179 488 L170 502 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="161" y1="502" x2="179" y2="502" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="170" y1="502" x2="170" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="179" y1="495" x2="188" y2="486" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M188 486 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="179" y1="502" x2="188" y2="493" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M188 493 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="218" y1="480" x2="218" y2="488" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M209 488 L227 488 L218 502 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="209" y1="502" x2="227" y2="502" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="218" y1="502" x2="218" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="227" y1="495" x2="236" y2="486" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M236 486 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="227" y1="502" x2="236" y2="493" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M236 493 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="266" y1="480" x2="266" y2="488" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M257 488 L275 488 L266 502 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="257" y1="502" x2="275" y2="502" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="266" y1="502" x2="266" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="275" y1="495" x2="284" y2="486" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M284 486 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="275" y1="502" x2="284" y2="493" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M284 493 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="370" y1="480" x2="370" y2="488" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M361 488 L379 488 L370 502 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="361" y1="502" x2="379" y2="502" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="370" y1="502" x2="370" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="379" y1="495" x2="388" y2="486" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M388 486 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="379" y1="502" x2="388" y2="493" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M388 493 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="418" y1="480" x2="418" y2="488" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M409 488 L427 488 L418 502 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="409" y1="502" x2="427" y2="502" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="418" y1="502" x2="418" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="427" y1="495" x2="436" y2="486" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M436 486 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="427" y1="502" x2="436" y2="493" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M436 493 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="466" y1="480" x2="466" y2="488" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M457 488 L475 488 L466 502 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="457" y1="502" x2="475" y2="502" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="466" y1="502" x2="466" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="475" y1="495" x2="484" y2="486" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M484 486 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="475" y1="502" x2="484" y2="493" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M484 493 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="570" y1="480" x2="570" y2="488" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M561 488 L579 488 L570 502 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="561" y1="502" x2="579" y2="502" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="570" y1="502" x2="570" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="579" y1="495" x2="588" y2="486" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M588 486 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="579" y1="502" x2="588" y2="493" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M588 493 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="618" y1="480" x2="618" y2="488" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M609 488 L627 488 L618 502 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="609" y1="502" x2="627" y2="502" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="618" y1="502" x2="618" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="627" y1="495" x2="636" y2="486" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M636 486 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="627" y1="502" x2="636" y2="493" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M636 493 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="666" y1="480" x2="666" y2="488" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M657 488 L675 488 L666 502 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="657" y1="502" x2="675" y2="502" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="666" y1="502" x2="666" y2="512" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="675" y1="495" x2="684" y2="486" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M684 486 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="675" y1="502" x2="684" y2="493" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M684 493 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="170" y1="630" x2="170" y2="638" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M161 638 L179 638 L170 652 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="161" y1="652" x2="179" y2="652" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="170" y1="652" x2="170" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="179" y1="645" x2="188" y2="636" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M188 636 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="179" y1="652" x2="188" y2="643" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M188 643 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="218" y1="630" x2="218" y2="638" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M209 638 L227 638 L218 652 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="209" y1="652" x2="227" y2="652" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="218" y1="652" x2="218" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="227" y1="645" x2="236" y2="636" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M236 636 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="227" y1="652" x2="236" y2="643" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M236 643 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="266" y1="630" x2="266" y2="638" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M257 638 L275 638 L266 652 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="257" y1="652" x2="275" y2="652" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="266" y1="652" x2="266" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="275" y1="645" x2="284" y2="636" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M284 636 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="275" y1="652" x2="284" y2="643" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M284 643 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="370" y1="630" x2="370" y2="638" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M361 638 L379 638 L370 652 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="361" y1="652" x2="379" y2="652" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="370" y1="652" x2="370" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="379" y1="645" x2="388" y2="636" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M388 636 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="379" y1="652" x2="388" y2="643" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M388 643 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="418" y1="630" x2="418" y2="638" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M409 638 L427 638 L418 652 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="409" y1="652" x2="427" y2="652" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="418" y1="652" x2="418" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="427" y1="645" x2="436" y2="636" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M436 636 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="427" y1="652" x2="436" y2="643" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M436 643 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="466" y1="630" x2="466" y2="638" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M457 638 L475 638 L466 652 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="457" y1="652" x2="475" y2="652" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="466" y1="652" x2="466" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="475" y1="645" x2="484" y2="636" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M484 636 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="475" y1="652" x2="484" y2="643" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M484 643 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="570" y1="630" x2="570" y2="638" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<path d="M561 638 L579 638 L570 652 Z" fill="#fbd5d5" stroke="#d62828" stroke-width="2" stroke-linejoin="round"/>
<line x1="561" y1="652" x2="579" y2="652" stroke="#d62828" stroke-width="2.4" stroke-linecap="round"/>
<line x1="570" y1="652" x2="570" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="579" y1="645" x2="588" y2="636" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M588 636 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="579" y1="652" x2="588" y2="643" stroke="#d62828" stroke-width="1.4" stroke-linecap="round"/>
<path d="M588 643 l-5 1 l4 4 Z" fill="#d62828"/>
<line x1="618" y1="630" x2="618" y2="638" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<path d="M609 638 L627 638 L618 652 Z" fill="#d3f0d8" stroke="#2a9d3a" stroke-width="2" stroke-linejoin="round"/>
<line x1="609" y1="652" x2="627" y2="652" stroke="#2a9d3a" stroke-width="2.4" stroke-linecap="round"/>
<line x1="618" y1="652" x2="618" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="627" y1="645" x2="636" y2="636" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M636 636 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="627" y1="652" x2="636" y2="643" stroke="#2a9d3a" stroke-width="1.4" stroke-linecap="round"/>
<path d="M636 643 l-5 1 l4 4 Z" fill="#2a9d3a"/>
<line x1="666" y1="630" x2="666" y2="638" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<path d="M657 638 L675 638 L666 652 Z" fill="#d6e3f7" stroke="#2f6fc4" stroke-width="2" stroke-linejoin="round"/>
<line x1="657" y1="652" x2="675" y2="652" stroke="#2f6fc4" stroke-width="2.4" stroke-linecap="round"/>
<line x1="666" y1="652" x2="666" y2="662" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="675" y1="645" x2="684" y2="636" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M684 636 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="675" y1="652" x2="684" y2="643" stroke="#2f6fc4" stroke-width="1.4" stroke-linecap="round"/>
<path d="M684 643 l-5 1 l4 4 Z" fill="#2f6fc4"/>
<line x1="170" y1="362" x2="170" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="218" y1="362" x2="218" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="218" cy="390" r="4" fill="#3a3a3a"/>
<line x1="266" y1="362" x2="266" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="266" cy="390" r="4" fill="#3a3a3a"/>
<line x1="370" y1="362" x2="370" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="370" cy="390" r="4" fill="#3a3a3a"/>
<line x1="418" y1="362" x2="418" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="418" cy="390" r="4" fill="#3a3a3a"/>
<line x1="466" y1="362" x2="466" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="466" cy="390" r="4" fill="#3a3a3a"/>
<line x1="570" y1="362" x2="570" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="570" cy="390" r="4" fill="#3a3a3a"/>
<line x1="618" y1="362" x2="618" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="618" cy="390" r="4" fill="#3a3a3a"/>
<line x1="666" y1="362" x2="666" y2="390" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="666" cy="390" r="4" fill="#3a3a3a"/>
<path d="M170 390 H190 a6 6 0 0 1 12 0 H238 a6 6 0 0 1 12 0 H342 a6 6 0 0 1 12 0 H390 a6 6 0 0 1 12 0 H438 a6 6 0 0 1 12 0 H542 a6 6 0 0 1 12 0 H590 a6 6 0 0 1 12 0 H638 a6 6 0 0 1 12 0 H778 V410" fill="none" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<text x="734" y="382" font-size="13" text-anchor="end" fill="#555" font-weight="bold">ligne 0</text>
<circle cx="789" cy="430" r="25" fill="#fafafa" stroke="#333333" stroke-width="1.6"/>
<line x1="798" y1="417" x2="798" y2="443" stroke="#333333" stroke-width="3" stroke-linecap="round"/>
<line x1="798" y1="424" x2="778" y2="410" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="798" y1="436" x2="778" y2="450" stroke="#222222" stroke-width="2.2" stroke-linecap="round"/>
<path d="M778 450 l3 -9 l5 7 Z" fill="#222222"/>
<line x1="798" y1="430" x2="830" y2="430" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<text x="746" y="428" font-size="14" text-anchor="middle" fill="#333333" font-weight="bold">T0</text>
<text x="746" y="444" font-size="11" text-anchor="middle" fill="#666">BC337</text>
<text x="812" y="448" font-size="10" text-anchor="middle" fill="#888">B</text>
<text x="768" y="404" font-size="10" text-anchor="middle" fill="#888">C</text>
<text x="764" y="458" font-size="10" text-anchor="middle" fill="#888">E</text>
<line x1="778" y1="450" x2="778" y2="466" stroke="#222222" stroke-width="2.2" stroke-linecap="round"/>
<line x1="767" y1="466" x2="789" y2="466" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="771" y1="471" x2="785" y2="471" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="775" y1="476" x2="781" y2="476" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="830" y1="430" x2="840.0" y2="430" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<line x1="890.0" y1="430" x2="900" y2="430" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<rect x="840.0" y="423" width="50" height="14" rx="2" fill="#fff" stroke="#c98a00" stroke-width="2.2"/>
<text x="865.0" y="417" font-size="12" text-anchor="middle" fill="#c98a00">1 kΩ</text>
<line x1="900" y1="430" x2="900" y2="190" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<line x1="170" y1="512" x2="170" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="218" y1="512" x2="218" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="218" cy="540" r="4" fill="#3a3a3a"/>
<line x1="266" y1="512" x2="266" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="266" cy="540" r="4" fill="#3a3a3a"/>
<line x1="370" y1="512" x2="370" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="370" cy="540" r="4" fill="#3a3a3a"/>
<line x1="418" y1="512" x2="418" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="418" cy="540" r="4" fill="#3a3a3a"/>
<line x1="466" y1="512" x2="466" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="466" cy="540" r="4" fill="#3a3a3a"/>
<line x1="570" y1="512" x2="570" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="570" cy="540" r="4" fill="#3a3a3a"/>
<line x1="618" y1="512" x2="618" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="618" cy="540" r="4" fill="#3a3a3a"/>
<line x1="666" y1="512" x2="666" y2="540" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="666" cy="540" r="4" fill="#3a3a3a"/>
<path d="M170 540 H190 a6 6 0 0 1 12 0 H238 a6 6 0 0 1 12 0 H342 a6 6 0 0 1 12 0 H390 a6 6 0 0 1 12 0 H438 a6 6 0 0 1 12 0 H542 a6 6 0 0 1 12 0 H590 a6 6 0 0 1 12 0 H638 a6 6 0 0 1 12 0 H778 V560" fill="none" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<text x="734" y="532" font-size="13" text-anchor="end" fill="#555" font-weight="bold">ligne 1</text>
<circle cx="789" cy="580" r="25" fill="#fafafa" stroke="#333333" stroke-width="1.6"/>
<line x1="798" y1="567" x2="798" y2="593" stroke="#333333" stroke-width="3" stroke-linecap="round"/>
<line x1="798" y1="574" x2="778" y2="560" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="798" y1="586" x2="778" y2="600" stroke="#222222" stroke-width="2.2" stroke-linecap="round"/>
<path d="M778 600 l3 -9 l5 7 Z" fill="#222222"/>
<line x1="798" y1="580" x2="830" y2="580" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<text x="746" y="578" font-size="14" text-anchor="middle" fill="#333333" font-weight="bold">T1</text>
<text x="746" y="594" font-size="11" text-anchor="middle" fill="#666">BC337</text>
<text x="812" y="598" font-size="10" text-anchor="middle" fill="#888">B</text>
<text x="768" y="554" font-size="10" text-anchor="middle" fill="#888">C</text>
<text x="764" y="608" font-size="10" text-anchor="middle" fill="#888">E</text>
<line x1="778" y1="600" x2="778" y2="616" stroke="#222222" stroke-width="2.2" stroke-linecap="round"/>
<line x1="767" y1="616" x2="789" y2="616" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="771" y1="621" x2="785" y2="621" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="775" y1="626" x2="781" y2="626" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="830" y1="580" x2="855.0" y2="580" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<line x1="905.0" y1="580" x2="930" y2="580" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<rect x="855.0" y="573" width="50" height="14" rx="2" fill="#fff" stroke="#c98a00" stroke-width="2.2"/>
<text x="880.0" y="567" font-size="12" text-anchor="middle" fill="#c98a00">1 kΩ</text>
<line x1="930" y1="580" x2="930" y2="190" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<line x1="170" y1="662" x2="170" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="218" y1="662" x2="218" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="218" cy="690" r="4" fill="#3a3a3a"/>
<line x1="266" y1="662" x2="266" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="266" cy="690" r="4" fill="#3a3a3a"/>
<line x1="370" y1="662" x2="370" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="370" cy="690" r="4" fill="#3a3a3a"/>
<line x1="418" y1="662" x2="418" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="418" cy="690" r="4" fill="#3a3a3a"/>
<line x1="466" y1="662" x2="466" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="466" cy="690" r="4" fill="#3a3a3a"/>
<line x1="570" y1="662" x2="570" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="570" cy="690" r="4" fill="#3a3a3a"/>
<line x1="618" y1="662" x2="618" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="618" cy="690" r="4" fill="#3a3a3a"/>
<line x1="666" y1="662" x2="666" y2="690" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="666" cy="690" r="4" fill="#3a3a3a"/>
<path d="M170 690 H778 V710" fill="none" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<text x="734" y="682" font-size="13" text-anchor="end" fill="#555" font-weight="bold">ligne 2</text>
<circle cx="789" cy="730" r="25" fill="#fafafa" stroke="#333333" stroke-width="1.6"/>
<line x1="798" y1="717" x2="798" y2="743" stroke="#333333" stroke-width="3" stroke-linecap="round"/>
<line x1="798" y1="724" x2="778" y2="710" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="798" y1="736" x2="778" y2="750" stroke="#222222" stroke-width="2.2" stroke-linecap="round"/>
<path d="M778 750 l3 -9 l5 7 Z" fill="#222222"/>
<line x1="798" y1="730" x2="830" y2="730" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<text x="746" y="728" font-size="14" text-anchor="middle" fill="#333333" font-weight="bold">T2</text>
<text x="746" y="744" font-size="11" text-anchor="middle" fill="#666">BC337</text>
<text x="812" y="748" font-size="10" text-anchor="middle" fill="#888">B</text>
<text x="768" y="704" font-size="10" text-anchor="middle" fill="#888">C</text>
<text x="764" y="758" font-size="10" text-anchor="middle" fill="#888">E</text>
<line x1="778" y1="750" x2="778" y2="766" stroke="#222222" stroke-width="2.2" stroke-linecap="round"/>
<line x1="767" y1="766" x2="789" y2="766" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="771" y1="771" x2="785" y2="771" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="775" y1="776" x2="781" y2="776" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="830" y1="730" x2="870.0" y2="730" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<line x1="920.0" y1="730" x2="960" y2="730" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<rect x="870.0" y="723" width="50" height="14" rx="2" fill="#fff" stroke="#c98a00" stroke-width="2.2"/>
<text x="895.0" y="717" font-size="12" text-anchor="middle" fill="#c98a00">1 kΩ</text>
<line x1="960" y1="730" x2="960" y2="190" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<rect x="40" y="814" width="1000" height="136" rx="10" fill="#fafafa" stroke="#e2e2e2"/>
<text x="60" y="840" font-size="15" text-anchor="start" fill="#111" font-weight="bold">Légende</text>
<line x1="60" y1="870" x2="90" y2="870" stroke="#d62828" stroke-width="2.2" stroke-linecap="round"/>
<line x1="94" y1="870" x2="124" y2="870" stroke="#2a9d3a" stroke-width="2.2" stroke-linecap="round"/>
<line x1="128" y1="870" x2="158" y2="870" stroke="#2f6fc4" stroke-width="2.2" stroke-linecap="round"/>
<text x="170" y="874" font-size="12" text-anchor="start" fill="#333333">colonnes : anodes R, G, B (D2 à D10)</text>
<line x1="400" y1="870" x2="498" y2="870" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round"/>
<text x="510" y="874" font-size="12" text-anchor="start" fill="#333333">lignes : cathodes communes</text>
<line x1="700" y1="870" x2="798" y2="870" stroke="#c98a00" stroke-width="2.2" stroke-linecap="round"/>
<text x="810" y="874" font-size="12" text-anchor="start" fill="#333333">commande des lignes (D11 à D13)</text>
<line x1="98" y1="896" x2="120" y2="896" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="102" y1="901" x2="116" y2="901" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<line x1="106" y1="906" x2="112" y2="906" stroke="#222222" stroke-width="2.4" stroke-linecap="round"/>
<text x="170" y="906" font-size="12" text-anchor="start" fill="#333333">masse (GND) : symboles tous reliés</text>
<circle cx="449" cy="902" r="4" fill="#3a3a3a"/>
<text x="510" y="906" font-size="12" text-anchor="start" fill="#333333">point = fils connectés</text>
<path d="M700 902 H743 a6 6 0 0 1 12 0 H798" fill="none" stroke="#3a3a3a" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
<text x="810" y="906" font-size="12" text-anchor="start" fill="#333333">pont = croisement sans contact</text>
<text x="60" y="938" font-size="12" text-anchor="start" fill="#555" font-style="italic">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).</text>
</svg>

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB