Add routed PSU carrier board layout (rev 0.1)

- Placement script (layout_pcb.py): LV left, HV right, panel connector on the
  boundary, terminal blocks on the edges, heatsink space for the TO-220s
- Freerouting-based routing script (route_pcb.py) that routes with oversized
  tracks/vias and shrinks them, giving 3 mm HV-to-LV and 1.3 mm HV-to-HV
- Custom DRC rules (plasma_dmd_psu.kicad_dru) with documented exceptions
- Wide TO-92 footprints; schematic generator now keeps symbol UUIDs
- DRC: 0 violations, 0 unconnected pads, schematic parity OK

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-24 02:58:35 +02:00
1 parent dbc1f0041f
commit 28c666506e
11 files changed
+30816 -422

No files matched your search

+25 -6
View File
@@ -23,7 +23,7 @@ FP_D35 = "Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal"
FP_D41 = "Diode_THT:D_DO-41_SOD81_P10.16mm_Horizontal"
FP_D15 = "Diode_THT:D_DO-15_P12.70mm_Horizontal"
FP_LED = "LED_THT:LED_D5.0mm"
FP_TO92 = "Package_TO_SOT_THT:TO-92_Inline"
FP_TO92 = "Package_TO_SOT_THT:TO-92_Inline_Wide" # 2.54 mm pitch for HV clearance
FP_TO220 = "Package_TO_SOT_THT:TO-220-3_Vertical"
FP_FUSE = "Fuse:Fuseholder_Cylinder-5x20mm_Schurter_0031_8201_Horizontal_Open"
FP_CFILM = "Capacitor_THT:C_Rect_L18.0mm_W5.0mm_P15.00mm_FKS3_FKP3"
@@ -213,8 +213,9 @@ def snap(v):
return round(round(v / 1.27) * 1.27, 2)
HV_NETS = ["+90V_RAW", "+65V", "HVP_MOD", "Q2_E", "REF_P", "Q3_B", "N_LED1",
"-130V_RAW", "-112V", "-100V", "HVN_MOD", "Q4_E", "REF_N", "Q5_B", "REF_M", "Q6_B", "Q6_C", "N_LED2"]
# N_LED1/N_LED2 sit a LED drop away from GND, so they stay in Default.
HV_NETS = ["+90V_RAW", "+65V", "HVP_MOD", "Q2_E", "REF_P", "Q3_B",
"-130V_RAW", "-112V", "-100V", "HVN_MOD", "Q4_E", "REF_N", "Q5_B", "REF_M", "Q6_B", "Q6_C"]
POWER_NETS = ["GND", "+12V", "+12V_IN", "+12V_HV", "+12V_HVP", "+12V_HVN", "+5V", "+12V_PANEL"]
@@ -236,7 +237,7 @@ def write_project():
"classes": [
netclass("Default", 0.25, 0.4, 2147483647),
netclass("Power", 0.3, 1.0, 1),
netclass("HV", 3.0, 0.6, 0),
netclass("HV", 1.3, 0.6, 0) # HV <-> LV 3 mm comes from plasma_dmd_psu.kicad_dru,
],
"meta": {"version": 5},
"net_colors": None,
@@ -247,8 +248,26 @@ def write_project():
pro.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
def existing_uuids():
path = HERE / f"{PROJECT}.kicad_sch"
if not path.exists():
return None, {}
text = path.read_text(encoding="utf-8")
root = re.search(r'^\(kicad_sch.*?\(uuid "([^"]+)"\)', text, re.S).group(1)
syms = {}
for m in re.finditer(r'^ \(symbol \(lib_id', text, re.M):
blk = read_sexpr_block(text, m.start() + 2)
u = re.search(r'\(dnp no\) \(uuid "([^"]+)"\)', blk)
r = re.search(r'\(property "Reference" "([^"]+)"', blk)
if u and r:
syms[r.group(1)] = u.group(1)
return root, syms
def main():
root = uid()
# Reuse UUIDs from an existing schematic so the PCB keeps its links to the symbols.
old_root, old_sym = existing_uuids()
root = old_root or uid()
lib_blocks, pin_cache = {}, {}
for p in PARTS:
if p[1] not in lib_blocks:
@@ -273,7 +292,7 @@ def main():
rx, ry, vx, vy, just = snap(x + 5.08), snap(y - 1.27), snap(x + 5.08), snap(y + 1.27), " (justify left)"
pin_uuid = "\n".join(f' (pin {q(num)} (uuid {q(uid())}))' for num, *_ in pins)
items.append(f""" (symbol (lib_id {q(lib_id)}) (at {x} {y} 0) (unit 1)
(exclude_from_sim no) (in_bom yes) (on_board yes) (dnp no) (uuid {q(uid())})
(exclude_from_sim no) (in_bom yes) (on_board yes) (dnp no) (uuid {q(old_sym.get(ref) or uid())})
(property "Reference" {q(ref)} (at {rx} {ry} 0) (effects (font (size 1.27 1.27)){just}))
(property "Value" {q(value)} (at {vx} {vy} 0) (effects (font (size 1.27 1.27)){just}))
(property "Footprint" {q(fp)} (at {x} {y} 0) (effects (font (size 1.27 1.27)) (hide yes)))