Annular checking: How do I check if all my pads diameter is drill diameter +0.3 (or so)?

Hi there!
I just faced with the problem that some of my pads are too small relative to their hole diameter. I made some visual search and fixed some.
However I can not rely on my eyes in this case.
I tried to make a out of rules hole (1.6mm hole, 1.65 size while my design rules set to min width at 0,15mm) so it SHOULD not be passed, however it does :frowning:
Is there any better way to check my pads?

Pics:

Pads are not tracks, neither build with tracks, so you can not create any rule for that in Design Rule Editor. Therefore - I think - you may use build in Pcbnew Python scripting to create a simple script which may validate your pads.

To me, that is certainly a deficiency in the DRC capabilities. I believe every board vendor I have dealt width will put a job on “Hold” if they detect insufficient annulus width.

I acknowledge that there are practical barriers to implementing such a DRC check, because occasionally we deliberately specify a hole with the same diameter as its pad. Nevertheless, a DRC check for minimum annular ring seems like a pretty fundamental feature.

Dale

1 Like

I personally think the current DRC code has been written especially for Freerouter. That’s why there is no progress in applying other rules.

Hi @Roman_Matveev, here is an example script that I’ve created to check annular ring sizes of the pads. When you run, it will simply iterate over all pads and print the locations of the pads that violate annular ring size.

from kicad.pcbnew.board import Board

def annring_size(pad):
    return min(pad.size) - max(pad.drill)

MIN_AR_SIZE = .25

board = Board.from_editor()

for m in board.modules:
    for pad in m.pads:
        if annring_size(pad) < MIN_AR_SIZE:
            print("AR violation at %s." % pad.position)

To run this script in pcbnew’s python shell, you will need my fork of kicad-python. You can find the file that contains above code in the ‘examples/’ folder of the repository. Let me know if you can’t get it work, I will try to help.

6 Likes

wow, Impressively simple.
Now I’m a little confused about Python status. I find this thread…

That suggests it is in 4.x+, and I can see this promising window…

PyCrust 0.9.8 - KiCAD Python Shell
Python 2.7.10 (default, Jul 8 2015, 15:10:39)
[GCC 5.1.0] on win32
Type “help”, “copyright”, “credits” or “license” for more information.

but paste of the code above tries to work, but gives this error
Traceback (most recent call last):
File “”, line 1, in
ImportError: No module named kicad.pcbnew.board

Is there more than one Python, and what is different about the fork of kicad-python you mention ?
ie what can it do, the main fork cannot, and vice versa ?
Is there a timeline to merge this ?

Hi @PCB_Wiz, let me clarify a few things.

Kicad has a python api which is automatically created from the C++ API using a tool called SWIG. This API isn’t very pythonic, it feels like a c++ library and doesn’t have the ease of use and flexibility of python. So, some developers decided to create a wrapper around this API, called kicad-python. I believe their aim was to create a simpler and better documented scripting interface for kicad.

Notice that kicad-python, doesn’t call the C++ API directly, so it isn’t a replacement of actual python API of kicad, but is a wrapper around it.

About my fork of kicad-python; it wasn’t actively developed at the time I saw it, so I decided to fork it and add some features. It’s far from complete, and I only add features as I need them.

Is it ever going to be merged to kicad? I don’t know.


To be able to use above code snippet, you should download/clone my kicad-python repository and add it to python path so that interpreter can import modules;

import sys
sys.path.append("/path/to/kicad-python/")

A tip; you can use function execfile() function to run python scripts from the python command line.

1 Like

Is this then a superset of what KiCad has ?
Trying to figure out why not to merge this ?

I think it tried to work, but I get this message on a test board

File “/KiCad_Python/kicad-python-master/kicad/pcbnew/pad.py”, line 34, in PadShape
RoundedRectangle = pcbnew.PAD_SHAPE_ROUNDRECT
AttributeError: ‘module’ object has no attribute ‘PAD_SHAPE_ROUNDRECT’

@PCB_Wiz, what is your KiCad version? This may require a very up to date version of kicad. Can you try with a nightly build?

Sort of. But when its completed (if that ever happens) it won’t be able provide any features that is not provided by native python API.

Disclaimer: this is my opinion, I don’t know what kicad developers think about the matter: It’s yet another burden. Native python API is automatically generated so it doesn’t have much development overhead. kicad-python on the other hand, should be updated every time there is a change to C++ API.

I have 4.0.2.the latest full release, of 2016. I was wary of anything less mainstream, as that may be less stable.

[quote=“hyOzd”] Native python API is automatically generated so it doesn’t have much development overhead. kicad-python on the other hand, should be updated every time there is a change to C++ API.
[/quote]
hmm.
If the same script was attempted in the main-stream version, what would that need to change to ?

Here is a version that doesn’t need kicad-python. To be honest it is not that bad. Most annoying part is the unit conversions.

import pcbnew

def annring_size(pad):
    return min(pad.GetSize()) - max(pad.GetDrillSize())

mm_ius = 1000000
MIN_AR_SIZE = .25 * mm_ius

board = pcbnew.GetBoard()

