-
Notifications
You must be signed in to change notification settings - Fork 0
/
tc2-panel.py
210 lines (171 loc) · 6.39 KB
/
tc2-panel.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# flatpak run --command=bash org.kicad.KiCad
from kikit import panelize
from kikit import panelize_ui_impl as ki
from kikit.units import mm, deg
from kikit.panelize import Panel, BasicGridPosition, Origin
from pcbnewTransition.pcbnew import LoadBoard, VECTOR2I
from pcbnewTransition import pcbnew
from itertools import chain
from kikit.units import mm
import os
from shapely.geometry import Polygon
# Custom config
main_board_path = "tc2-main-pcb/tc2-main-pcb.kicad_pcb"
plugs_board_path = "tc2-plugs-buck-boost-pcb/tc2-plugs-buck-boost-pcb.kicad_pcb"
sim_board_path = "tc2-sim-usb-pcb/tc2-sim-usb-pcb.kicad_pcb"
touch_board_path = "tc2-touch-sensor/tc2-touch-sensor.kicad_pcb"
output_dir = "generated-pcbs/tc2-panel"
output_path = f"{output_dir}/tc2-panel.kicad_pcb"
os.makedirs(output_dir, exist_ok=True)
board_spacing = 3*mm
## Check kikit cli for defaults https://yaqwsx.github.io/KiKit/latest/panelization/cli/
framing={
"type": "frame", # One of none, railstb (top/bottom), railslr (left/right), frame, tightframe
"vspace": "2.5mm", # Min of 2mm for PCBA at JLCPCB
"hspace": "2.5mm", # Min of 2mm for PCBA at JLCPCB
"width": "5mm", # Min width of 5mm for PCBA at JLCPCB
}
cuts = {
"type": "mousebites",
"drill": "0.6mm", # Minimum mouse bite holes
"spacing": "0.9mm", # Minimum mouse bite spacing (0.3mm between holes)
"offset": "-0.3mm", # Offset of mouse bite holes into the mouse bite. -0.12mm gives enough clearance for traces/copper on the edge of the PCB for the DRM.
}
tabs = {
"type":"annotation", # Use annotations in the PCBs for the placement of the tabs.
"fillet": "1mm", # Required for manufacturability of the tabs.
}
tooling = {
"type": "4hole",
"hoffset": "3mm",
"voffset": "3mm",
"size": "2mm", # JLCPCB requires 2mm tooling holes
}
fiducials = {
"type": "4fid",
"hoffset": "3.85mm", # JLCPCB requires fids 3.85mm from edge
"voffset": "6mm",
}
post = {
"millradius": "1mm" # Will add fillets when needed for manufacturability.
}
copperfill = {
"type": "solid", # Sometimes needed for manufacturability (lower than 30% copper fill can increase min trace width)
"layers": "all",
}
preset = ki.obtainPreset([],
tabs=tabs,
cuts=cuts,
framing=framing,
tooling=tooling,
post=post,
fiducials=fiducials,
copperfill=copperfill,
)
board1 = LoadBoard(main_board_path)
board2 = LoadBoard(plugs_board_path)
board3 = LoadBoard(sim_board_path)
board4 = LoadBoard(touch_board_path)
panel = Panel(output_path)
# Inherit settings from board2
panel.inheritDesignSettings(board2)
panel.inheritProperties(board2)
panel.inheritTitleBlock(board2)
### Build layout of boards for panel.
# Get source areas for the boards.
sourceArea1 = ki.readSourceArea(preset["source"], board1)
sourceArea2 = ki.readSourceArea(preset["source"], board2)
sourceArea3 = ki.readSourceArea(preset["source"], board3)
sourceArea4 = ki.readSourceArea(preset["source"], board4)
# Prepare renaming nets and references.
mainRefRenamer = lambda x, orig: "{orig}".format(n=x, orig=orig)
mainNetRenamer = lambda x, orig: "{orig}-main".format(n=x, orig=orig)
plugsRefRenamer = lambda x, orig: "{orig}".format(n=x, orig=orig)
plugsNetRenamer = lambda x, orig: "{orig}-plugs".format(n=x, orig=orig)
simRefRenamer = lambda x, orig: "{orig}".format(n=x, orig=orig)
simNetRenamer = lambda x, orig: "{orig}-sim".format(n=x, orig=orig)
touchRefRenamer = lambda x, orig: "{orig}".format(n=x, orig=orig)
touchNetRenamer = lambda x, orig: "{orig}-touch".format(n=x, orig=orig)
# Place the boards in the panel. The origin is the center of each board.
# If needing to rotate a board you can add `rotationAngle=deg*90` as a parameter.
panel.appendBoard(
main_board_path,
pcbnew.wxPointMM(0, 0),
sourceArea=sourceArea1,
netRenamer=mainNetRenamer,
refRenamer=mainRefRenamer,
bufferOutline=100000,
inheritDrc=False,
)
panel.appendBoard(
plugs_board_path,
pcbnew.wxPointMM(4+1.75-4, -50),
sourceArea=sourceArea2,
netRenamer=plugsNetRenamer,
refRenamer=plugsRefRenamer,
inheritDrc=True,
)
panel.appendBoard(
sim_board_path,
pcbnew.wxPointMM(-4, -73),
rotationAngle=deg*270,
sourceArea=sourceArea3,
netRenamer=simNetRenamer,
refRenamer=simRefRenamer,
inheritDrc=False,
)
panel.appendBoard(
touch_board_path,
pcbnew.wxPointMM(-1, -73-25),
#rotationAngle=deg*270,
sourceArea=sourceArea4,
netRenamer=touchNetRenamer,
refRenamer=touchRefRenamer,
inheritDrc=False,
)
# Add substrate on left edge for attaching tabs to. Otherwise the tabs are too far from the edge and won't be created.
x1 = -40*mm
y1 = -75*mm
x2 = -37*mm
y2 = 5*mm
substrate = Polygon([(x1, y1), (x1, y2), (x2, y2), (x2, y1)])
panel.appendSubstrate(substrate)
# Add substrate on left edge for attaching tabs to. Otherwise the tabs are too far from the edge and won't be created.
x1 = 40*mm
y1 = -64*mm
x2 = 33*mm
y2 = -104*mm
substrate = Polygon([(x1, y1), (x1, y2), (x2, y2), (x2, y1)])
panel.appendSubstrate(substrate)
"""
# Add substrate on left edge for attaching tabs to. Otherwise the tabs are too far from the edge and won't be created.
x1 = 42*mm
y1 = 10*mm
x2 = 64*mm
y2 = 36*mm
substrate = Polygon([(x1, y1), (x1, y2), (x2, y2), (x2, y1)])
panel.appendSubstrate(substrate)
"""
# Add mill fillets
panel.addMillFillets(panelize.fromMm(0.75))
# Build frame
ki.buildFraming(preset, panel)
framingSubstrates = ki.dummyFramingSubstrate(panel.substrates, preset)
# safeMargin set to true helps to force building tabs when they won't reach the frame.
# If this is the case then you want to add substrates to the panel with Polygon as was done above.
panel.buildPartitionLineFromBB(framingSubstrates, safeMargin=True)
backboneCuts = ki.buildBackBone(preset["layout"], panel, panel.substrates, preset)
# Debug to help visualize the layout and as to why some tabs might not be created
panel.debugRenderPartitionLines()
panel.debugRenderBoundingBoxes()
panel.debugRenderBackboneLines()
# Panelize things..
ki.buildTooling(preset, panel)
ki.buildFiducials(preset, panel)
tabCuts = ki.buildTabs(preset, panel, panel.substrates, framingSubstrates)
ki.makeTabCuts(preset, panel, tabCuts)
frameCuts = ki.buildFraming(preset, panel)
ki.makeOtherCuts(preset, panel, chain(backboneCuts, frameCuts))
ki.buildPostprocessing(preset["post"], panel)
ki.buildCopperfill(preset["copperfill"], panel)
panel.save()