Compared to other scripting tasks in pcbnew, figuring out how to add footprints to a design was a pain. In the end, it’s pretty easy
My designs are pretty simple
First off, while pcbnew’s add footprint command can access kicad’s footprint libraries on GITHUB, this is not something I’ve achieved yet.
git clone https://github.com/KiCad/Connectors.pretty.gitDon’t forget where you put it. In the case of the script, I have a variable footprint_lib. You’ll want to change this variable
footprint_lib = '/bubba/electronicsDS/kicad/development/footprints/Connectors.pretty' board = pcbnew.GetBoard() # the internal coorinate space of pcbnew is 10E-6 mm. (a millionth of a mm) # the coordinate 121550000 corresponds to 121.550000 SCALE = 1000000.0Since I want to put my mounting holes in the four corners of the board, I have to compute the four corners:
rect = None for d in board.GetDrawings(): if (d.GetLayerName() != "Edge.Cuts"): continue if (rect == None): rect = d.GetBoundingBox() else: rect.Merge(d.GetBoundingBox())While the module class has a GetBoundingBox function, that box includes stuff like reference designators. So I have a function to compute the bounding box of metals, solder masks and such.
def GetModBBox(mod): modbox = None for pad in mod.Pads(): if (modbox == None): modbox = pad.GetBoundingBox() else: modbox.Merge(pad.GetBoundingBox()) for gi in mod.GraphicalItems(): if (modbox == None): modbox = gi.GetBoundingBox() else: modbox.Merge(gi.GetBoundingBox()) return modboxSince I want to put a mounting hole in each corner, I generate a list of points from a bounding rectangle. Much better than cut/pasting a bunch of module code.
def GetRectCorners(rect): return [pcbnew.wxPoint(rect.Centre().x-rect.GetWidth()/2, rect.Centre().y-rect.GetHeight()/2), pcbnew.wxPoint(rect.Centre().x-rect.GetWidth()/2, rect.Centre().y+rect.GetHeight()/2), pcbnew.wxPoint(rect.Centre().x+rect.GetWidth()/2, rect.Centre().y+rect.GetHeight()/2), pcbnew.wxPoint(rect.Centre().x+rect.GetWidth()/2, rect.Centre().y-rect.GetHeight()/2)]
How to actually add a footprint.
Now we finally get to the “hard” part, adding the footprint. The ability to add a footprint is exposed in an API in the PCB_IO plugin. I don’t yet understand the role that plugin’s play in the context of pcbnew; most plugins are python scripts. PCB_IO is one written in C++.It comes down to two easy lines. One to construct an instance of the PCB_IO plugin, and the second to instantiate the footprint. As I mentioned earlier in this post footprint_lib contains a path to a directory where you’ve put your kicad_mod files.
io = pcbnew.PCB_IO() mod = io.FootprintLoad(footprint_lib, "1pin")Everything after is easy.
board = pcbnew.GetBoard() board.Add(mod)I want to put four of these in the four corners of the boundary bounding box defined by rect above. First I shrink rect by the size of the footprint module.
mod = io.FootprintLoad(footprint_lib, "1pin") modbox = GetModBBox(mod); rect.SetWidth(rect.GetWidth() - modbox.GetWidth()) rect.SetHeight(rect.GetHeight() - modbox.GetHeight()) rect.SetX(rect.GetX() + modbox.GetWidth()/2) rect.SetY(rect.GetY() + modbox.GetHeight()/2)And now I finally create and place the holes:
for point in GetRectCorners(rect): mod = io.FootprintLoad(footprint_lib, "1pin") modbox = GetModBBox(mod) point.x = point.x - modbox.Centre().x + mod.GetPosition().x point.y = point.y - modbox.Centre().y + mod.GetPosition().y mod.SetPosition(point) point.y - modbox.Centre().y)) board.Add(mod)Again, the script can be found on my github.
Makes me think of times in my career when I spent a couple full days debugging a problem that was fixed with a single character. I’m sure most C/C++ programmers have experienced this with “=” vs “==” in an if statement. In this case, it’s not a matter of bugs, but that I don’t know the code that well.I should probably try to interact some with the kicad developers.
I’m a software guy. I entered college intending to major EE, but my aptitude for programming eclipsed circuit stuff. Still, I pine for the ability to design circuits.
I didn’t actually try, but I did keep and eye out for relevant code while tracking down the APIs needed to add a module
“bubba”, in the path below, is one of my drives. I think of it as a name that only big guys have. As disks go and as technology has progressed, it really not that big anymore.
EDA_RECT is nice enough to have an API called inflate. Sadly, it takes wxCoord as arguments. I haven’t found a way to create one or these via the existing python APIs.