for module in board.GetModules():
    for pad in module.Pads():
        if annring_size(pad) < MIN_AR_SIZE:
            print("AR violation at %s." % pad.GetPosition())
3 Likes

That seems to work.
I added counters so it reports like this

execfile(“C:\KiCad_Python\kicad-python-master\examples\checkar_count.py”)
checkar_count.py Testing PCB
AR violation at (172974000, 110744000).
AR violation at (172212000, 110744000).
AR violation at (154813000, 96520000).
PADS that Pass = 49 Fails = 3

but I’m new to Python, so could not find a way to scale the list back to mm ( /mm_ius ?), other than this…

  • improved the reporting, and add report actual value

      # -*- coding: utf-8 -*-
      #
      # An example script to check for annular ring violations
      #
    
     import pcbnew
    
      mm_ius = 1000000.0
      AR_SET = 0.25
      MIN_AR_SIZE = AR_SET * mm_ius
    
      def annring_size(pad):
          return min(pad.GetSize()) - max(pad.GetDrillSize())
    
      def f_mm(raw):
          return repr(raw/mm_ius)
    
      board = pcbnew.GetBoard()
      PassC=FailC=0
      print("checkar_count.py Testing PCB for Annular Ring >= "+repr(AR_SET))
    
      for module in board.GetModules():
          for pad in module.Pads():
              ARv = annring_size(pad)
              if ARv  < MIN_AR_SIZE:
      #            print("AR violation at %s." % (pad.GetPosition() / mm_ius ))  Raw units, needs fixing
                  XYpair =  pad.GetPosition()
                  print("AR violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1]) )
                  FailC = FailC+1
              else:
                  PassC = PassC+1
      print("PADS that Pass = "+repr(PassC)+" Fails = "+repr(FailC))
    
      #  execfile("C:\KiCad_Python\kicad-python-master\examples\checkar_count.py")
      # checkar_count.py Testing PCB for Annular Ring >= 0.25
      # AR violation of 0.1 at XY 172.974,110.744
      # AR violation of 0.1 at XY 172.212,110.744
      # AR violation of 0.0 at XY 154.813,96.52
      # PADS that Pass = 49 Fails = 3
2 Likes

Hi @PCB_Wiz
I modified the annring_size function to manage also oval drills
def annring_size(pad): # valid for oval pad/drills annrX=(pad.GetSize()[0]) - (pad.GetDrillSize()[0]) annrY=(pad.GetSize()[1]) - (pad.GetDrillSize()[1]) #annr=min(pad.GetSize()) - max(pad.GetDrillSize()) #if annr < MIN_AR_SIZE: # print pad.GetSize() # print pad.GetDrillSize() return min(annrX,annrY)

and the full script
# -*- coding: utf-8 -*- # # An example script to check for annular ring violations #

import sys
import pcbnew

mm_ius = 1000000.0
AR_SET = 0.30
MIN_AR_SIZE = AR_SET * mm_ius

def annring_size(pad):
    # valid for oval pad/drills
    annrX=(pad.GetSize()[0]) - (pad.GetDrillSize()[0])
    annrY=(pad.GetSize()[1]) - (pad.GetDrillSize()[1])
    #annr=min(pad.GetSize()) - max(pad.GetDrillSize())
    #if annr < MIN_AR_SIZE:
    #    print pad.GetSize()
    #    print pad.GetDrillSize()
    return min(annrX,annrY)

def f_mm(raw):
    return repr(raw/mm_ius)

board = pcbnew.GetBoard()
PassC=FailC=0
print("checkar_count.py Testing PCB for Annular Ring >= "+repr(AR_SET))

for module in board.GetModules():
    for pad in module.Pads():
        ARv = annring_size(pad)
        if ARv  < MIN_AR_SIZE:
#            print("AR violation at %s." % (pad.GetPosition() / mm_ius ))  Raw units, needs fixing
            XYpair =  pad.GetPosition()
            print("AR violation of "+f_mm(ARv)+" at XY "+f_mm(XYpair[0])+","+f_mm(XYpair[1]) )
            FailC = FailC+1
        else:
            PassC = PassC+1
print("PADS that Pass = "+repr(PassC)+" Fails = "+repr(FailC))

#  execfile("C:\KiCad_Python\kicad-python-master\examples\checkar_count.py")
# checkar_count.py Testing PCB for Annular Ring >= 0.25
# AR violation of 0.1 at XY 172.974,110.744
# AR violation of 0.1 at XY 172.212,110.744
# AR violation of 0.0 at XY 154.813,96.52
# PADS that Pass = 49 Fails = 3
3 Likes

Hi again,
EDIT: I corrected annular calculation, which has to be 1/2 the previous calculation value
I’ve added a checking also for via annulars
and added an extra on drill tool as


here the script @ github
3 Likes

small fix :smiley:

just putting a link here…
annular script can be called directly from a button now, using Action Script


https://kicad-info.s3-us-west-2.amazonaws.com/optimized/2X/b/bfe71eb0d1c222ad1e6f51c876749e83c3c22394_1_632x500.gif

1 Like