Edit April 3, 2018 The comment below about 4.0.5 is not true. Even the most recent 4.0.7 is missing a ton of python related stuff. Until kicad 5.0 comes out, I recommend using one of the nightly builds from the kicad downloads page. End Edit
Note that these examples don’t work on the latest release as of Feb 2017 (4.0.5). You want one of the nightly builds, also in the kicad download area. Or you can build it
The interface is lacking some consistency but it’s fine if you have a map of the classes (click for a larger version or download it from here):
In this post, I’ll focus on querying a board for information about it’s contents. The code can be found in this github repo.
Getting started
To invoke any of these examples, you’ll want pcbnew’s scripting window. Tools->scripting consoleYou’ll probably want these in your scripts
import pcbnew # most queries start with a board board = pcbnew.GetBoard()
Nets
Want to know all of the nets in your board?Nets can be looked up in two ways:
- by name
- by netcode – a unique integer identifier for your net.
# returns a dictionary netcode:netinfo_item netcodes = board.GetNetsByNetcode() # list off all of the nets in the board. for netcode, net in netcodes.items(): print("netcode {}, name {}".format(netcode, net.GetNetname())) # here's another way of doing the same thing. print("here's the other way to do it") nets = board.GetNetsByName() for netname, net in nets.items(): print("method2 netcode {}, name{}".format(net.GetNet(), netname)) # maybe you just want a single net # the find method returns an iterator to all matching nets. # the value of an iterator is a tuple: name, netinfo clknet = nets.find("/clk").value()[1] clkclass = clknet.GetNetClass() print("net {} is on netclass {}".format(clknet.GetNetname(), clkclass))You’ll get something like this:
netcode 49, name /ihg netcode 50, name /ihh netcode 51, name /data_in netcode 52, name /data_out netcode 53, name /clk here's the other way to do it method2 netcode 0, name method2 netcode 23, name+5V method2 netcode 53, name/clk method2 netcode 55, name/data_contd method2 netcode 51, name/data_in
Physical dimensions
The coordinate space of kicad_pcb is in mm. At the beginning of this wiki about Kicad’s Board_File_FormatThen later in historical notes, it says,“All physical units are in mils (1/1000th inch) unless otherwise noted.”
In short, for the data that I’ve recently created, the internal coordinate space of pcbnew is 10E-6 mm. (a millionth of a mm)“As of 2013, the PCBnew application creates ‘.kicad_pcb’ files that begin with (kicad_pcb (version 3)”. All distances are in millimeters.
For example, the coordinate 121550000 corresponds to 121.550000mm
SCALE = 1000000.0 boardbbox = board.ComputeBoundingBox() boardxl = boardbbox.GetX() boardyl = boardbbox.GetY() boardwidth = boardbbox.GetWidth() boardheight = boardbbox.GetHeight() print("this board is at position {},{} {} wide and {} high".format(boardxl, boardyl, boardwidth, boardheight))
Modules/Pads
Each of your placed modules can be found with its reference name. The module connection points are pads, of course.# generate a LUT with shape integers to a string padshapes = { pcbnew.PAD_SHAPE_CIRCLE: "PAD_SHAPE_CIRCLE", pcbnew.PAD_SHAPE_OVAL: "PAD_SHAPE_OVAL", pcbnew.PAD_SHAPE_RECT: "PAD_SHAPE_RECT", pcbnew.PAD_SHAPE_TRAPEZOID: "PAD_SHAPE_TRAPEZOID" } # new in the most recent kicad code if hasattr(pcbnew, 'PAD_SHAPE_ROUNDRECT'): padshapes[pcbnew.PAD_SHAPE_ROUNDRECT] = "PAD_SHAPE_ROUNDRECT", modref = "U1" mod = board.FindModuleByReference(modref) for pad in mod.Pads(): print("pad {}({}) on {}({}) at {},{} shape {} size {},{}" .format(pad.GetPadName(), pad.GetNet().GetNetname(), mod.GetReference(), mod.GetValue(), pad.GetPosition().x, pad.GetPosition().y, padshapes[pad.GetShape()], pad.GetSize().x, pad.GetSize().y ))Gives you this:
pad 1(/ilb) on U1(74HC595) at 127635000,106520000 shape PAD_SHAPE_RECT size 1500000,600000 pad 2(/ilc) on U1(74HC595) at 126365000,106520000 shape PAD_SHAPE_RECT size 1500000,600000 pad 3(/ild) on U1(74HC595) at 125095000,106520000 shape PAD_SHAPE_RECT size 1500000,600000
Layer
Most of the pcb data is on a layer. pcbnew stores layers as numbers. Here we can print them all outlayertable = {} numlayers = pcbnew.LAYER_ID_COUNT for i in range(numlayers): layertable[i] = board.GetLayerName(i) print("{} {}".format(i, board.GetLayerName(i)))Which gives you this:
0 F.Cu 1 In1.Cu 2 In2.Cu 3 In3.Cu ...
Tracks (wires and vias)
A wire is stored in a TRACK object. Vias are in a class derived from TRACK. Let’s list some of them.# clk net was defined above as was SCALE clktracks = board.TracksInNet(clknet.GetNet()) for track in clktracks: print("{},{}->{},{} width {} layer {}".format(track.GetStart().x/SCALE, track.GetStart().y/SCALE, track.GetEnd().x/SCALE, track.GetEnd().y/SCALE, track.GetWidth()/SCALE, layertable[track.GetLayer()]))And here are the wires
121.92,97.79->126.492,97.79 width 0.25 layer F.Cu 127.762,100.33->125.984,100.33 width 0.25 layer F.Cu 127.762,99.314->127.762,100.33 width 0.25 layer B.CuSo that’s how to query data. In my next post, I’ll talk about making changes
The basics of scripting in pcbnew
thanks to recent work by Kicad contributor/developer Dick Hollenbeck↩