diff --git a/panelize.py b/panelize.py new file mode 100755 index 0000000..fadb74e --- /dev/null +++ b/panelize.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 + +from kikit import panelize, substrate +import kikit.common +from kikit.units import mm, deg +from kikit.defs import Layer +from kikit import panelize_ui_impl as ki +import shapely +import shapely.geometry +import pcbnew +import sys +import itertools + + +def main(): + pcb_filename = "SH-ESP32-engine-hat.kicad_pcb" + panel_filename = "SH-ESP32-engine-hat-panel.kicad_pcb" + + n_panel_rows = 2 + n_panel_columns = 5 + + frame_width = 6 * mm + rail_width = frame_width + hor_backbone_width = 3 * mm + ver_backbone_width = 4 * mm + + tab_width = 2 * mm + backbone_cut_width = tab_width + + hor_board_spacing = ver_backbone_width + 2 * tab_width + ver_board_spacing = hor_backbone_width + 2 * tab_width + + frame_hor_space = tab_width + frame_ver_space = tab_width + + frame_hor_offset = tab_width + frame_ver_offset = tab_width + + tooling_hor_offset = frame_width / 2 + tooling_ver_offset = frame_width / 2 + tooling_hole_diam = 1.152 * mm + + fiducial_hor_offset = 2 * tooling_hor_offset + fiducial_ver_offset = tooling_ver_offset + fiducial_coppersize = 2 * mm + fiducial_opening = 1 * mm + + text_anchor = "mt" + text_hor_offset = 0. * mm + text_ver_offset = frame_width / 2 + text_width = 1.5 * mm + text_height = 1.5 * mm + text_thickness = int(0.3 * mm) + text_orientation = 0 * deg + text_hor_justify = "center" + text_ver_justify = "center" + + panel = panelize.Panel(panel_filename) + + first_panel_origin = pcbnew.wxPointMM(40, 40) + + # add the boards + + pcb1_source_area = pcbnew.wxRect( + pcbnew.wxPointMM(115, 53), pcbnew.wxPointMM(165, 115) + ) + + # add the first pcb + + bounding_box_1 = panel.appendBoard( + pcb_filename, + destination=first_panel_origin, + sourceArea=pcb1_source_area, + shrink=True, + origin=panelize.Origin.TopLeft, + tolerance=10 * mm, + ) + + pcb_1_x = bounding_box_1.GetX() + pcb_1_y = bounding_box_1.GetY() + pcb_1_width = bounding_box_1.GetWidth() + pcb_1_height = bounding_box_1.GetHeight() + + # add the remaining boards + + for i in range(n_panel_rows): + for j in range(n_panel_columns): + if i == 0 and j == 0: + # the first board has already been placed + continue + + pcb_origin = pcbnew.wxPoint( + pcb_1_x + j * (pcb_1_width + hor_board_spacing), + pcb_1_y + i * (pcb_1_height + ver_board_spacing), + ) + + print("pcb_origin:", pcb_origin) + + bounding_box_2 = panel.appendBoard( + pcb_filename, + destination=pcb_origin, + sourceArea=pcb1_source_area, + shrink=True, + origin=panelize.Origin.TopLeft, + tolerance=20 * mm, + ) + + # create a dummy framing substrate (required for partition lines) + + framing_substrates = ki.dummyFramingSubstrate( + panel.substrates, (frame_hor_offset, frame_ver_offset) + ) + + panel.buildPartitionLineFromBB(framing_substrates) + + # add the tabs + + tab_cuts = panel.buildTabsFromAnnotations() + + # add a backbone + + backbone_cuts = [] + backbone_cuts = panel.renderBackbone( + ver_backbone_width, hor_backbone_width, backbone_cut_width, backbone_cut_width + ) + + # add frame + + cuts = panel.makeFrame(frame_width, frame_hor_space, frame_ver_space) + frame_cuts = itertools.chain(*cuts) + + # OR add rails + + # panel.makeRailsLr(rail_width) + # frame_cuts = [] + + # round the machined cuts + + panel.addMillFillets(1.0 * mm) + + # create the tab cuts + + panel.makeMouseBites( + tab_cuts, + diameter=0.5 * mm, + spacing=0.75 * mm, + offset=0 * mm, + prolongation=0.5 * mm, + ) + + # create the backbone and frame cuts + + panel.makeMouseBites( + itertools.chain(backbone_cuts, frame_cuts), + diameter=0.5 * mm, + spacing=0.75 * mm, + offset=0, + prolongation=0.5 * mm, + ) + + # add JLCPCB tooling holes + + panel.addCornerTooling( + 4, tooling_hor_offset, tooling_ver_offset, tooling_hole_diam, paste=True + ) + + # add fiducials + + panel.addCornerFiducials( + 3, + fiducial_hor_offset, + fiducial_ver_offset, + fiducial_coppersize, + fiducial_opening, + ) + + # add JLCPCB order number + + text_origin = kikit.common.resolveAnchor(text_anchor)( + panel.boardSubstrate.boundingBox() + ) + pcbnew.wxPoint(text_hor_offset, text_ver_offset) + + text_layer = Layer.F_SilkS + + panel.addText( + text="JLCJLCJLCJLC", + position=text_origin, + orientation=text_orientation, + ) + + panel.save() + + +if __name__ == "__main__": + main() diff --git a/prepare_panel_assembly.sh b/prepare_panel_assembly.sh new file mode 100755 index 0000000..45265f0 --- /dev/null +++ b/prepare_panel_assembly.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail +shopt -s inherit_errexit + +./panelize.py + +kikit fab jlcpcb --no-drc --assembly --schematic SH-ESP32-engine-hat.kicad_sch SH-ESP32-engine-hat-panel.kicad_pcb assembly-panel