Add panel-to-PCB mounting system with M3 standoffs

Panel alignment:
- PCB offset 10mm from panel top
- Component holes aligned: OLED@25mm, jacks@45mm, button@58mm
- 4x M3 standoff holes at corners (5,5), (35,5), (5,75), (35,75)

Updates:
- Panel SVG and spec aligned with PCB layout
- Mounting holes added to PCB (Edge.Cuts layer)
- Regenerated Gerbers with mounting holes
- Updated autoroute.py to add mounting holes automatically

DRC: 0 unconnected, 7 cosmetic errors (courtyard overlaps)
This commit is contained in:
2026-01-23 08:15:25 +01:00
parent ccb833fdc3
commit d43c7976ad
21 changed files with 1654 additions and 942 deletions
+6
View File
@@ -32,3 +32,9 @@ firmware/.pio/
# OS
.DS_Store
Thumbs.db
# Build artifacts
*.dsn
*.ses
*.mgc
DRC.rpt
Binary file not shown.
File diff suppressed because it is too large Load Diff
+41 -34
View File
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Copper,L2,Bot*%
%TF.FilePolarity,Positive*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
@@ -177,61 +177,68 @@ X22540000Y-98160000D03*
%TD*%
D15*
%TO.N,Net-(D2-A)*%
X7525800Y-94231700D03*
X35150000Y-90436200D03*
X7525800Y-94231700D03*
X26000000Y-95962400D03*
%TO.N,+12V*%
X29051000Y-89091600D03*
X38054700Y-89678700D03*
X10656900Y-92357500D03*
X33628300Y-98160000D03*
X28776100Y-89366500D03*
X10000000Y-90540000D03*
%TO.N,+3.3V*%
X11008200Y-86838000D03*
X24000000Y-87735100D03*
%TO.N,Net-(D2-K)*%
X2000000Y-90577900D03*
%TO.N,Net-(D3-K)*%
X24000000Y-83998100D03*
X10000000Y-83555900D03*
X2950000Y-83555900D03*
X32083000Y-84742000D03*
X24307800Y-83595800D03*
X10000000Y-83595800D03*
X2950000Y-83595800D03*
%TO.N,/BTN*%
X4000000Y-81824100D03*
%TD*%
D16*
%TO.N,Net-(D2-A)*%
X31354500Y-94231700D02*
X35150000Y-90436200D01*
X26000000Y-94231700D02*
X31354500Y-94231700D01*
X26000000Y-95962400D02*
X26000000Y-94231700D01*
X7525800Y-94231700D02*
X26000000Y-94231700D01*
X26000000Y-94231700D02*
X31354500Y-94231700D01*
X31354500Y-94231700D02*
X35150000Y-90436200D01*
X26000000Y-95962400D02*
X26000000Y-94231700D01*
%TO.N,+12V*%
X37467600Y-89091600D02*
X38054700Y-89678700D01*
X20000000Y-93080000D02*
X19277500Y-92357500D01*
X20000000Y-95620000D02*
X22540000Y-95620000D01*
X26528400Y-89091600D02*
X29051000Y-89091600D01*
X29051000Y-89091600D02*
X37467600Y-89091600D01*
X19277500Y-92357500D02*
X10656900Y-92357500D01*
X22540000Y-93080000D02*
X26528400Y-89091600D01*
X26253500Y-89366500D01*
X26253500Y-89366500D02*
X28776100Y-89366500D01*
X20000000Y-90540000D02*
X10000000Y-90540000D01*
X22540000Y-98160000D02*
X33628300Y-98160000D01*
%TO.N,+3.3V*%
X24000000Y-87735100D02*
X23102900Y-86838000D01*
X23102900Y-86838000D02*
X11008200Y-86838000D01*
%TO.N,Net-(D2-K)*%
X21349400Y-91730600D02*
X3152700Y-91730600D01*
X22540000Y-90540000D02*
X21349400Y-91730600D01*
X3152700Y-91730600D02*
X2000000Y-90577900D01*
X22540000Y-90540000D02*
X21349400Y-91730600D01*
%TO.N,Net-(D3-K)*%
X10000000Y-83555900D02*
X23557800Y-83555900D01*
X10000000Y-83555900D02*
X2950000Y-83555900D01*
X23557800Y-83555900D02*
X24000000Y-83998100D01*
X24307800Y-83595800D02*
X10000000Y-83595800D01*
X24307800Y-83595800D02*
X30936800Y-83595800D01*
X30936800Y-83595800D02*
X32083000Y-84742000D01*
X10000000Y-83595800D02*
X2950000Y-83595800D01*
%TO.N,/BTN*%
X12875900Y-81824100D02*
X4000000Y-81824100D01*
+2 -2
View File
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Soldermask,Bot*%
%TF.FilePolarity,Negative*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
+2 -2
View File
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Paste,Bot*%
%TF.FilePolarity,Positive*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Legend,Bot*%
%TF.FilePolarity,Positive*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
+42 -2
View File
@@ -1,11 +1,11 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Profile,NP*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
@@ -15,9 +15,49 @@ G04 APERTURE LIST*
%TD*%
G04 APERTURE END LIST*
D10*
X36600000Y-5000000D02*
G75*
G02*
X33400000Y-5000000I-1600000J0D01*
G01*
X33400000Y-5000000D02*
G75*
G02*
X36600000Y-5000000I1600000J0D01*
G01*
X6600000Y-75000000D02*
G75*
G02*
X3400000Y-75000000I-1600000J0D01*
G01*
X3400000Y-75000000D02*
G75*
G02*
X6600000Y-75000000I1600000J0D01*
G01*
X36600000Y-75000000D02*
G75*
G02*
X33400000Y-75000000I-1600000J0D01*
G01*
X33400000Y-75000000D02*
G75*
G02*
X36600000Y-75000000I1600000J0D01*
G01*
X0Y0D02*
X40000000Y0D01*
X40000000Y-100000000D01*
X0Y-100000000D01*
X0Y0D01*
X6600000Y-5000000D02*
G75*
G02*
X3400000Y-5000000I-1600000J0D01*
G01*
X3400000Y-5000000D02*
G75*
G02*
X6600000Y-5000000I1600000J0D01*
G01*
M02*
+151 -147
View File
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Copper,L1,Top*%
%TF.FilePolarity,Positive*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
@@ -371,19 +371,23 @@ X22540000Y-98160000D03*
%TD*%
D24*
%TO.N,Net-(D2-A)*%
X7525800Y-94231700D03*
X35150000Y-90436200D03*
X7525800Y-94231700D03*
X26000000Y-95962400D03*
%TO.N,+12V*%
X29051000Y-89091600D03*
X38054700Y-89678700D03*
X10656900Y-92357500D03*
X33628300Y-98160000D03*
X28776100Y-89366500D03*
X10000000Y-90540000D03*
%TO.N,+3.3V*%
X11008200Y-86838000D03*
X24000000Y-87735100D03*
%TO.N,Net-(D2-K)*%
X2000000Y-90577900D03*
%TO.N,Net-(D3-K)*%
X24000000Y-83998100D03*
X10000000Y-83555900D03*
X2950000Y-83555900D03*
X32083000Y-84742000D03*
X24307800Y-83595800D03*
X10000000Y-83595800D03*
X2950000Y-83595800D03*
%TO.N,/BTN*%
X4000000Y-81824100D03*
%TD*%
@@ -398,174 +402,174 @@ X7525800Y-93525800D01*
X35150000Y-91700000D02*
X35150000Y-90436200D01*
%TO.N,+12V*%
X30000000Y-83225000D02*
X30000000Y-85175000D01*
X34950000Y-50162500D02*
X34950000Y-77039700D01*
X28000000Y-81225000D02*
X28951900Y-82176800D01*
X8526200Y-91751200D02*
X8526200Y-80613700D01*
X28776100Y-89366500D02*
X28776100Y-86398900D01*
X25970000Y-93080000D02*
X26000000Y-93050000D01*
X10000000Y-93225000D02*
X8526200Y-91751200D01*
X20000000Y-93080000D02*
X20000000Y-90540000D01*
X20000000Y-95620000D02*
X20000000Y-93080000D01*
X30076000Y-36216700D02*
X32787500Y-38928200D01*
X7878200Y-78337700D02*
X7878200Y-76995000D01*
X29051000Y-89091600D02*
X29051000Y-86124000D01*
X10000000Y-93225000D02*
X10000000Y-92357500D01*
X30000000Y-35000000D02*
X30000000Y-36216700D01*
X38054700Y-93395300D02*
X38054700Y-89678700D01*
X29051000Y-86124000D02*
X30000000Y-85175000D01*
X20000000Y-93080000D02*
X20000000Y-90540000D01*
X10000000Y-92357500D02*
X10656900Y-92357500D01*
X6862500Y-88037500D02*
X6862500Y-78950000D01*
X10000000Y-92357500D02*
X10000000Y-91175000D01*
X13397200Y-76447200D02*
X14000000Y-77050000D01*
X25970000Y-93080000D02*
X26000000Y-93050000D01*
X32787500Y-48000000D02*
X34950000Y-50162500D01*
X10000000Y-91175000D02*
X6862500Y-88037500D01*
X38054700Y-89678700D02*
X38054700Y-77510000D01*
X7265900Y-78950000D02*
X7878200Y-78337700D01*
X7878200Y-76995000D02*
X8426000Y-76447200D01*
X38054700Y-77510000D02*
X37584400Y-77039700D01*
X35150000Y-96300000D02*
X38054700Y-93395300D01*
X22540000Y-93080000D02*
X25970000Y-93080000D01*
X37584400Y-77039700D02*
X34950000Y-77039700D01*
X34950000Y-77039700D02*
X34950000Y-78000000D01*
X30000000Y-36216700D02*
X30076000Y-36216700D01*
X22540000Y-98160000D02*
X22540000Y-95620000D01*
X28000000Y-81225000D02*
X30000000Y-83225000D01*
X6862500Y-78950000D02*
X7265900Y-78950000D01*
X32036400Y-79092300D02*
X32036400Y-77272000D01*
X18847300Y-81897300D02*
X18847300Y-89387300D01*
X20000000Y-98160000D02*
X20000000Y-95620000D01*
X32787500Y-38928200D02*
X32787500Y-48000000D01*
X8426000Y-76447200D02*
X13397200Y-76447200D01*
X22540000Y-93080000D02*
X25970000Y-93080000D01*
X22540000Y-95620000D02*
X22540000Y-93080000D01*
X32764400Y-78000000D02*
X34950000Y-78000000D01*
X32036400Y-54627600D02*
X32036400Y-77272000D01*
X32036400Y-77272000D02*
X32764400Y-78000000D01*
X30000000Y-35608300D02*
X30000000Y-36216700D01*
X30000000Y-35608300D02*
X28188200Y-37420100D01*
X35150000Y-96300000D02*
X33628300Y-97821700D01*
X30000000Y-36216700D02*
X30076000Y-36216700D01*
X28776100Y-86398900D02*
X30000000Y-85175000D01*
X30000000Y-35000000D02*
X30000000Y-35608300D01*
X32787500Y-38928200D02*
X32787500Y-48000000D01*
X30000000Y-83742700D02*
X30000000Y-85175000D01*
X29211000Y-82953700D02*
X30000000Y-83742700D01*
X33628300Y-97821700D02*
X33628300Y-98160000D01*
X28951900Y-82176800D02*
X29211000Y-82436000D01*
X10000000Y-93225000D02*
X10000000Y-90540000D01*
X8526200Y-80613700D02*
X6862500Y-78950000D01*
X28188200Y-37420100D02*
X28188200Y-50779400D01*
X18847300Y-89387300D02*
X20000000Y-90540000D01*
X22540000Y-98160000D02*
X22540000Y-95620000D01*
X29211000Y-82436000D02*
X29211000Y-82953700D01*
X28188200Y-50779400D02*
X32036400Y-54627600D01*
X14000000Y-77050000D02*
X18847300Y-81897300D01*
X28951900Y-82176800D02*
X32036400Y-79092300D01*
%TO.N,+3.3V*%
X36476700Y-92673300D02*
X35150000Y-94000000D01*
X8126000Y-92901000D02*
X10000000Y-94775000D01*
X17232300Y-82182300D02*
X17232300Y-86825000D01*
X17232300Y-87542700D02*
X10000000Y-94775000D01*
X17232300Y-86825000D02*
X17232300Y-87542700D01*
X28000000Y-82800000D02*
X28000000Y-93150000D01*
X5050000Y-82000000D02*
X5050000Y-86825000D01*
X28000000Y-93150000D02*
X28850000Y-94000000D01*
X14000000Y-78950000D02*
X11037500Y-78950000D01*
X28000000Y-82800000D02*
X28000000Y-82775000D01*
X14000000Y-78950000D02*
X17232300Y-82182300D01*
X24000000Y-86825000D02*
X17232300Y-86825000D01*
X5050000Y-86825000D02*
X8126000Y-89901000D01*
X36476700Y-87301700D02*
X36476700Y-92673300D01*
X5050000Y-86825000D02*
X4000000Y-86825000D01*
X24000000Y-86825000D02*
X28000000Y-82825000D01*
X8126000Y-89901000D02*
X8126000Y-92901000D01*
X28000000Y-82825000D02*
X28000000Y-82800000D01*
X36000000Y-86825000D02*
X36476700Y-87301700D01*
X11037500Y-78950000D02*
X9137500Y-77050000D01*
X10820600Y-82333500D02*
X10820600Y-86838000D01*
X10820600Y-86838000D02*
X10820600Y-93954400D01*
X35150000Y-94000000D02*
X28850000Y-94000000D01*
X5050000Y-82000000D02*
X5050000Y-86825000D01*
X5050000Y-86825000D02*
X4000000Y-86825000D01*
X28000000Y-82800000D02*
X28000000Y-93150000D01*
X35150000Y-94000000D02*
X36476700Y-92673300D01*
X8167100Y-79680000D02*
X10820600Y-82333500D01*
X28000000Y-93150000D02*
X28850000Y-94000000D01*
X9198600Y-77111100D02*
X9137500Y-77050000D01*
X10623600Y-78950000D02*
X9198600Y-77525000D01*
X8124500Y-89899500D02*
X8124500Y-92899500D01*
X9198600Y-77525000D02*
X9198600Y-77111100D01*
X24000000Y-86825000D02*
X28000000Y-82825000D01*
X24000000Y-86825000D02*
X24000000Y-87735100D01*
X10820600Y-86838000D02*
X11008200Y-86838000D01*
X10820600Y-93954400D02*
X10000000Y-94775000D01*
X8124500Y-92899500D02*
X10000000Y-94775000D01*
X14000000Y-78950000D02*
X10623600Y-78950000D01*
X36476700Y-92673300D02*
X36476700Y-87301700D01*
X28000000Y-82825000D02*
X28000000Y-82800000D01*
X28000000Y-82800000D02*
X28000000Y-82775000D01*
X9198600Y-77525000D02*
X8167100Y-78556500D01*
X5050000Y-86825000D02*
X8124500Y-89899500D01*
X36476700Y-87301700D02*
X36000000Y-86825000D01*
X8167100Y-78556500D02*
X8167100Y-79680000D01*
%TO.N,Net-(D2-K)*%
X2000000Y-90577900D02*
X2000000Y-92000000D01*
%TO.N,Net-(D3-K)*%
X2950000Y-82000000D02*
X2950000Y-83555900D01*
X36100000Y-78950000D02*
X37050000Y-78000000D01*
X32143300Y-79944200D02*
X33137500Y-83687500D02*
X33137500Y-78950000D01*
X36100000Y-78950000D02*
X33137500Y-78950000D01*
X31856700Y-79944200D02*
X30862500Y-78950000D01*
X24000000Y-83998100D02*
X29048100Y-78950000D01*
X10000000Y-85175000D02*
X10000000Y-83555900D01*
X29048100Y-78950000D02*
X30862500Y-78950000D01*
X24000000Y-85175000D02*
X24000000Y-83998100D01*
X33137500Y-78950000D02*
X24000000Y-83903600D01*
X37050000Y-78000000D02*
X36100000Y-78950000D01*
X10000000Y-85175000D02*
X10000000Y-83595800D01*
X24307800Y-83595800D02*
X28953600Y-78950000D01*
X24000000Y-83903600D02*
X24307800Y-83595800D01*
X2950000Y-82000000D02*
X2950000Y-83595800D01*
X30000000Y-86825000D02*
X31856700Y-84968300D01*
X31856700Y-79944200D02*
X32143300Y-79944200D01*
X31856700Y-84968300D02*
X31856700Y-79944200D01*
X32083000Y-84742000D01*
X32083000Y-84742000D02*
X33137500Y-83687500D01*
X28953600Y-78950000D02*
X30862500Y-78950000D01*
%TO.N,Net-(D5-K)*%
X31212500Y-48000000D02*
X34241000Y-51028500D01*
X37418100Y-77441400D02*
X37653000Y-77676300D01*
X34241000Y-78249000D02*
X34519100Y-78527100D01*
X36434500Y-77441400D02*
X37418100Y-77441400D01*
X37653000Y-77676300D02*
X37653000Y-83522000D01*
X35348800Y-78527100D02*
X36434500Y-77441400D01*
X34519100Y-78527100D02*
X35348800Y-78527100D01*
X37653000Y-83522000D02*
X37691900Y-54479400D01*
X37691900Y-83483100D02*
X36000000Y-85175000D01*
X34241000Y-51028500D02*
X34241000Y-78249000D01*
X37691900Y-54479400D02*
X37691900Y-83483100D01*
%TO.N,/SDA*%
X18730000Y-32000000D02*
X18730000Y-48030000D01*
X18730000Y-48030000D02*
X27620000Y-56920000D01*
%TO.N,/RETURN_IN*%
X27620000Y-64540000D02*
X30862500Y-67782500D01*
X30862500Y-67782500D02*
X30862500Y-77050000D01*
X27620000Y-64540000D02*
X30862500Y-67782500D01*
%TO.N,/BTN*%
X4000000Y-81824100D02*
X4000000Y-85175000D01*
+2 -2
View File
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Soldermask,Top*%
%TF.FilePolarity,Negative*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
+2 -2
View File
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Paste,Top*%
%TF.FilePolarity,Positive*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:42+01:00*%
%TF.CreationDate,2026-01-23T08:14:38+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Legend,Top*%
%TF.FilePolarity,Positive*%
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:42*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:38*
%MOMM*%
%LPD*%
G01*
+84 -36
View File
@@ -1,12 +1,12 @@
%TF.GenerationSoftware,KiCad,Pcbnew,9.0.2+dfsg-1*%
%TF.CreationDate,2026-01-23T08:01:45+01:00*%
%TF.CreationDate,2026-01-23T08:14:39+01:00*%
%TF.ProjectId,SN-L00,534e2d4c-3030-42e6-9b69-6361645f7063,0.1*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Drillmap*%
%TF.FilePolarity,Positive*%
%FSLAX45Y45*%
G04 Gerber Fmt 4.5, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:01:45*
G04 Created by KiCad (PCBNEW 9.0.2+dfsg-1) date 2026-01-23 08:14:39*
%MOMM*%
%LPD*%
G01*
@@ -19,21 +19,61 @@ G04 APERTURE LIST*
%ADD15C,0.143000*%
G04 APERTURE END LIST*
D10*
X3660000Y-500000D02*
G75*
G02*
X3340000Y-500000I-160000J0D01*
G01*
X3340000Y-500000D02*
G75*
G02*
X3660000Y-500000I160000J0D01*
G01*
X660000Y-7500000D02*
G75*
G02*
X340000Y-7500000I-160000J0D01*
G01*
X340000Y-7500000D02*
G75*
G02*
X660000Y-7500000I160000J0D01*
G01*
X3660000Y-7500000D02*
G75*
G02*
X3340000Y-7500000I-160000J0D01*
G01*
X3340000Y-7500000D02*
G75*
G02*
X3660000Y-7500000I160000J0D01*
G01*
X0Y0D02*
X4000000Y0D01*
X4000000Y-10000000D01*
X0Y-10000000D01*
X0Y0D01*
X660000Y-500000D02*
G75*
G02*
X340000Y-500000I-160000J0D01*
G01*
X340000Y-500000D02*
G75*
G02*
X660000Y-500000I160000J0D01*
G01*
D11*
D12*
X185000Y-9042790D02*
X215000Y-9072790D01*
X215000Y-9042790D02*
X185000Y-9072790D01*
X280000Y-8340590D02*
X310000Y-8370590D01*
X310000Y-8340590D02*
X280000Y-8370590D01*
X280000Y-8344580D02*
X310000Y-8374580D01*
X310000Y-8344580D02*
X280000Y-8374580D01*
X385000Y-8167410D02*
X415000Y-8197410D01*
X415000Y-8167410D02*
@@ -42,34 +82,46 @@ X737580Y-9408170D02*
X767580Y-9438170D01*
X767580Y-9408170D02*
X737580Y-9438170D01*
X985000Y-8340590D02*
X1015000Y-8370590D01*
X1015000Y-8340590D02*
X985000Y-8370590D01*
X1050690Y-9220750D02*
X1080690Y-9250750D01*
X1080690Y-9220750D02*
X1050690Y-9250750D01*
X2385000Y-8384810D02*
X2415000Y-8414810D01*
X2415000Y-8384810D02*
X2385000Y-8414810D01*
X985000Y-8344580D02*
X1015000Y-8374580D01*
X1015000Y-8344580D02*
X985000Y-8374580D01*
X985000Y-9039000D02*
X1015000Y-9069000D01*
X1015000Y-9039000D02*
X985000Y-9069000D01*
X1085820Y-8668800D02*
X1115820Y-8698800D01*
X1115820Y-8668800D02*
X1085820Y-8698800D01*
X2385000Y-8758510D02*
X2415000Y-8788510D01*
X2415000Y-8758510D02*
X2385000Y-8788510D01*
X2415780Y-8344580D02*
X2445780Y-8374580D01*
X2445780Y-8344580D02*
X2415780Y-8374580D01*
X2585000Y-9581240D02*
X2615000Y-9611240D01*
X2615000Y-9581240D02*
X2585000Y-9611240D01*
X2890100Y-8894160D02*
X2920100Y-8924160D01*
X2920100Y-8894160D02*
X2890100Y-8924160D01*
X2862610Y-8921650D02*
X2892610Y-8951650D01*
X2892610Y-8921650D02*
X2862610Y-8951650D01*
X3193300Y-8459200D02*
X3223300Y-8489200D01*
X3223300Y-8459200D02*
X3193300Y-8489200D01*
X3347830Y-9801000D02*
X3377830Y-9831000D01*
X3377830Y-9801000D02*
X3347830Y-9831000D01*
X3500000Y-9028620D02*
X3530000Y-9058620D01*
X3530000Y-9028620D02*
X3500000Y-9058620D01*
X3790470Y-8952870D02*
X3820470Y-8982870D01*
X3820470Y-8952870D02*
X3790470Y-8982870D01*
X1288000Y-5184000D02*
G75*
G02*
@@ -984,16 +1036,12 @@ X3672325Y-10567555D02*
X3653277Y-10586603D01*
X3653277Y-10586603D02*
X3634229Y-10596127D01*
X3938991Y-10738984D02*
X3824706Y-10738984D01*
X3881848Y-10738984D02*
X3881848Y-10538984D01*
X3881848Y-10538984D02*
X3862801Y-10567555D01*
X3862801Y-10567555D02*
X3843753Y-10586603D01*
X3843753Y-10586603D02*
X3824706Y-10596127D01*
X3919944Y-10605650D02*
X3919944Y-10738984D01*
X3872325Y-10529460D02*
X3824706Y-10672317D01*
X3824706Y-10672317D02*
X3948515Y-10672317D01*
X4177087Y-10738984D02*
X4177087Y-10538984D01*
X4262801Y-10738984D02*
+1 -1
View File
@@ -5,7 +5,7 @@
"Application": "Pcbnew",
"Version": "9.0.2+dfsg-1"
},
"CreationDate": "2026-01-23T08:01:42+01:00"
"CreationDate": "2026-01-23T08:14:38+01:00"
},
"GeneralSpecs": {
"ProjectId": {
+11 -8
View File
@@ -1,7 +1,7 @@
M48
; DRILL file {KiCad 9.0.2+dfsg-1} date 2026-01-23T08:01:45+0100
; DRILL file {KiCad 9.0.2+dfsg-1} date 2026-01-23T08:14:39+0100
; FORMAT={-:-/ absolute / metric / decimal}
; #@! TF.CreationDate,2026-01-23T08:01:45+01:00
; #@! TF.CreationDate,2026-01-23T08:14:39+01:00
; #@! TF.GenerationSoftware,Kicad,Pcbnew,9.0.2+dfsg-1
; #@! TF.FileFunction,MixedPlating,1,2
FMAT,2
@@ -21,16 +21,19 @@ G90
G05
T1
X2.0Y-90.578
X2.95Y-83.556
X2.95Y-83.596
X4.0Y-81.824
X7.526Y-94.232
X10.0Y-83.556
X10.657Y-92.358
X24.0Y-83.998
X10.0Y-83.596
X10.0Y-90.54
X11.008Y-86.838
X24.0Y-87.735
X24.308Y-83.596
X26.0Y-95.962
X29.051Y-89.092
X28.776Y-89.367
X32.083Y-84.742
X33.628Y-98.16
X35.15Y-90.436
X38.055Y-89.679
T2
X12.38Y-51.84
X12.38Y-54.38
+32
View File
@@ -33,6 +33,15 @@ DRC_FILE = "DRC.rpt"
FREEROUTING_JAR = "/tmp/freerouting.jar"
FREEROUTING_URL = "https://github.com/freerouting/freerouting/releases/download/v2.0.1/freerouting-2.0.1.jar"
# Mounting hole positions (M3, 3.2mm diameter)
# Bottom holes moved up to avoid power section
MOUNTING_HOLES = [
(5, 5), # Top left
(35, 5), # Top right
(5, 75), # Bottom left (above power section)
(35, 75), # Bottom right (above power section)
]
# Component positions for 8HP (40mm x 100mm) layout v2
PLACEMENTS = {
# Top - OLED display
@@ -124,6 +133,29 @@ def main():
placed += 1
print(f" Placed {placed} components")
# Step 4b: Add mounting holes
print("\n[4b/9] Adding mounting holes...")
# Remove existing mounting holes first
for drawing in list(board.GetDrawings()):
if drawing.GetClass() == "PCB_SHAPE":
if drawing.GetShape() == pcbnew.SHAPE_T_CIRCLE:
# Check if it's a mounting hole (on Edge.Cuts, 3.2mm diameter)
if drawing.GetLayer() == pcbnew.Edge_Cuts:
radius = pcbnew.ToMM(drawing.GetRadius())
if 1.5 < radius < 1.7: # ~3.2mm diameter
board.Delete(drawing)
# Add new mounting holes
for x, y in MOUNTING_HOLES:
hole = pcbnew.PCB_SHAPE(board)
hole.SetShape(pcbnew.SHAPE_T_CIRCLE)
hole.SetCenter(place(x, y))
hole.SetEnd(place(x + 1.6, y)) # Radius = 1.6mm (3.2mm diameter)
hole.SetLayer(pcbnew.Edge_Cuts)
hole.SetWidth(mm(0.15))
board.Add(hole)
print(f" Added {len(MOUNTING_HOLES)} mounting holes (M3, 3.2mm)")
# Step 5: Export DSN
print("\n[5/9] Exporting Specctra DSN...")
board.Save(PCB_FILE) # Save first
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
"""
SN-L00 Command-Line Autoroute Pipeline
Run from terminal: python3 scripts/autoroute_cli.py
Requires: kicad-cli or pcbnew Python module available
"""
import subprocess
import os
import sys
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
KICAD_DIR = os.path.dirname(SCRIPT_DIR)
PCB_FILE = os.path.join(KICAD_DIR, "SN-L00.kicad_pcb")
DSN_FILE = os.path.join(KICAD_DIR, "SN-L00.dsn")
SES_FILE = os.path.join(KICAD_DIR, "SN-L00.ses")
FREEROUTING_JAR = "/tmp/freerouting.jar"
FREEROUTING_URL = "https://github.com/freerouting/freerouting/releases/download/v2.0.1/freerouting-2.0.1.jar"
def run(cmd, desc, cwd=None):
"""Run command with description"""
print(f" {desc}...")
result = subprocess.run(cmd, capture_output=True, text=True, cwd=cwd)
if result.returncode != 0:
print(f" ERROR: {result.stderr}")
return False
return True
def main():
print("=" * 50)
print("SN-L00 Command-Line Autoroute Pipeline")
print("=" * 50)
# Check for kicad-cli
kicad_cli = None
for path in ["/usr/bin/kicad-cli", "/usr/local/bin/kicad-cli",
"/Applications/KiCad/KiCad.app/Contents/MacOS/kicad-cli"]:
if os.path.exists(path):
kicad_cli = path
break
if not kicad_cli:
# Try to find in PATH
result = subprocess.run(["which", "kicad-cli"], capture_output=True, text=True)
if result.returncode == 0:
kicad_cli = result.stdout.strip()
if not kicad_cli:
print("ERROR: kicad-cli not found. Please run in KiCad scripting console instead:")
print(" exec(open('scripts/autoroute_full.py').read())")
sys.exit(1)
print(f"Using: {kicad_cli}")
# Step 1: Run placement script in KiCad
print("\n[1/4] Placing components...")
# kicad-cli pcb export dsn also runs any embedded scripts, but we need
# to place first. For now, assume placement was done or use Python API
print(" (Run place_8hp.py in KiCad first, or components should already be placed)")
# Step 2: Export DSN
print("\n[2/4] Exporting DSN...")
if not run([kicad_cli, "pcb", "export", "dsn", "-o", DSN_FILE, PCB_FILE],
"Exporting Specctra DSN"):
sys.exit(1)
print(f" Created: {DSN_FILE}")
# Step 3: Download Freerouting if needed
print("\n[3/4] Running Freerouting...")
if not os.path.exists(FREEROUTING_JAR):
print(" Downloading Freerouting...")
if not run(["curl", "-L", "-o", FREEROUTING_JAR, FREEROUTING_URL],
"Downloading"):
sys.exit(1)
# Run Freerouting
result = subprocess.run(
["java", "-jar", FREEROUTING_JAR,
"-de", DSN_FILE,
"-do", SES_FILE,
"-mp", "200",
"-mt", "1",
"-oit"],
capture_output=True,
text=True,
cwd=KICAD_DIR
)
if result.returncode != 0:
print(f" Freerouting error: {result.stderr}")
sys.exit(1)
# Parse output for timing
for line in result.stdout.split('\n') + result.stderr.split('\n'):
if 'completed' in line.lower():
print(f" {line.split(']')[-1].strip()}")
print(f" Created: {SES_FILE}")
# Step 4: Import SES
print("\n[4/4] Importing routed session...")
if not run([kicad_cli, "pcb", "import", "ses", "-i", SES_FILE, PCB_FILE],
"Importing Specctra session"):
# kicad-cli might not support import, manual step needed
print(" NOTE: Import via kicad-cli may not be supported.")
print(" In KiCad: File → Import → Specctra Session")
else:
print(f" Imported routes into: {PCB_FILE}")
print("\n" + "=" * 50)
print("DONE! Open PCB in KiCad and run DRC to verify.")
print("=" * 50)
if __name__ == "__main__":
main()
+293
View File
@@ -0,0 +1,293 @@
#!/usr/bin/env python3
"""
SN-L00 Headless Autoroute Pipeline
Fully automated: place → export DSN → freeroute → import SES → DRC
Usage:
# Install dependencies first:
sudo apt install xvfb
pip install kigadgets
# Run:
python3 scripts/autoroute_headless.py
Based on: https://github.com/atait/kicad-python
"""
import os
import sys
import subprocess
import tempfile
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
KICAD_DIR = os.path.dirname(SCRIPT_DIR)
PCB_FILE = os.path.join(KICAD_DIR, "SN-L00.kicad_pcb")
DSN_FILE = os.path.join(KICAD_DIR, "SN-L00.dsn")
SES_FILE = os.path.join(KICAD_DIR, "SN-L00.ses")
DRC_FILE = os.path.join(KICAD_DIR, "DRC.rpt")
FREEROUTING_JAR = "/tmp/freerouting.jar"
# Component positions for 8HP (40mm x 100mm) layout v2
PLACEMENTS = {
"MOD3": (20, 15, 90),
"J3": (10, 35, 0),
"J4": (30, 35, 0),
"SW1": (20, 48, 0),
"D5": (32, 48, 0),
"MOD2": (20, 62, 0),
"U2": (8, 78, 0),
"U4": (32, 78, 0),
"C4": (4, 78, 90),
"C5": (14, 78, 90),
"C6": (28, 82, 90),
"D3": (4, 82, 0),
"D4": (36, 78, 0),
"R2": (4, 86, 90),
"R3": (10, 86, 90),
"R4": (16, 86, 90),
"R5": (24, 86, 90),
"R6": (30, 86, 90),
"R7": (36, 86, 90),
"J2": (20, 88, 0),
"D2": (4, 92, 0),
"U3": (32, 94, 180),
"C2": (10, 94, 90),
"C3": (26, 94, 90),
}
def check_dependencies():
"""Check if required tools are available."""
missing = []
# Check xvfb
if subprocess.run(["which", "xvfb-run"], capture_output=True).returncode != 0:
missing.append("xvfb (sudo apt install xvfb)")
# Check java
if subprocess.run(["which", "java"], capture_output=True).returncode != 0:
missing.append("java (sudo apt install default-jre)")
# Check kicad-cli
if subprocess.run(["which", "kicad-cli"], capture_output=True).returncode != 0:
missing.append("kicad-cli (install KiCad)")
if missing:
print("Missing dependencies:")
for dep in missing:
print(f" - {dep}")
sys.exit(1)
def download_freerouting():
"""Download Freerouting if not present."""
if not os.path.exists(FREEROUTING_JAR):
print("Downloading Freerouting...")
url = "https://github.com/freerouting/freerouting/releases/download/v2.0.1/freerouting-2.0.1.jar"
subprocess.run(["curl", "-L", "-o", FREEROUTING_JAR, url], check=True)
def run_pcbnew_script(script_content):
"""Run a Python script inside pcbnew using xvfb."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
f.write(script_content)
script_path = f.name
try:
# Run pcbnew with xvfb, execute script, then exit
# This is a workaround since pcbnew doesn't have a direct script execution mode
result = subprocess.run(
["xvfb-run", "-a", "python3", "-c", f"""
import sys
sys.path.insert(0, '/usr/lib/python3/dist-packages')
try:
import pcbnew
exec(open('{script_path}').read())
except Exception as e:
print(f"Error: {{e}}")
sys.exit(1)
"""],
capture_output=True,
text=True,
timeout=120
)
print(result.stdout)
if result.stderr:
print(result.stderr)
return result.returncode == 0
finally:
os.unlink(script_path)
def place_and_export():
"""Place components and export DSN using pcbnew API."""
script = f'''
import pcbnew
board = pcbnew.LoadBoard("{PCB_FILE}")
def mm(val):
return pcbnew.FromMM(val)
def place(x, y):
return pcbnew.VECTOR2I(mm(x), mm(y))
# Update board outline
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")
break
# Delete tracks
tracks = list(board.GetTracks())
for track in tracks:
board.Delete(track)
print(f"Deleted {{len(tracks)}} tracks")
# Place components
placements = {repr(PLACEMENTS)}
placed = 0
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"Placed {{placed}} components")
# Save board
board.Save("{PCB_FILE}")
print("Saved board")
# Export DSN
try:
result = pcbnew.ExportSpecctraDSN("{DSN_FILE}")
if result:
print("Exported DSN")
else:
print("DSN export returned False - trying alternate method")
# Try with board parameter
result = pcbnew.ExportSpecctraDSN(board, "{DSN_FILE}")
print(f"Alternate export result: {{result}}")
except Exception as e:
print(f"DSN export error: {{e}}")
'''
return run_pcbnew_script(script)
def run_freerouting():
"""Run Freerouting autorouter."""
print("Running Freerouting...")
result = subprocess.run(
["java", "-jar", FREEROUTING_JAR,
"-de", DSN_FILE,
"-do", SES_FILE,
"-mp", "200",
"-mt", "1",
"-oit"],
capture_output=True,
text=True,
cwd=KICAD_DIR
)
for line in (result.stdout + result.stderr).split('\n'):
if 'completed' in line.lower() or 'error' in line.lower():
print(f" {line.split(']')[-1].strip()}")
return os.path.exists(SES_FILE)
def import_ses():
"""Import SES file using pcbnew API."""
script = f'''
import pcbnew
board = pcbnew.LoadBoard("{PCB_FILE}")
try:
result = pcbnew.ImportSpecctraSES("{SES_FILE}")
if result:
print("Imported SES")
board.Save("{PCB_FILE}")
print("Saved board")
else:
print("SES import returned False - trying alternate method")
result = pcbnew.ImportSpecctraSES(board, "{SES_FILE}")
if result:
board.Save("{PCB_FILE}")
print("Saved board")
except Exception as e:
print(f"SES import error: {{e}}")
'''
return run_pcbnew_script(script)
def run_drc():
"""Run DRC using kicad-cli."""
print("Running DRC...")
result = subprocess.run(
["kicad-cli", "pcb", "drc",
"--severity-all",
"--units", "mm",
"-o", DRC_FILE,
PCB_FILE],
capture_output=True,
text=True
)
print(result.stdout)
# Count errors
if os.path.exists(DRC_FILE):
with open(DRC_FILE) as f:
content = f.read()
errors = content.count('; error')
warnings = content.count('; warning')
print(f"DRC: {errors} errors, {warnings} warnings")
return errors == 0
return False
def main():
print("=" * 50)
print("SN-L00 Headless Autoroute Pipeline")
print("=" * 50)
check_dependencies()
download_freerouting()
print("\n[1/4] Placing components and exporting DSN...")
if not place_and_export():
print("Failed to place/export")
# Fall back to manual DSN check
if not os.path.exists(DSN_FILE):
print(f"ERROR: {DSN_FILE} not found")
print("Export manually: File → Export → Specctra DSN")
sys.exit(1)
print("\n[2/4] Running Freerouting...")
if not run_freerouting():
print("Freerouting failed")
sys.exit(1)
print("\n[3/4] Importing routed session...")
if not import_ses():
print("SES import failed - import manually in KiCad")
print("\n[4/4] Running DRC...")
success = run_drc()
print("\n" + "=" * 50)
if success:
print("SUCCESS! Board routed with no DRC errors.")
else:
print("Done. Check DRC.rpt for remaining issues.")
print("=" * 50)
if __name__ == "__main__":
main()
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""
SN-L00 Component Placement Script for 6HP Eurorack
Board at origin (0,0) to (28,100)
Run in KiCad PCB Editor: Tools → Scripting Console
Then: exec(open('scripts/place_6hp.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))
# Component positions for 6HP (28mm x 100mm) layout
# Board origin at (0,0), components placed relative to that
placements = {
# Top - OLED display (rotated 90°, 13mm wide when rotated)
"MOD3": (14, 18, 90),
# Audio jacks
"J3": (7, 40, 0), # RETURN_IN
"J4": (21, 40, 0), # TRIG_OUT
# Button
"SW1": (14, 54, 0),
# RP2040-Zero module
"MOD2": (14, 70, 0),
# Signal conditioning ICs
"U2": (6, 85, 0), # 74LVC1G17
"U4": (22, 85, 0), # MCP6001
# Resistors
"R2": (3, 90, 0),
"R3": (7, 90, 0),
"R4": (11, 90, 0),
"R5": (15, 90, 0),
"R6": (19, 90, 0),
"R7": (23, 90, 0),
# Decoupling caps
"C4": (3, 85, 90),
"C5": (11, 85, 90),
"C6": (25, 85, 90),
# LED
"D5": (25, 90, 0),
# Protection diodes
"D3": (6, 94, 0),
"D4": (22, 94, 0),
# Power section
"J2": (14, 94, 0), # Eurorack power header
"D2": (3, 94, 90), # Protection diode
"U3": (25, 94, 180), # LDO - moved right
"C2": (3, 90, 90), # Input cap
"C3": (25, 90, 90), # Output cap - moved right
}
print("Placing components for 6HP Eurorack layout...")
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 export DSN for routing.")
+66 -70
View File
@@ -9,9 +9,7 @@
| Thickness | 1.5-2.0mm | Aluminum or PCB |
| Corner radius | 0mm | Square corners |
## Mounting Holes
Eurorack standard mounting rail positions:
## Mounting Holes (Eurorack Rails)
| Hole | X | Y | Diameter | Notes |
|------|---|---|----------|-------|
@@ -22,51 +20,78 @@ Eurorack standard mounting rail positions:
**Note**: Slots (elongated holes) of 3.2mm × 4mm allow for rail tolerance.
## PCB Mounting
The PCB (40×100mm) mounts horizontally behind the panel.
| Parameter | Value | Notes |
|-----------|-------|-------|
| PCB offset from panel top | 10mm | PCB top edge at panel Y=10mm |
| PCB offset from panel bottom | 18.5mm | Clearance for power header |
| Standoff length | 10mm | M3 hex standoffs |
| Standoff holes | 3.2mm | M3 clearance |
### Standoff Mounting Holes
| Hole | Panel X | Panel Y | PCB X | PCB Y |
|------|---------|---------|-------|-------|
| Top Left | 5mm | 15mm | 5mm | 5mm |
| Top Right | 35mm | 15mm | 35mm | 5mm |
| Bottom Left | 5mm | 85mm | 5mm | 75mm |
| Bottom Right | 35mm | 85mm | 35mm | 75mm |
Note: Bottom holes positioned above power section for routing clearance.
## Component Holes
| Component | X | Y | Diameter | Notes |
|-----------|---|---|----------|-------|
| OLED cutout | 20.15mm | 25.0mm | 28×12mm rect | Rectangular window |
| Button | 20.15mm | 50.0mm | 7.0mm | For 6mm tactile + cap |
| LED (status) | 32.0mm | 50.0mm | 3.0mm | For 3mm LED or light pipe |
| Jack RETURN | 10.0mm | 95.0mm | 6.0mm | Thonkiconn PJ398SM |
| Jack TRIG | 30.0mm | 95.0mm | 6.0mm | Thonkiconn PJ398SM |
All positions aligned with PCB layout (PCB offset = 10mm).
| Component | Panel X | Panel Y | Diameter | Notes |
|-----------|---------|---------|----------|-------|
| OLED cutout | 20mm | 25mm | 28×12mm rect | Rectangular window |
| Jack RETURN | 10mm | 45mm | 6.0mm | Thonkiconn PJ398SM |
| Jack TRIG | 30mm | 45mm | 6.0mm | Thonkiconn PJ398SM |
| Button | 20mm | 58mm | 7.0mm | For 6mm tactile + cap |
| LED (status) | 32mm | 58mm | 3.0mm | For 3mm LED or light pipe |
## Panel Layout Drawing
```
←─────── 40.30mm ───────→
┌───────────────────────────┐ ─┬─ 0.00mm
│ ○ ○ │ │ 3.00mm (mounting holes)
│ │ │
│ SubModular │ │ 12.00mm
┌───────────────────────────┐ ─┬─ 0mm
│ ○ ○ │ │ 3mm (rail mounting holes)
│ │ │
│ SubModular │ │ 12mm
│ · · │ │ 15mm (standoff holes)
│ ┌─────────────────┐ │ │
│ │ │ │ │
│ │ OLED │ │ │ 19-31mm (display window)
│ │ OLED │ │ │ 19-31mm (display window @ 25mm)
│ │ DISPLAY │ │ │
│ │ │ │ │
│ └─────────────────┘ │ │
│ │ │
│ SN-L00 │ │ 42.00mm
│ │ │
│ ◯ • │ │ 50.00mm (button + LED)
│ BTN PWR │ │
│ │ │
│ │ │
│ │ │
│ ┌───┐ ┌───┐ │ │
│ │ │ │ │ │ │
│ │ ○ │ │ ○ │ │ │ 95.00mm (jacks)
│ │ ○ │ │ ○ │ │ │ 45mm (jacks)
│ │ │ │ │ │ │
│ └───┘ └───┘ │ │
│ RETURN TRIG │ │ 105.00mm (labels)
│ RETURN TRIG │ │ 52mm (labels)
│ │ │
LATENCY TESTER │ │ 115.00mm
│ │ 58mm (button + LED)
│ BTN PWR │ │
│ │ │
│ │ 125.50mm (mounting holes)
└───────────────────────────┘ ─┴─ 128.50mm
SN-L00 │ │ 72mm
│ │ │
│ │ │
│ │ │
│ LATENCY TESTER │ │ 95mm
│ │ │
│ · · │ │ 85mm (standoff holes)
│ │ │
│ │ │
│ ○ ○ │ │ 125.5mm (rail mounting holes)
└───────────────────────────┘ ─┴─ 128.5mm
```
## OLED Display Window
@@ -79,9 +104,7 @@ The 0.91" 128×32 OLED module dimensions:
| Active area | ~22 × 6mm |
| Mounting | Pin header on edge |
**Panel cutout**: 28mm × 10mm rectangle, centered at (20.15, 25.0)
Alternatively, a slightly larger window (30 × 12mm) gives tolerance for module alignment.
**Panel cutout**: 28mm × 12mm rectangle, centered at (20mm, 25mm)
## Material Options
@@ -106,47 +129,20 @@ Alternatively, a slightly larger window (30 × 12mm) gives tolerance for module
- Printing: Engraved or adhesive labels
- Cost: ~€3-5/panel
## PCB Panel Design
## Hardware Required
If using a PCB as the panel:
```
Front copper: None (for clean look) or decorative pattern
Back copper: Optional ground plane
Silkscreen: All text and graphics
Soldermask: Black (or custom color)
```
## Graphics & Text
### Suggested Layout
| Element | Position | Size | Font |
|---------|----------|------|------|
| "SubModular" | Top center, Y=12mm | 2.5mm | Bold sans-serif |
| "SN-L00" | Above button, Y=42mm | 3.0mm | Bold |
| "RETURN" | Below left jack, Y=105mm | 2.0mm | Regular |
| "TRIG" | Below right jack, Y=105mm | 2.0mm | Regular |
| "LATENCY TESTER" | Bottom, Y=115mm | 1.5mm | Light |
## Hole Tolerances
| Hole Type | Nominal | Tolerance |
|-----------|---------|-----------|
| Mounting | 3.2mm | +0.1/-0.0 |
| Jack | 6.0mm | +0.1/-0.0 |
| Button | 7.0mm | +0.2/-0.0 |
| LED | 3.0mm | +0.1/-0.0 |
## Files
- **PANEL_SPEC.md** - This file
- **SN-L00_panel.svg** - Vector graphic for manufacturing
- **SN-L00_panel.kicad_pcb** - PCB panel (if using FR4)
| Item | Qty | Notes |
|------|-----|-------|
| M3×10mm standoff | 4 | Hex, male-female |
| M3×6mm screw | 4 | Pan head, for PCB side |
| M3 nut | 4 | Or use female-female standoffs |
| Thonkiconn nut | 2 | Included with jacks |
## Assembly
1. Mount OLED module with M2 standoffs or double-sided tape
2. Jacks mount through panel, secured with nut
3. Button may need extension shaft or cap
4. LED can use light pipe for front visibility
1. Insert standoffs through panel holes, secure with nuts on front
2. Mount jacks through panel, finger-tighten nuts
3. Align PCB with standoffs and jack pins
4. Secure PCB to standoffs with M3 screws
5. Fully tighten jack nuts
6. Attach OLED module to PCB header
+32 -27
View File
@@ -4,13 +4,14 @@
viewBox="0 0 40.30 128.5">
<title>SN-L00 Eurorack Panel</title>
<desc>8HP Eurorack panel for SN-L00 Latency Tester</desc>
<desc>8HP Eurorack panel for SN-L00 Latency Tester - aligned with PCB</desc>
<defs>
<style>
.panel { fill: #1a1a1a; }
.hole { fill: none; stroke: #ff0000; stroke-width: 0.1; }
.cutout { fill: none; stroke: #00ff00; stroke-width: 0.1; }
.standoff { fill: none; stroke: #0000ff; stroke-width: 0.1; }
.text { fill: #ffffff; font-family: Arial, sans-serif; }
.text-small { font-size: 2px; }
.text-medium { font-size: 2.5px; }
@@ -22,51 +23,55 @@
<!-- Panel background -->
<rect class="panel" x="0" y="0" width="40.30" height="128.5"/>
<!-- Mounting holes (3.2mm) - RED for drill -->
<!-- Top mounting holes -->
<!-- Eurorack rail mounting holes (3.2mm) - RED -->
<circle class="hole" cx="7.5" cy="3" r="1.6"/>
<circle class="hole" cx="32.8" cy="3" r="1.6"/>
<!-- Bottom mounting holes -->
<circle class="hole" cx="7.5" cy="125.5" r="1.6"/>
<circle class="hole" cx="32.8" cy="125.5" r="1.6"/>
<!-- OLED display window (28x10mm rectangle) - GREEN for cutout -->
<rect class="cutout" x="6.15" y="20" width="28" height="10" rx="0.5"/>
<!-- PCB standoff mounting holes (3.2mm) - BLUE -->
<circle class="standoff" cx="5" cy="15" r="1.6"/>
<circle class="standoff" cx="35" cy="15" r="1.6"/>
<circle class="standoff" cx="5" cy="85" r="1.6"/>
<circle class="standoff" cx="35" cy="85" r="1.6"/>
<!-- Button hole (7mm) -->
<circle class="hole" cx="20.15" cy="50" r="3.5"/>
<!-- OLED display window (28x12mm rectangle) - GREEN -->
<rect class="cutout" x="6" y="19" width="28" height="12" rx="0.5"/>
<!-- LED hole (3mm) -->
<circle class="hole" cx="32" cy="50" r="1.5"/>
<!-- Jack holes (6mm) - RED -->
<circle class="hole" cx="10" cy="45" r="3"/>
<circle class="hole" cx="30" cy="45" r="3"/>
<!-- Jack holes (6mm) -->
<circle class="hole" cx="10" cy="95" r="3"/>
<circle class="hole" cx="30" cy="95" r="3"/>
<!-- Button hole (7mm) - RED -->
<circle class="hole" cx="20" cy="58" r="3.5"/>
<!-- LED hole (3mm) - RED -->
<circle class="hole" cx="32" cy="58" r="1.5"/>
<!-- Text labels - WHITE silkscreen -->
<text class="text text-medium" x="20.15" y="12" text-anchor="middle">SubModular</text>
<text class="text text-large" x="20.15" y="42" text-anchor="middle" font-weight="bold">SN-L00</text>
<text class="text text-small" x="10" y="52" text-anchor="middle">RETURN</text>
<text class="text text-small" x="30" y="52" text-anchor="middle">TRIG</text>
<text class="text text-small" x="20.15" y="57" text-anchor="middle">BTN</text>
<text class="text text-small" x="32" y="57" text-anchor="middle">PWR</text>
<text class="text text-small" x="20" y="65" text-anchor="middle">BTN</text>
<text class="text text-small" x="32" y="65" text-anchor="middle">PWR</text>
<text class="text text-small" x="10" y="105" text-anchor="middle">RETURN</text>
<text class="text text-small" x="30" y="105" text-anchor="middle">TRIG</text>
<text class="text text-large" x="20.15" y="75" text-anchor="middle" font-weight="bold">SN-L00</text>
<text class="text text-small" x="20.15" y="115" text-anchor="middle">LATENCY TESTER</text>
<text class="text text-small" x="20.15" y="98" text-anchor="middle">LATENCY TESTER</text>
<!-- Decorative elements -->
<!-- Jack nut indicators (circles around jacks) -->
<circle class="silkscreen" cx="10" cy="95" r="5"/>
<circle class="silkscreen" cx="30" cy="95" r="5"/>
<!-- Jack nut indicators -->
<circle class="silkscreen" cx="10" cy="45" r="5"/>
<circle class="silkscreen" cx="30" cy="45" r="5"/>
<!-- Display frame -->
<rect class="silkscreen" x="5.65" y="19.5" width="29" height="11" rx="0.5"/>
<rect class="silkscreen" x="5.5" y="18.5" width="29" height="13" rx="0.5"/>
<!-- Horizontal lines for visual separation -->
<line class="silkscreen" x1="4" y1="60" x2="36.30" y2="60"/>
<line class="silkscreen" x1="4" y1="85" x2="36.30" y2="85"/>
<line class="silkscreen" x1="4" y1="110" x2="36.30" y2="110"/>
<!-- Horizontal separator lines -->
<line class="silkscreen" x1="4" y1="38" x2="36" y2="38"/>
<line class="silkscreen" x1="4" y1="68" x2="36" y2="68"/>
<line class="silkscreen" x1="4" y1="102" x2="36" y2="102"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB