#!/usr/bin/env python3 """ SN-L00 Component Placement Script for 8HP Eurorack (40mm x 100mm) Run in KiCad PCB Editor: Tools → Scripting Console Then: exec(open('scripts/place_8hp.py').read()) """ import pcbnew board = pcbnew.GetBoard() def mm(val): return pcbnew.FromMM(val) def place(x, y): return pcbnew.VECTOR2I(mm(x), mm(y)) # First, update the board outline to 8HP (40mm x 100mm) for drawing in board.GetDrawings(): if drawing.GetClass() == "PCB_SHAPE": if drawing.GetShape() == pcbnew.SHAPE_T_RECT: drawing.SetStart(pcbnew.VECTOR2I(mm(0), mm(0))) drawing.SetEnd(pcbnew.VECTOR2I(mm(40), mm(100))) print("Updated board outline to 40mm x 100mm (8HP)") # Delete all tracks for fresh routing tracks = list(board.GetTracks()) for track in tracks: board.Delete(track) print(f"Deleted {len(tracks)} tracks") # Component positions for 8HP (40mm x 100mm) layout v2 placements = { "MOD3": (20, 15, 90), # OLED display "J3": (10, 35, 0), # RETURN_IN jack "J4": (30, 35, 0), # TRIG_OUT jack "SW1": (20, 48, 0), # Button "D5": (32, 48, 0), # LED "MOD2": (20, 62, 0), # RP2040-Zero "U2": (8, 78, 0), # 74LVC1G17 "U4": (32, 78, 0), # MCP6001 "C4": (4, 78, 90), # Decoupling "C5": (14, 78, 90), "C6": (28, 82, 90), "D3": (4, 82, 0), # Protection diodes "D4": (36, 78, 0), "R2": (4, 86, 90), # Resistors "R3": (10, 86, 90), "R4": (16, 86, 90), "R5": (24, 86, 90), "R6": (30, 86, 90), "R7": (36, 86, 90), "J2": (20, 88, 0), # Eurorack power "D2": (4, 92, 0), "U3": (32, 94, 180), # LDO "C2": (10, 94, 90), "C3": (26, 94, 90), } print("\nPlacing components for 8HP Eurorack layout (v2)...") placed = 0 not_found = [] for ref, (x, y, rot) in placements.items(): fp = board.FindFootprintByReference(ref) if fp: fp.SetPosition(place(x, y)) fp.SetOrientationDegrees(rot) placed += 1 print(f" {ref} -> ({x}, {y}) rot={rot}°") else: not_found.append(ref) print(f"\nPlaced {placed} components") if not_found: print(f"Not found: {', '.join(not_found)}") pcbnew.Refresh() print("\nDone! Save (Ctrl+S), then run: ./scripts/route.sh")