Finished initial implementation of the footprint generator.
There is now a dependant submodule to produce footprints.
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "kicad-footprint-generator"]
|
||||||
|
path = kicad-footprint-generator
|
||||||
|
url = https://gitlab.com/kicad/libraries/kicad-footprint-generator.git
|
||||||
@@ -1,26 +1,31 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
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]
|
filename = sys.argv[1]
|
||||||
|
|
||||||
|
os.mkdir("test")
|
||||||
|
|
||||||
pcb = LoadBoard(filename)
|
pcb = LoadBoard(filename)
|
||||||
|
|
||||||
ToUnits = ToMM
|
box = pcb.GetBoardEdgesBoundingBox()
|
||||||
FromUnits = FromMM
|
brd_cent = box.GetCenter()
|
||||||
|
brd_width = ToMM(box.GetWidth())
|
||||||
print("")
|
brd_height = ToMM(box.GetHeight())
|
||||||
print("List drawings:")
|
|
||||||
|
|
||||||
|
print("Box: ", box)
|
||||||
|
print("W: ", brd_width, "H: ", brd_height)
|
||||||
|
|
||||||
# layers = pcb.GetEnabledLayers()
|
# layers = pcb.GetEnabledLayers()
|
||||||
top_layer_id = pcb.GetLayerID("F.Cu")
|
top_layer_id = pcb.GetLayerID("F.Cu")
|
||||||
|
|
||||||
|
|
||||||
new_foots = {}
|
new_foots = {}
|
||||||
|
brd_outline = []
|
||||||
foot_name = ""
|
foot_name = ""
|
||||||
foot_path = ""
|
foot_path = ""
|
||||||
|
z_offset = 0
|
||||||
for item in pcb.GetDrawings():
|
for item in pcb.GetDrawings():
|
||||||
if type(item) is PCB_TEXT and "User.Drawings" in item.GetLayerName():
|
if type(item) is PCB_TEXT and "User.Drawings" in item.GetLayerName():
|
||||||
lines = str(item.GetText()).splitlines()
|
lines = str(item.GetText()).splitlines()
|
||||||
@@ -33,7 +38,10 @@ for item in pcb.GetDrawings():
|
|||||||
if not lines[2].startswith("Path:"):
|
if not lines[2].startswith("Path:"):
|
||||||
continue
|
continue
|
||||||
foot_path = lines[2].split(":")[-1].strip()
|
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)
|
sp = line.split(':', 1)
|
||||||
if len(sp) != 2:
|
if len(sp) != 2:
|
||||||
continue
|
continue
|
||||||
@@ -53,19 +61,27 @@ for item in pcb.GetDrawings():
|
|||||||
# pin_refs.push(int(pin))
|
# pin_refs.push(int(pin))
|
||||||
|
|
||||||
break
|
break
|
||||||
elif type(item) is PCB_TEXT:
|
elif "Edge.Cuts" in item.GetLayerName():
|
||||||
print("Text: ", item.GetText())
|
brd_outline.append(item)
|
||||||
print("Layer: ", item.GetLayerName())
|
# print("Text: ", item.GetText())
|
||||||
|
# print("Layer: ", item.GetLayerName())
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
print("New Footprint List: ", new_foots)
|
print("New Footprint List: ", new_foots)
|
||||||
|
|
||||||
|
|
||||||
|
if len(new_foots) == 0:
|
||||||
|
exit(0)
|
||||||
|
|
||||||
# Clear tracks
|
# Clear tracks
|
||||||
pcb.Tracks().clear()
|
pcb.Tracks().clear()
|
||||||
# Clear zones
|
# Clear zones
|
||||||
pcb.Zones().clear()
|
pcb.Zones().clear()
|
||||||
# Clear Drawings
|
# Clear Drawings
|
||||||
pcb.Drawings().clear()
|
pcb.Drawings().clear()
|
||||||
|
# Add back in the outline
|
||||||
|
for d in brd_outline:
|
||||||
|
pcb.Drawings().append(d)
|
||||||
|
|
||||||
# Keep only required foots
|
# Keep only required foots
|
||||||
saved = []
|
saved = []
|
||||||
@@ -76,107 +92,149 @@ while len(pcb.Footprints()) > 1:
|
|||||||
# just in case
|
# just in case
|
||||||
pcb.DeleteAllFootprints()
|
pcb.DeleteAllFootprints()
|
||||||
# Add them back
|
# Add them back
|
||||||
sorted_pads = []
|
sorted_foots = []
|
||||||
for foot in saved:
|
for foot in saved:
|
||||||
vals = new_foots[foot.GetReference()]
|
vals = new_foots[foot.GetReference()]
|
||||||
# Change the footprint
|
# 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
|
# Save the original postion of footprint + pads
|
||||||
orig_cent = foot.GetBoundingBox(False,False).Centre()
|
orig_cent = foot.GetBoundingBox(False,False).Centre()
|
||||||
|
orig_orient = foot.GetOrientation()
|
||||||
pads = []
|
pads = []
|
||||||
for pad in foot.Pads():
|
for pad in foot.Pads():
|
||||||
pads.append([pad.GetCenter(), pad.GetNet()])
|
pads.append([pad.GetNumber(), pad.GetCenter(), pad.GetNet()])
|
||||||
|
|
||||||
# Flip to other side
|
# # Flip to other side
|
||||||
foot.SetLayerAndFlip(top_layer_id)
|
# foot.SetLayerAndFlip(top_layer_id)
|
||||||
# Put back in original position with an offset
|
# Put back in original position with an offset
|
||||||
box = foot.GetBoundingBox(False,False)
|
load_foot.SetOrientation(orig_orient)
|
||||||
new_cent = foot.GetBoundingBox(False,False).Centre()
|
new_cent = load_foot.GetBoundingBox(False,False).Centre()
|
||||||
cent_diff = orig_cent - new_cent
|
cent_diff = orig_cent - new_cent
|
||||||
foot.SetX(foot.GetX() + cent_diff.x + vals[1][0])
|
load_foot.SetX(load_foot.GetX() + cent_diff.x + vals[1][0])
|
||||||
foot.SetY(foot.GetY() + cent_diff.y + vals[1][1])
|
load_foot.SetY(load_foot.GetY() + cent_diff.y + vals[1][1])
|
||||||
# Flip the net assignments of the pads
|
# Flip the net assignments of the pads
|
||||||
for pad in foot.Pads():
|
pad_map = {}
|
||||||
sorted_pads.append(pad)
|
for pad in load_foot.Pads():
|
||||||
# Check position diff from old
|
# Check position diff from old
|
||||||
# to new
|
# to new
|
||||||
new_cent = pad.GetCenter()
|
new_cent = pad.GetCenter()
|
||||||
diffs = []
|
diffs = []
|
||||||
for [old_cent,_] in pads:
|
for [_, old_cent,_] in pads:
|
||||||
diffs.append(new_cent - old_cent)
|
diffs.append(new_cent - old_cent)
|
||||||
min_diff = min(diffs)
|
min_diff = min(diffs)
|
||||||
# If pad is within 0.05mm it's a match
|
# If pad is within 0.05mm it's a match
|
||||||
if (min_diff.x**2 + min_diff.y**2)**0.5 < 50000:
|
if (min_diff.x**2 + min_diff.y**2)**0.5 < 50000:
|
||||||
# Set the net to what the old pad was
|
# Set the net to what the old pad was
|
||||||
i = diffs.index(min_diff)
|
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.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
|
# Sort by Y
|
||||||
sorted_pads.sort(key=lambda p: p.GetY())
|
sorted_foots.sort(key=lambda foot: foot[0].GetY())
|
||||||
|
|
||||||
box = pcb.GetBoundingBox()
|
# Export the step file
|
||||||
brd_width = ToUnits(box.GetWidth())
|
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])
|
||||||
brd_height = ToUnits(box.GetHeight())
|
|
||||||
|
|
||||||
print("Box: ", box)
|
# Import the 3d model of the actual PCB
|
||||||
print("W: ", brd_width, "H: ", brd_height)
|
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 import *
|
||||||
from KicadModTree.nodes.specialized.PadArray import PadArray
|
from KicadModTree.nodes.specialized.PadArray import PadArray
|
||||||
|
|
||||||
footprint_name = ""
|
|
||||||
|
|
||||||
# init kicad footprint
|
# 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.setDescription("A example footprint")
|
||||||
kicad_mod.setTags("example")
|
kicad_mod.setTags("example")
|
||||||
|
|
||||||
# set general values
|
# set general values
|
||||||
kicad_mod.append(Text(type='reference', text='REF**', at=[0,-3], layer='F.SilkS'))
|
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
|
# 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))
|
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
|
# 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
|
# 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):
|
pad_shape = Pad.SHAPE_RECT
|
||||||
cent = ToUnits(pad.GetCenter())
|
if shape_type == pcbnew.PAD_SHAPE_CIRCLE:
|
||||||
pad_size = ToUnits(pad.GetSize())
|
pad_shape = Pad.SHAPE_CIRCLE
|
||||||
drill_size = ToUnits(pad.GetDrillSize())
|
elif shape_type == pcbnew.PAD_SHAPE_OVAL:
|
||||||
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']))
|
pad_shape = Pad.SHAPE_OVAL
|
||||||
# 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']))
|
elif shape_type == pcbnew.PAD_SHAPE_CHAMFERED_RECT:
|
||||||
#
|
pad_shape = Pad.SHAPE_TRAPEZE
|
||||||
# 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']))
|
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"]))
|
final_model_path = "${KIPRJMOD}/../libs/melon3d/" + foot_path + ".3dshapes/" + foot_name + ".step"
|
||||||
|
kicad_mod.append(Model(filename=final_model_path
|
||||||
# output kicad model
|
,at=[0,0,-1.6]
|
||||||
#print(kicad_mod)
|
,scale=[1,1,1]
|
||||||
|
,rotate=[0,0,0]))
|
||||||
# print render tree
|
|
||||||
#print(kicad_mod.getRenderTree())
|
|
||||||
#print(kicad_mod.getCompleteRenderTree())
|
|
||||||
|
|
||||||
# write file
|
# write file
|
||||||
file_handler = KicadFileHandler(kicad_mod)
|
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")
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ workflow:
|
|||||||
|
|
||||||
variables:
|
variables:
|
||||||
GIT_STRATEGY: clone
|
GIT_STRATEGY: clone
|
||||||
GIT_SUBMODULE_STRATEGY: normal
|
GIT_SUBMODULE_STRATEGY: recursive
|
||||||
GIT_SUBMODULE_FORCE_HTTPS: "true"
|
GIT_SUBMODULE_FORCE_HTTPS: "true"
|
||||||
# GIT_SUBMODULE_UPDATE_FLAGS: --remote --merge
|
# GIT_SUBMODULE_UPDATE_FLAGS: --remote --merge
|
||||||
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/kicad"
|
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/kicad"
|
||||||
|
|||||||
1
kicad-footprint-generator
Submodule
1
kicad-footprint-generator
Submodule
Submodule kicad-footprint-generator added at 7d3e9fcf89
Reference in New Issue
Block a user