Hi everyone,
I am currently trying to use the KiCad Python interface to automatically place footprints. Unfortunately, when my script finishes running, it non-deterministically corrupts the footprint save file. Obviously there is something I am missing, but I can’t seem to find it.
Firstly, I start with a pre-made footprint library called beans
, and using the KiCad GUI footprint editor tool I create one footprint called My_PCI_footprint
. This creates the following files on the filesystem:
beans.pretty/
-> beans.pretty/ (empty directory)
-> My_PCI_footprint.kicad_mod
Consequently, My_PCI_footprint.kicad_mod
looks like this:
The idea is, that I want to use the API function ImportSettingsFrom function, and use that one pad as a “master pad”. When I finish running the script, the footprint save file gets broken, and each time in a different way:

Well, you get the idea. Note that I commented out ImportSettingsFrom
thinking that maybe that was what was causing the problem, which is why they are all default attributes.
Also another problem: For some reason, the pads are all set to position (0, 0)
despite the fact that I explicitly set it in the script for each pad.
Here is the script:
Script source
import sys, os;
import pcbnew;
def dbg_report_pad(pad):
pad_shape_t_strtab = [
"PAD_SHAPE_CIRCLE",
"PAD_SHAPE_RECT",
"PAD_SHAPE_OVAL",
"PAD_SHAPE_TRAPEZOID",
"PAD_SHAPE_ROUNDRECT",
"PAD_SHAPE_CHAMFERED_RECT",
"PAD_SHAPE_CUSTOM"
];
print("Pad: \"{}\"".format(pad.GetName()));
print("\tPad class: {}".format(pad.GetClass()));
print("\tPad shape: {} ({})".format(pad.GetShape(),
pad_shape_t_strtab[pad.GetShape()]));
print("\tAnchor pad shape: {} ({})".format(pad.GetAnchorPadShape(),
pad_shape_t_strtab[pad.GetAnchorPadShape()]));
print("\tPosition: ({}mm, {}mm)".format(pcbnew.ToMM(pad.GetPosition().x),
pcbnew.ToMM(pad.GetPosition().y)));
size = pad.GetSize();
print("\tSize: ({}mm, {}mm)".format(pcbnew.ToMM(size.GetWidth()),
pcbnew.ToMM(size.GetHeight())));
print("#### Loading plugin");
plugin = pcbnew.GetPluginForPath("beans.pretty");
print("plugin object: " + str(plugin));
print("plugin name: " + plugin.PluginName());
print("\t");
print("#### Enumerating footprints");
footprints = plugin.footprintPyEnumerate("beans.pretty", False);
print("Found footprints:");
for fp_name in footprints:
print("\t{}".format(fp_name));
print("\t");
print("#### Loading beans footprint in enumerator list");
fp = plugin.GetEnumeratedFootprint("beans.pretty", footprints[0]);
print("footprint object: {}".format(fp));
print("\t");
print("#### Loading pads");
pads = fp.Pads();
print("Pads object: {}".format(pads));
master_pad = None;
for idx, p in enumerate(pads):
if idx == 0:
master_pad = p;
dbg_report_pad(p);
ypos = pcbnew.FromMM(-4.0);
xpos = pcbnew.FromMM(2.0);
xincr = pcbnew.FromMM(1.27);
for i in range(10):
padname = "abracadabra" + str(i);
new_pad = pcbnew.D_PAD(fp);
print("Instianted:\n\tD_PAD {}\n\tchild of MODULE {}\n".format(new_pad, fp));
#new_pad.ImportSettingsFromMaster(master_pad);
print("Adding new pad at coords ({}, {})".format(xpos, ypos));
print("Current coords: ({}, {})".format(new_pad.GetPosition().x,
new_pad.GetPosition().y));
new_pad.SetPosition(pcbnew.wxPoint(xpos, ypos));
print("New coords: ({}, {})".format(new_pad.GetPosition().x,
new_pad.GetPosition().y));
new_pad.SetName(padname);
fp.Add(new_pad);
xpos += xincr;
print("Current pads in footprint module:");
pads = fp.Pads()
for i, p in enumerate(pads):
print("{}:".format(i));
dbg_report_pad(p);
print("Ok, saving...");
plugin.FootprintSave("beans.pretty", fp);
And here is the log that it prints. Note that just before saving, I iterate over the fp.Pads()
, and the output is totally sane.
Output log
#### Loading plugin
plugin object: <pcbnew.PLUGIN; proxy of <Swig Object of type 'PLUGIN *' at 0x0000000004151fc0> >
plugin name: KiCad
#### Enumerating footprints
Found footprints:
My_PCI_footprint
#### Loading beans footprint in enumerator list
footprint object: <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
#### Loading pads
Pads object: <pcbnew.PAD_List; proxy of <Swig Object of type 'DLIST< D_PAD > *' at 0x0000000003432090> >
Pad: "1"
Pad class: PAD
Pad shape: 4 (PAD_SHAPE_ROUNDRECT)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (0.0mm, -6.35mm)
Size: (1.106mm, 3.0mm)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x00000000034320f0> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (2000000, -4000000)
Current coords: (0, 0)
New coords: (2000000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x00000000034320c0> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (3270000, -4000000)
Current coords: (0, 0)
New coords: (3270000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x0000000003432180> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (4540000, -4000000)
Current coords: (0, 0)
New coords: (4540000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x00000000034320f0> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (5810000, -4000000)
Current coords: (0, 0)
New coords: (5810000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x00000000034320c0> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (7080000, -4000000)
Current coords: (0, 0)
New coords: (7080000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x0000000003432180> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (8350000, -4000000)
Current coords: (0, 0)
New coords: (8350000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x00000000034320f0> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (9620000, -4000000)
Current coords: (0, 0)
New coords: (9620000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x00000000034320c0> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (10890000, -4000000)
Current coords: (0, 0)
New coords: (10890000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x0000000003432180> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (12160000, -4000000)
Current coords: (0, 0)
New coords: (12160000, -4000000)
Instianted:
D_PAD <pcbnew.D_PAD; proxy of <Swig Object of type 'D_PAD *' at 0x00000000034320f0> >
child of MODULE <pcbnew.MODULE; proxy of <Swig Object of type 'MODULE *' at 0x0000000003432060> >
Adding new pad at coords (13430000, -4000000)
Current coords: (0, 0)
New coords: (13430000, -4000000)
Current pads in footprint module:
0:
Pad: "abracadabra9"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (13.43mm, -4.0mm)
Size: (1.524mm, 1.524mm)
1:
Pad: "abracadabra8"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (12.16mm, -4.0mm)
Size: (1.524mm, 1.524mm)
2:
Pad: "abracadabra7"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (10.89mm, -4.0mm)
Size: (1.524mm, 1.524mm)
3:
Pad: "abracadabra6"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (9.62mm, -4.0mm)
Size: (1.524mm, 1.524mm)
4:
Pad: "abracadabra5"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (8.35mm, -4.0mm)
Size: (1.524mm, 1.524mm)
5:
Pad: "abracadabra4"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (7.08mm, -4.0mm)
Size: (1.524mm, 1.524mm)
6:
Pad: "abracadabra3"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (5.81mm, -4.0mm)
Size: (1.524mm, 1.524mm)
7:
Pad: "abracadabra2"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (4.54mm, -4.0mm)
Size: (1.524mm, 1.524mm)
8:
Pad: "abracadabra1"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (3.27mm, -4.0mm)
Size: (1.524mm, 1.524mm)
9:
Pad: "abracadabra0"
Pad class: PAD
Pad shape: 0 (PAD_SHAPE_CIRCLE)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (2.0mm, -4.0mm)
Size: (1.524mm, 1.524mm)
10:
Pad: "1"
Pad class: PAD
Pad shape: 4 (PAD_SHAPE_ROUNDRECT)
Anchor pad shape: 0 (PAD_SHAPE_CIRCLE)
Position: (0.0mm, -6.35mm)
Size: (1.106mm, 3.0mm)
Ok, saving...