diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f691bed --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "kicad-footprint-generator"] + path = kicad-footprint-generator + url = https://gitlab.com/kicad/libraries/kicad-footprint-generator.git diff --git a/.scripts/foot_gen.py b/.scripts/foot_gen.py index 2326499..a392155 100644 --- a/.scripts/foot_gen.py +++ b/.scripts/foot_gen.py @@ -1,26 +1,31 @@ import sys import os -from pcbnew import * +import pcbnew +from pcbnew import FOOTPRINT, FP_3DMODEL, VECTOR3D, FootprintLoad, FromMM, ToMM, LoadBoard, SaveBoard, PCB_TEXT filename = sys.argv[1] +os.mkdir("test") + pcb = LoadBoard(filename) -ToUnits = ToMM -FromUnits = FromMM - -print("") -print("List drawings:") +box = pcb.GetBoardEdgesBoundingBox() +brd_cent = box.GetCenter() +brd_width = ToMM(box.GetWidth()) +brd_height = ToMM(box.GetHeight()) +print("Box: ", box) +print("W: ", brd_width, "H: ", brd_height) # layers = pcb.GetEnabledLayers() top_layer_id = pcb.GetLayerID("F.Cu") - new_foots = {} +brd_outline = [] foot_name = "" foot_path = "" +z_offset = 0 for item in pcb.GetDrawings(): if type(item) is PCB_TEXT and "User.Drawings" in item.GetLayerName(): lines = str(item.GetText()).splitlines() @@ -33,7 +38,10 @@ for item in pcb.GetDrawings(): if not lines[2].startswith("Path:"): continue foot_path = lines[2].split(":")[-1].strip() - for line in lines[3:]: + if not lines[3].startswith("Z:"): + continue + z_offset = float(lines[3].split(":")[-1].strip()) + for line in lines[4:]: sp = line.split(':', 1) if len(sp) != 2: continue @@ -53,19 +61,27 @@ for item in pcb.GetDrawings(): # pin_refs.push(int(pin)) break - elif type(item) is PCB_TEXT: - print("Text: ", item.GetText()) - print("Layer: ", item.GetLayerName()) + elif "Edge.Cuts" in item.GetLayerName(): + brd_outline.append(item) + # print("Text: ", item.GetText()) + # print("Layer: ", item.GetLayerName()) print("") print("New Footprint List: ", new_foots) + +if len(new_foots) == 0: + exit(0) + # Clear tracks pcb.Tracks().clear() # Clear zones pcb.Zones().clear() # Clear Drawings pcb.Drawings().clear() +# Add back in the outline +for d in brd_outline: + pcb.Drawings().append(d) # Keep only required foots saved = [] @@ -76,107 +92,149 @@ while len(pcb.Footprints()) > 1: # just in case pcb.DeleteAllFootprints() # Add them back -sorted_pads = [] +sorted_foots = [] for foot in saved: vals = new_foots[foot.GetReference()] # Change the footprint - foot.SetFPIDAsString(vals[0]) + path_split = vals[0].split(':') + folder = sys.path[0] + "/../../libs/melonlib/"+ path_split[0] + ".pretty" + load_foot = FootprintLoad(folder, path_split[1]) + # foot.SetFPIDAsString(vals[0]) # Save the original postion of footprint + pads orig_cent = foot.GetBoundingBox(False,False).Centre() + orig_orient = foot.GetOrientation() pads = [] for pad in foot.Pads(): - pads.append([pad.GetCenter(), pad.GetNet()]) + pads.append([pad.GetNumber(), pad.GetCenter(), pad.GetNet()]) - # Flip to other side - foot.SetLayerAndFlip(top_layer_id) + # # Flip to other side + # foot.SetLayerAndFlip(top_layer_id) # Put back in original position with an offset - box = foot.GetBoundingBox(False,False) - new_cent = foot.GetBoundingBox(False,False).Centre() + load_foot.SetOrientation(orig_orient) + new_cent = load_foot.GetBoundingBox(False,False).Centre() cent_diff = orig_cent - new_cent - foot.SetX(foot.GetX() + cent_diff.x + vals[1][0]) - foot.SetY(foot.GetY() + cent_diff.y + vals[1][1]) + load_foot.SetX(load_foot.GetX() + cent_diff.x + vals[1][0]) + load_foot.SetY(load_foot.GetY() + cent_diff.y + vals[1][1]) # Flip the net assignments of the pads - for pad in foot.Pads(): - sorted_pads.append(pad) + pad_map = {} + for pad in load_foot.Pads(): # Check position diff from old # to new new_cent = pad.GetCenter() diffs = [] - for [old_cent,_] in pads: + for [_, old_cent,_] in pads: diffs.append(new_cent - old_cent) min_diff = min(diffs) # If pad is within 0.05mm it's a match if (min_diff.x**2 + min_diff.y**2)**0.5 < 50000: # Set the net to what the old pad was i = diffs.index(min_diff) - match_pad = pads[i][1:] + match_num = pads[i][0] + match_pad = pads[i][2:] pad.SetNet(match_pad[0]) + pad_map[pad.GetNumber()] = match_num - pcb.Add(foot) + sorted_foots.append([load_foot, pad_map]) + pcb.Add(load_foot) # Sort by Y -sorted_pads.sort(key=lambda p: p.GetY()) +sorted_foots.sort(key=lambda foot: foot[0].GetY()) -box = pcb.GetBoundingBox() -brd_width = ToUnits(box.GetWidth()) -brd_height = ToUnits(box.GetHeight()) +# Export the step file +os.system("kicad-cli pcb export step -f --subst-models --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o /tmp/dummy.step " + sys.argv[1]) -print("Box: ", box) -print("W: ", brd_width, "H: ", brd_height) +# Import the 3d model of the actual PCB +dummy = FOOTPRINT(pcb) +dummy.SetPosition(brd_cent) +dummy_model = FP_3DMODEL() +dummy_model.m_Filename = "/tmp/dummy.step" +dummy_model.m_Offset = VECTOR3D(0.0, 0.0, z_offset) +dummy.Add3DModel(dummy_model) +pcb.Add(dummy) + +# # Set the pcb thickness to 0 +# des_sett = pcb.GetDesignSettings() +# stackup = des_sett.GetStackupDescriptor() + +# Save and export step of board + mating connectors +SaveBoard("test/test.kicad_pcb", pcb) +final_model_path = sys.path[0] + "/../../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".step" +os.system("kicad-cli pcb export step -f --subst-models --user-origin " + str(ToMM(brd_cent.x)) + "x" + str(ToMM(brd_cent.y)) + "mm -o " + final_model_path + " test/test.kicad_pcb") -sys.path.append(os.path.join(sys.path[0],"../../../../../dev/kicad-footprint-generator")) +# Generate footprint +sys.path.append(os.path.join(sys.path[0],"../kicad-footprint-generator")) from KicadModTree import * from KicadModTree.nodes.specialized.PadArray import PadArray -footprint_name = "" - # init kicad footprint -kicad_mod = Footprint(footprint_name, FootprintType.SMD) +kicad_mod = Footprint(foot_name, FootprintType.SMD) kicad_mod.setDescription("A example footprint") kicad_mod.setTags("example") # set general values kicad_mod.append(Text(type='reference', text='REF**', at=[0,-3], layer='F.SilkS')) -kicad_mod.append(Text(type='value', text=footprint_name, at=[1.5,3], layer='F.Fab')) +kicad_mod.append(Text(type='value', text=foot_name, at=[1.5,3], layer='F.Fab')) # create silscreen kicad_mod.append(RectLine(start=[-brd_width/2,-brd_height/2], end=[brd_width/2,brd_height/2], layer='F.SilkS', width=0.15)) # create courtyard -kicad_mod.append(RectLine(start=[-brd_width/2 - 0.1,-brd_height/2 - 0.1], end=[brd_width/2 + 0.1,brd_height/2 + 0.1], layer='F.CrtYd', width=0.05, offset=2)) +kicad_mod.append(RectLine(start=[-brd_width/2,-brd_height/2], end=[brd_width/2,brd_height/2], layer='F.CrtYd', width=0.05, offset=0.5)) # create pads +pad_cnt = 0 +for [foot, pad_map] in sorted_foots: + for pad in foot.Pads(): + cent = ToMM(pad.GetCenter() - brd_cent) + pad_size = ToMM(pad.GetSize()) + drill_size = ToMM(pad.GetDrillSize()) + curr_pad_num = pad.GetNumber() + attr_type = pad.GetAttribute() + shape_type = pad.GetShape() + + pad_type = Pad.TYPE_THT + pad_layers = Pad.LAYERS_THT + if attr_type == pcbnew.PAD_ATTRIB_SMD: + pad_type = Pad.TYPE_SMT + pad_layers = Pad.LAYERS_SMT + elif attr_type == pcbnew.PAD_ATTRIB_NPTH: + pad_type = Pad.TYPE_NPTH + pad_layers = Pad.LAYERS_NPTH + elif attr_type == pcbnew.PAD_ATTRIB_CONN: + pad_type = Pad.TYPE_CONNECT + pad_layers = Pad.LAYERS_NPTH -for x, pad in enumerate(sorted_pads): - cent = ToUnits(pad.GetCenter()) - pad_size = ToUnits(pad.GetSize()) - drill_size = ToUnits(pad.GetDrillSize()) - kicad_mod.append(Pad(number=x, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT, at=list(cent), size=list(pad_size), drill=list(drill_size), layers=['*.Cu', '*.Mask', 'F.SilkS'])) -# kicad_mod.append(Pad(number=22, type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, at=[3,0], size=[2,2], drill=1.2, layers=['*.Cu', '*.Mask', 'F.SilkS'])) -# -# kicad_mod.append(Pad(number=12, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, at=[3,0], size=[2,2], drill=1.2, layers=['*.Cu', '*.Mask', 'F.SilkS'])) + pad_shape = Pad.SHAPE_RECT + if shape_type == pcbnew.PAD_SHAPE_CIRCLE: + pad_shape = Pad.SHAPE_CIRCLE + elif shape_type == pcbnew.PAD_SHAPE_OVAL: + pad_shape = Pad.SHAPE_OVAL + elif shape_type == pcbnew.PAD_SHAPE_CHAMFERED_RECT: + pad_shape = Pad.SHAPE_TRAPEZE + elif shape_type == pcbnew.PAD_SHAPE_ROUNDRECT: + pad_shape = Pad.SHAPE_ROUNDRECT + elif shape_type == pcbnew.PAD_SHAPE_CUSTOM: + pad_shape = Pad.SHAPE_CUSTOM + + kicad_mod.append(Pad(number=pad_cnt + int(pad_map[curr_pad_num]), type=pad_type, shape=pad_shape, at=list(cent), size=list(pad_size), drill=list(drill_size), layers=pad_layers)) + pad_cnt += len(foot.Pads()) -# add model -# kicad_mod.append(Model(filename="example.3dshapes/example_footprint.wrl" -# ,at=[0,0,0] -# ,scale=[1,1,1] -# ,rotate=[0,0,0])) -# kicad_mod.append(PadArray(pincount=10,spacing=[1,-1],center=[0,0], initial=5, increment=2, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=[1,2], layers=["*.Cu"])) - -# output kicad model -#print(kicad_mod) - -# print render tree -#print(kicad_mod.getRenderTree()) -#print(kicad_mod.getCompleteRenderTree()) +final_model_path = "${KIPRJMOD}/../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".step" +kicad_mod.append(Model(filename=final_model_path + ,at=[0,0,-1.6] + ,scale=[1,1,1] + ,rotate=[0,0,0])) # write file file_handler = KicadFileHandler(kicad_mod) -file_handler.writeFile('example_footprint.kicad_mod') +final_foot_path = sys.path[0] + "/../../libs/melonlib/" + foot_path + ".pretty/" + foot_name + ".kicad_mod" +file_handler.writeFile(final_foot_path) -SaveBoard("test/test.kicad_pcb", pcb) +import shutil + +shutil.rmtree("test") diff --git a/kibot-ci.yml b/kibot-ci.yml index 466e47c..ae3e6d9 100644 --- a/kibot-ci.yml +++ b/kibot-ci.yml @@ -7,7 +7,7 @@ workflow: variables: GIT_STRATEGY: clone - GIT_SUBMODULE_STRATEGY: normal + GIT_SUBMODULE_STRATEGY: recursive GIT_SUBMODULE_FORCE_HTTPS: "true" # GIT_SUBMODULE_UPDATE_FLAGS: --remote --merge PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/kicad" diff --git a/kicad-footprint-generator b/kicad-footprint-generator new file mode 160000 index 0000000..7d3e9fc --- /dev/null +++ b/kicad-footprint-generator @@ -0,0 +1 @@ +Subproject commit 7d3e9fcf8930e452e68a66f008ad319126d0a9b0