Creating a zone array and assign Net Names with Python

I’ve dug through some older (and somewhat recent) posts, but cannot seem to find a working answer for this. I am using Kicad 6.0.8 on Windows 11.

Using Python, I would like to make an array of zones and assign them a net name. (For an array of LEDs). I have no problem creating the zones, however I cannot seem to assign net names to the zones. I tried the following from another post:

net = pcbnew.NETINFO_ITEM(board, "net_TEST2")
board.AppendNet(net)
print(net.GetNet())
z = pcbnew.ZONE(board)
z.SetLayer(pcbnew.F_Cu)
z.SetLayer(pcbnew.F_Cu)
z.SetNetCode(net.GetNet())

… but I get the error AttributeError: 'BOARD' object has no attribute 'AppendNet'

So, two questions:

  1. Is there a way to create and assign net names via Python in 6.x? I know I can pass z.SetNetCode(<INTEGER OF NAME ALREADY IN LIST>)

  2. In the big picture, what is the best solution to this problem? Assume I already have a schematic that has the LED array with net names that I want to apply to the zones.

Basically, I want to auto-layout the zone locations and LED footprint arrays. Bonus points for being able to dynamically adjust the number of LEDs in the schematic and layout.

AppendNet() is a method of NETINFO_LIST, not BOARD. Try

board.GetNetInfo().AppendNet(...)

But if you have a schematic then you shouldn’t have to create any nets, only use existing ones, for that use board.GetNetsByName() to get net map.

There is no scripting in schematic editor yet. But in general if you have lots of repeated pieces then create a hierarchical sheet, put the repeated piece in it and replicate the sheet required times in schematic. Then you can use place footprints/replicate layout plugins to do initial placing in an array and then copy surrounding stuff like tracks, zones (I think) current limiting resistors if you have them etc.

You can find these plugins in plugin manager

This is how I do it…

  1. Must have a Track to the Zone (to a Pad, Via,… to something in the zone that’s Netable)

  2. Double-Click the Zone, Select the desired Net

ADDED: Amusing myself…
Video shows Double-Clicking Zones and showing the Net they belong to.
The Middle Zone is not assigned to a Net and shows no Net in panel.

Regarding Array: You can select a Zone containing LED’s and Create an Array with it (Right-Click>Special_Tools>Create_Array. Works !) Image shows LED’s with Vcc net on Top layer and GND on Bottom layer…

Thank you for the feedback. In my case there are no tracks on the PCB at all. It is a single sided board with SMT LEDs. I did find the net-index to net-name table in the .kicad_pcb file. I am already using hierarchical sheets, but due to the nature of the design, I need to adjust the zone layouts intra-sheet to avoid creating a ton of sheets. Because of this, I would rather create the array in python rather than use the Replicate Layout plugin.

@qu1ck board.GetNetsByName() is what I was looking for. Is there an example of its usage somewhere? What I tried did not work. As a fallback, I can pull the net index and name data in by parsing the net table in pcb file manually in python, but GetNetsByName() should do this for me I believe.

Well, what did you try?

GetNetsByName() returns a map, you can iterate over it with

for name, net in m.items():
  ...

or access elements directly with indexing operator:
m['GND']

I assume you want to give each LED a little heatsink, If the LED pattern is regular, then you can very simple create a custom footprint for the LED with big pads. This can be done in several way. You can place a pad, then press [Ctrl + E] to enter “pad edit mode” and then you can add graphics such as filled rectangles lines and arcs to a pad.

Another way is to use several pads with the same pad number in the footprint and then overlap them partially. Note that you can disable paste and/or solder mask layers for each pad and this makes it easy to combine them into something fancy.

@qu1ck, thank you. I figured it out shortly after I posted, but somehow my updated post didn’t get submitted.

EDIT: I figured it out from another example:

nets = pcbnew.GetBoard().GetNetsByName()
for netname, net in nets.items():
    netname = net.GetNetname()
    if netname != None and netname != "":
        print(netname)

I didn’t find this posted anywhere, so I will leave it here for reference. It was a good primer on getting Kicad python scripting up and running.

I am now able to selectivity read the board net names and create my zones, then read footprint Refdes and place the parts. Here is the proof-of-concept:

# To execute from Python Shell
# exec(open("pcbnew_test.py").read())
import pcbnew
board = pcbnew.GetBoard()

#----------------------------------------------------------
#-- Create Zones
#----------------------------------------------------------
xSize = 5e6 # 5mm
ySize = 5e6 # 5mm
xOffset = 0
yOffset = 0

nets = board.GetNetsByName()
colCnt = 0
rowCnt = 0

# Create Zone for each net
# Array is built column by column in the y-direction
for netname, net in nets.items():
    # Find nets assigned to pads
    netname = net.GetNetname()
    if netname.find('Net') >= 0 :
        print(netname)
        
        # Calculate upper left corner offset
        xOffset = xSize * colCnt
        yOffset = ySize * rowCnt
        
        # Calculate all four corner points of Zone
        x0 = xOffset
        y0 = yOffset
        xM = x0 + xSize
        yM = y0 + ySize

        # Create Zone corner point array
        points = ( pcbnew.wxPoint(x0,y0), pcbnew.wxPoint(xM,y0), pcbnew.wxPoint(xM,yM), pcbnew.wxPoint(x0,yM))
        
        # Add Zone to board on Layer F_Cu
        z = pcbnew.ZONE(board)
        z.SetLayer(pcbnew.F_Cu)
        z.SetLayer(pcbnew.F_Cu)
        z.SetNetCode(net.GetNetCode())
        z.AddPolygon( pcbnew.wxPoint_Vector(points) )
        z.SetIsFilled(True)
        board.Add(z)
       
        # Check for end of column 
        rowCnt += 1 
        if rowCnt >= 7:
            rowCnt = 0
            colCnt += 1

# Fill board
filler = pcbnew.ZONE_FILLER(board)
filler.Fill(board.Zones())

#----------------------------------------------------------
#-- Place Footprints
#----------------------------------------------------------
footprints = board.GetFootprints()
colCnt = 0
rowCnt = 0

# Place each footprint
# Array is built column by column in the y-direction
for fprt in footprints :
    # Find nets assigned to pads
    fprtRef = fprt.GetReference()
    if fprtRef.find('D') >= 0 :
        print(fprtRef)
        
        # Calculate upper left corner offset
        xOffset = xSize * colCnt
        yOffset = ySize * rowCnt
        
        # Create Zone corner point array
        refDes = board.FindFootprintByReference(fprtRef)
        refDes.SetPosition(pcbnew.wxPoint(xOffset, yOffset)) 
        refDes.SetOrientation(90 * 10)    # rotate by 90 deg
       
        # Check for end of column 
        rowCnt += 1 
        if rowCnt >= 7:
            rowCnt = 0
            colCnt += 1

       #break # DEBUG, Break after one run

pcbnew.Refresh()

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.