Kevin Cuzner's Personal Blog

Electronics, Embedded Systems, and Software are my breakfast, lunch, and dinner.


Arranging components in a circle with Kicad

I've been using kicad for just about all of my designs for a little over 5 years now. It took a little bit of a learning curve, but I've really come to love it, especially with the improvements by CERN that came out in version 4. One of the greatest features, in my opinion, is the Python Scripting Console in the PCB editor (pcbnew). It gives (more or less) complete access to the design hierarchy so that things like footprints can be manipulated in a scripted fashion.

In my most recent design, the LED Watch, I used this to script myself a tool for arranging footprints in a circle. What I want to show today was how I did it and how to use it so that you can make your own scripting tools (or just arrange stuff in a circle).

*The python console can be found in pcbnew under Tools->Scripting Console. *

Step 1: Write the script

When writing a script for pcbnew, it is usually helpful to have some documentation. Some can be found here, though I mostly used "dir" a whole bunch and had it print me the structure of the various things once I found the points to hook in. The documentation is fairly spartan at this point, so that made things easier.

Here's my script:

 1#!/usr/bin/env python2
 2
 3# Random placement helpers because I'm tired of using spreadsheets for doing this
 4#
 5# Kevin Cuzner
 6
 7import math
 8from pcbnew import *
 9
10def place_circle(refdes, start_angle, center, radius, component_offset=0, hide_ref=True, lock=False):
11    """
12    Places components in a circle
13    refdes: List of component references
14    start_angle: Starting angle
15    center: Tuple of (x, y) mils of circle center
16    radius: Radius of the circle in mils
17    component_offset: Offset in degrees for each component to add to angle
18    hide_ref: Hides the reference if true, leaves it be if None
19    lock: Locks the footprint if true
20    """
21    pcb = GetBoard()
22    deg_per_idx = 360 / len(refdes)
23    for idx, rd in enumerate(refdes):
24        part = pcb.FindModuleByReference(rd)
25        angle = (deg_per_idx * idx + start_angle) % 360;
26        print "{0}: {1}".format(rd, angle)
27        xmils = center[0] + math.cos(math.radians(angle)) * radius
28        ymils = center[1] + math.sin(math.radians(angle)) * radius
29        part.SetPosition(wxPoint(FromMils(xmils), FromMils(ymils)))
30        part.SetOrientation(angle * -10)
31        if hide_ref is not None:
32            part.Reference().SetVisible(not hide_ref)
33    print "Placement finished. Press F11 to refresh."

There are several arguments to this function: a list of reference designators (["D1", "D2", "D3"] etc), the angle at which the first component should be placed, the position in mils for the center of the circle, and the radius of the circle in mils. Once the function is invoked, it will find all of the components indicated in the reference designator list and arrange them into the desired circle.

Step 2: Save the script

In order to make life easier, it is best if the script is saved somewhere that the pcbnew python interpreter knows where to look. I found a good location at "/usr/share/kicad/scripting/plugins", but the list of all paths that will be searched can be easily found by opening the python console and executing "import sys" followed by "print(sys.path)". Pick a path that makes sense and save your script there. I saved mine as "placement_helpers.py" since I intend to add more functions to it as situations require.

Step 3: Open your PCB and run the script

Before you can use the scripts on your footprints, they need to be imported. Make sure you execute the "Read Netlist" command before continuing.

The scripting console can be found under Tools->Scripting Console. Once it is opened you will see a standard python (2) command prompt. If you placed your script in a location where the Scripting Console will search, you should be able to do something like the following:

 1PyCrust 0.9.8 - KiCAD Python Shell
 2Python 2.7.13 (default, Feb 11 2017, 12:22:40)
 3[GCC 6.3.1 20170109] on linux2
 4Type "help", "copyright", "credits" or "license" for more information.
 5>>> import placement_helpers
 6>>> placement_helpers.place_circle(["D1", "D2"], 0, (500, 500), 1000)
 7D1: 0
 8D2: 180
 9Placement finished. Press F11 to refresh.
10>>>

Now, pcbnew may not recognize that your PCB has changed and enable the save button. You should do something like lay a trace or some other board modification so that you can save any changes the script made. I'm sure there's a way to trigger this in Python, but I haven't got around to trying it yet.

Conclusion

Hopefully this brief tutorial will either help you to place components in circles in Kicad/pcbnew or will help you to write your own scripts for easing PCB layout. Kicad can be a very capable tool and with its new expanded scripting functionality, the sky seems to be the limit.

The LED Wristwatch: A (more or less) completed project!

About 2009 I saw an article written by Dr. Paul Pounds in which he detailed a pocketwatch he had designed that fit inside a standard pocketwatch case and used LEDs as the dial. While the article has since disappeared, the youtube video remains. The wayback machine has a cached version of the page. Anyway, the idea has kind of stuck with me for a while and so a year or so ago I decided that I wanted to build a wristwatch inspired by that idea.

Although the project started out as an AVR project, I decided after my escapades with the STM32 in August that I really wanted to make it an STM32 project, so around November I started making a new design that used the STM32L052C8 ARM Cortex-M0+ ultra-low power USB microcontroller. The basic concept of the design is to mock up an analog watch face using a ring of LEDs for the hours, minutes, and seconds. I found three full rings to be expecting a bit much if I wanted to keep this small, so I ended up using two rings: One for the hours and another for combined minutes and seconds (the second hand is recognized by the fact that it is "moving" perceptibly).

In this post I'm going to go over my general design, some things I was happy with, and some things that I wasn't happy with. I'll make some follow-up posts for the following topics:

The complete design files can be found here:

https://github.com/kcuzner/led-watch

IMG_20170409_222521.jpg IMG_20170415_194157.jpg