a8e63aa45c
- Fixed KiCad 8 PCB file format (text rotation syntax) - PCB now loads correctly with board outline and labels - Added Python placement script for KiCad scripting console - Updated PCB_LAYOUT.md with quick start instructions Next step: Open in KiCad, run Update PCB from Schematic, then use Freerouting or manual routing to complete traces.
125 lines
3.6 KiB
Python
125 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
KiCad PCB Component Placement Script for SN-L00
|
|
|
|
Run this script in KiCad's Scripting Console (Tools > Scripting Console)
|
|
after running "Update PCB from Schematic" to place all components.
|
|
|
|
Usage in KiCad scripting console:
|
|
exec(open('/path/to/place_components.py').read())
|
|
"""
|
|
|
|
import pcbnew
|
|
|
|
# Component placement coordinates (mm) based on CPL_PCBWay.csv
|
|
# Format: {Reference: (x, y, rotation, layer)}
|
|
# Layer: "F.Cu" for top, "B.Cu" for bottom
|
|
|
|
PLACEMENTS = {
|
|
# Capacitors
|
|
"C1": (10.0, 60.0, 0, "F.Cu"),
|
|
"C2": (18.0, 60.0, 0, "F.Cu"),
|
|
"C3": (21.0, 60.0, 0, "F.Cu"),
|
|
"C4": (7.0, 68.0, 0, "F.Cu"),
|
|
"C5": (21.0, 68.0, 0, "F.Cu"),
|
|
|
|
# Resistors
|
|
"R1": (10.0, 35.0, 0, "F.Cu"),
|
|
"R2": (24.0, 36.0, 90, "F.Cu"),
|
|
"R3": (7.0, 76.0, 90, "F.Cu"),
|
|
"R4": (21.0, 76.0, 90, "F.Cu"),
|
|
"R5": (18.0, 76.0, 90, "F.Cu"),
|
|
"R6": (18.0, 72.0, 90, "F.Cu"),
|
|
|
|
# Diodes
|
|
"D1": (7.0, 65.0, 0, "B.Cu"), # Bottom layer
|
|
"D2": (24.0, 31.5, 90, "F.Cu"),
|
|
"D3": (24.0, 70.0, 90, "F.Cu"),
|
|
"D4": (24.0, 74.0, 90, "F.Cu"),
|
|
|
|
# ICs
|
|
"U1": (14.0, 65.0, 0, "B.Cu"), # LDO on bottom
|
|
"U2": (7.0, 72.0, 0, "F.Cu"), # Schmitt trigger
|
|
"U3": (21.0, 72.0, 0, "F.Cu"), # Op-amp
|
|
|
|
# Connectors
|
|
"J1": (14.0, 92.0, 0, "F.Cu"), # Power header
|
|
"J2": (7.0, 83.0, 0, "F.Cu"), # TRIG jack
|
|
"J3": (21.0, 83.0, 0, "F.Cu"), # RETURN jack
|
|
|
|
# Switch
|
|
"SW1": (14.0, 31.5, 0, "F.Cu"),
|
|
|
|
# Modules (hand-solder, placement reference only)
|
|
"MOD1": (14.0, 46.5, 0, "F.Cu"), # RP2040-Zero
|
|
"MOD2": (14.0, 17.5, 0, "F.Cu"), # OLED
|
|
}
|
|
|
|
def place_components():
|
|
"""Place all components according to the PLACEMENTS dictionary."""
|
|
board = pcbnew.GetBoard()
|
|
|
|
if not board:
|
|
print("Error: No board loaded!")
|
|
return
|
|
|
|
placed = 0
|
|
not_found = []
|
|
|
|
for ref, (x, y, rotation, layer) in PLACEMENTS.items():
|
|
# Find the footprint by reference
|
|
fp = board.FindFootprintByReference(ref)
|
|
|
|
if fp is None:
|
|
not_found.append(ref)
|
|
continue
|
|
|
|
# Convert mm to internal units (nanometers)
|
|
pos = pcbnew.VECTOR2I(pcbnew.FromMM(x), pcbnew.FromMM(y))
|
|
fp.SetPosition(pos)
|
|
|
|
# Set rotation (in tenths of degrees)
|
|
fp.SetOrientationDegrees(rotation)
|
|
|
|
# Set layer (flip if on bottom)
|
|
if layer == "B.Cu" and fp.GetLayer() == pcbnew.F_Cu:
|
|
fp.Flip(pos, False)
|
|
elif layer == "F.Cu" and fp.GetLayer() == pcbnew.B_Cu:
|
|
fp.Flip(pos, False)
|
|
|
|
placed += 1
|
|
print(f"Placed {ref} at ({x}, {y}) rot={rotation}° on {layer}")
|
|
|
|
if not_found:
|
|
print(f"\nNot found (run 'Update PCB from Schematic' first): {not_found}")
|
|
|
|
print(f"\nPlaced {placed}/{len(PLACEMENTS)} components")
|
|
|
|
# Refresh the board view
|
|
pcbnew.Refresh()
|
|
|
|
|
|
def add_mounting_holes():
|
|
"""Add M3 mounting holes at standard Eurorack positions."""
|
|
board = pcbnew.GetBoard()
|
|
|
|
# Check if mounting holes already exist
|
|
for fp in board.GetFootprints():
|
|
if "MountingHole" in fp.GetValue():
|
|
print("Mounting holes already exist, skipping...")
|
|
return
|
|
|
|
# Would need to load footprint from library - simplified for this script
|
|
print("Add mounting holes manually:")
|
|
print(" MH1: (14, 5) - Top")
|
|
print(" MH2: (14, 95) - Bottom")
|
|
print(" Footprint: MountingHole:MountingHole_3.2mm_M3")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("SN-L00 Component Placement Script")
|
|
print("=" * 40)
|
|
place_components()
|
|
add_mounting_holes()
|
|
print("\nDone! Run DRC and then route traces.")
|