Giter Club home page Giter Club logo

pcbflow's Introduction

pcbflow - Python PCB layout and design (based on CuFlow)

python version Code style: black

https://travis-ci.org/michaelgale/pcbflow codecov https://github.com/michaelgale/pcbflow/issues

This repository contains a python based Printed Circuit Board (PCB) layout and design package based on CuFlow by James Bowman.

This implementation is an experimental variation of CuFlow. It attempts to modularize the components of CuFlow and extend/modify its functionality in some key areas:

  • allow component placement on top or bottom (automatically chooses top or bottom companion layers of silkscreen, soldermask, copper)
  • allow customization of track widths, drill/hole types
  • contain design rules in a class rather than the Board class
  • improve layout metrics
  • robust import of components from Eagle LBR and KiCAD mod files
  • enhanced Gerber files with FileFunction assignments
  • more export formats including stylized views for SVG, PNG, PDF
  • integration with SKiDL for complete scripted EDA workflow

This implementation is alpha and not fully documented.

Requirements

Since the initial release of pcbflow, some changes have been made to adapt with newer versions of python and library dependancies. In particular:

  • the initial versions of pcbflow used shapely v.1.6+. However shapely has changed the way geometries are iterated in v.2.0.1+; therefore pcbflow has been changed to support shapley versions 2.0.1+

pcbflow has been changed to support shapley versions 2.0.1+ ONLY. Check your version with pip list and verify shapley is v.2.0.1+

Installation

The pcbflow package can be installed directly from the source code:

  $ git clone https://github.com/michaelgale/pcbflow.git
  $ cd pcbflow
  $ pip install .

Basic Usage

After installation, the package can imported:

    $ python
    >>> import pcbflow
    >>> pcbflow.__version__

An example of the package can be seen below

from pcbflow import *

# create a 40 mm x 30 mm PCB with outline
brd = Board((40, 30))
brd.add_outline()
# fill the top and bottom copper layers and merge nets named "GND"
brd.fill_layer("GTL", "GND")
brd.fill_layer("GBL", "GND")
# save the PCB asset files
brd.save("mypcb")

Board Object

The Board class is a top level object used to perform all the tasks to build a scripted PCB design in python. Once an instance of Board is created, calling methods to add features and configure the PCB can then be peformed as desired.

PCB Layers

pcbflow creates the following layer stack by default:

  • GML - Mechanical outline
  • GTD - Top side documentation
  • GTP - Top side solder paste
  • GTO - Top side silkscreen
  • GTS - Top side solder mask
  • GTL - Top side copper
  • GBL - Bottom side copper
  • GBS - Bottom side solder mask
  • GBO - Bottom side silkscreen
  • GBP - Bottom side solder paste
  • GBD - Bottom side documentation

Additional internal copper layers can be added as follows:

  brd.add_inner_copper_layer(layer_count=1)

This will insert a copper layer named GP2 inbetween GTL and GBL. Subsequent addition of copper layers will be named GP3, GP4, etc. layer_count specifies how many inner copper layers to add.

Design Rules

A basic set of design rules is stored in the Board.drc attribute. It has the following attributes:

# Copper features
self.trace_width = MILS(8)
self.via_drill = 0.5
self.via_annular_ring = MILS(8)
self.via_track_width = MILS(16)
# Clearances
self.clearance = MILS(8)
self.outline_clearance = MILS(20)
self.hole_clearance = MILS(20)
# Soldermask
self.mask_vias = False
self.mask_holes = True
self.hole_mask = MILS(16)
self.soldermask_margin = MILS(3)
# Other
self.bitmap_res = 0.04
self.silk_width = MILS(6)
self.text_silk_width = MILS(6)

Numeric Values

The default internal representation of numerical values of distance, length, etc. is metric millimetres (mm). However, pcbflow has the following convenience functions to specify values in other units:

  • MILS(x) - thousandths of an inch
  • INCHES(x) - inches
  • MICRONS(x) - micrometres

Holes

You can add standard non-plated through holes as follows:

brd.add_hole((x, y), diameter)

Note that added holes will automatically add a keepout and solder mask margin if specified by the DRC. DRC.hole_clearance specifies the keepout border clearance, DRC.mask_holes enables/disables a solder mask region over the hole with a border width specified by DRC.hole_mask.

To add a plated through hole:

brd.add_drill((x, y), diameter)

Text

Text annotations can be applied to any layer as follows:

brd.add_text((x, y), "ABC",
      scale=1.0,
      angle=0.0,
      side="top",
      layer=None,
      keepout_box=False,
      soldermask_box=False,
      justify="centre")

The side argument can be specified as either top or bottom. This will mirror the text for bottom layers so that it is the correct orientation for fabrication.

keepout_box specifies whether a keepout border region be applied to the text to prevent it from be lost in a poured copper layer for example.

soldermask_box specifies whether a solder mask region be applied so that the text would appear unmasked.

Bitmaps

Arbitrary bitmap logos/annotations can be applied to the PCB as follows:

brd.add_bitmap((x, y), "logo.png", 
  scale=None,
  side="top",
  layer=None,
  keepout_box=False,
  soldermask_box=False)

The bitmap should be a monochrome bitmap image with transparent background. It will be automatically converted into polygons and added to the desired layer. The bitmap size is can be adjusted with the scale parameter. Furthermore, keepout_box and soldermask_box can be applied as desired. Lastly, the side parameter can flip the orientation of the bitmap for bottom side layers if set to bottom

Named Polygons

Arbitary polygon regions can be added to a copper layer with a name corresponding to its net name. For example, this can be used to apply different voltage "patches" under a part requiring several voltages, or to make a split plane of several voltages or GND references.

# add a polygon with a coordinate list
#   add_named_poly(coords, layer, name)
brd.add_named_poly([(1,1), (1,2), (5,1)], layer="GTL", "GND")

# convenience method for making a rectangular polygon with two corner points
#   add_named_rect(top_left, bottom_right, layer, name)
brd.add_named_rect((1, 10), (20, 3), "GBL", "VCC")

Parts

Parts can be added in four ways:

  1. Drawing directly with primitives in class derived from PCBPart (see the footprints folder for examples)
  2. Importing a package from an Eagle library file using EaglePart
  3. Importing a footprint from a KiCAD footprint library file using KiCadPart
  4. Instantiating a part from a SKiDL circuit using SkiPart
# adding a generic part with SOT23(Part)
brd.add_part((10, 20), SOT23, side="top")
# adding a generic R0603(PCBPart) SMD resistor by passing the board "Drawing Context" (DC)
#   PCBPart classes instantiate themselves directly from DC--this allows the part
#   to derive its location, orientation, etc.
R0603(brd.DC((20, 10)), "4.7k", side="bottom")
# this is also equivalent:
brd.add_part((20, 10), R0603, val="4.7k", side="bottom")

# We can add multiple parts with an iterator:
for x in range(5):
    brd.add_part((5 + x*3, 4), C0402, val="0.1u", side="top")

# adding an Eagle part called USB-B-SMT from sparkfun.lbr
# chaining the right(90) method to DC places the part 90 deg rotated
EaglePart(brd.DC((10, 10)).right(90), libraryfile="sparkfun.lbr", partname="USB-B-SMT", side="top")
# this is also equivalent:
brd.add_part((10, 10), EaglePart, libraryfile="sparkfun.lbr", partname="USB-B-SMT", side="top", rot=90)

# adding a KiCAD footprint part from file kc1.kicad_mod
# specifying the side="bottom" automatically maps the footprint copper, mask, paste,
# and silkscreen layers to the bottom (automatically mirroring in the horizontal axis)
KiCadPart(brd.DC((10, 10)), libraryfile="kc1.kicad_mod", side="bottom")
# this is also equivalent:
brd.add_part((10, 10), KiCadPart, libraryfile="kc1.kicad_mod", side="bottom")

# assigning a variable to a placed part allow us to reference it again
# later for tasks such as renaming pads, routing signals from a pad location,
# routing a group of signals as a bus (or "river" in CuFlow), etc.
usb_con = EaglePart(brd.DC((10, 10)), libraryfile="sparkfun.lbr", partname="USB-B-SMT", side="top")
# route a wire from pad 3 to 5 mm right, 10 mm up with a width 0.25 mm
# if width is omitted it will use the default trace_width in Board.DRC
usb_con.pads[3].w("r 90 f 5 l 90 f 10").wire(width=0.25)

# print a PCBPart's details (pad 3 happens to be the USB connector's D- line)
print(usb_con)
# Part: 3   top    ( 10.00,  10.00) / 0 deg  6 pads
#   0: 5 (10.58, 16.80)    1: 6 (10.58, 3.20)     2: D+ (17.00, 11.88)   3: D- (22.00, 20.62)   4: GND (17.00, 9.38)
#   5: VUSB (17.00, 8.12)

# alternatively, we can reference the pad by name to do the same thing
usb_con.pad("D-").turtle("r 90 f 5 l 90 f 10").wire(width=0.25)     

Saving Asset Files

pcbflow can generate a variety of output asset files representing the PCB. These include:

  • Gerber files for fabrication
  • Bill of Materials (BOM) CSV file
  • Centroids of parts CSV file
  • SVG preview renders of the top, bottom, or all layer views
  • Postscript preview render
  • Povray raytracing files

Outfiles can be created in the same folder as the script file or in a subfolder under the script (generated automatically). To generate asset files:

brd.save(basename, in_subdir=True, 
  gerber=True, pdf=True, bom=True, centroids=True, povray=False)

The in_subdir argument specifies whether a subfolder named basename should be created for the assets. The gerber, pdf, bom, centroids, povray arguments specify which of the asset types to generate.

Alternatively, individual asset types can be generated using these convenience methods:

brd.save_gerbers(basename, in_subdir=True)
brd.save_pdf(basename, in_subdir=True)
brd.save_png(basename, in_subdir=True)
brd.save_svg(basename, in_subdir=True)
brd.save_centroids(basename, in_subdir=True)
brd.save_bom(basename, in_subdir=True)

Putting it Together with SKiDL

pcbflow is best used as a companion to SKiDL. SKiDL is a python based tool which allows you to script the design of electronic circuits. SKiDL integrates with KiCAD symbol and footprint libraries to enable seamless building of circuits with a rich library of pre-built parts.

After a circuit has been designed and validated with SKiDL, pcbflow can then be used to physically render the circuit on to a PCB. The attributes of the PCB including its size, shape, layer stack-up, as well as some basic design rules can be customized as desired with python code. A typical workflow will consist of the following steps:

  1. Generally, a script file will start with a SKiDL circuit definition. This will consist of various Part and Net declarations followed by code which makes net connections among parts.
  2. Next, a pcbflow Board instance can be declared and various Board methods can be used to configure the basic attributes of the PCB such as its size, layers, etc.
  3. Parts declared in SKiDL can then be placed on the PCB. This consists of accessing SKiDL parts either by iterating through the default_circuit.parts attribute or iterating over Part assignments explictly made in the code (e.g. mcu = Part("DSP_Microchip_DSPIC33", "DSPIC33EP256MU806-xPT", footprint="TQFP-64_10x10mm_P0.5mm",))
  4. Each part will require the instantiation of a SkiPart(brd.DC(x, y), part, side=side) object. This explictly tells pcbflow where the part should physically be placed on the PCB with its x, y coordinates and on which side of the PCB it is placed ("top" or "bottom"). The SkiPart object initialization can be passed a native SKiDL Part instance in order to derive the physical footprint, reference designator, family, etc.
  5. After parts have been placed, network connections can then be made using a combination of pcbflow operations including:
    • "fanout" pads to named vias
    • adding named polygons which can absorb a via connection or part pad of the same net name
    • "turtle" style routing commands to physically describe a net route path
  6. Special PCB features such as "keepout" regions, text annotations, bitmap logos, mounting holes, etc. can be added to the PCB as desired.
  7. If any layers are desired to be "flooded" with a named signal (e.g. a GND fill), then the Board.fill_layer() method can be called on any of the PCB layers as required.
  8. Lastly, the rendered PCB can be saved to a variety of asset files as desired including:
    • Gerber files for fabrication
    • BOM and centroid placement CSV files
    • PDF, SVG, PNG preview files for iterative checking of the board appearance or documentation

An example script is shown below:

import os
import math
import glob
import shapely.geometry as sg

from pcbflow import *
from skidl import *


if __name__ == "__main__":
    ###
    ### SKiDL Circuit Declarations
    ###

    # Declare microcontroller
    mcu = Part(
        "DSP_Microchip_DSPIC33",
        "DSPIC33EP256MU806-xPT",
        footprint="TQFP-64_10x10mm_P0.5mm",
    )
    # Declare a generic 0603 capacitor
    cap = Part(
        "Device",
        "C",
        footprint="C_0603_1608Metric_Pad1.08x0.95mm_HandSolder",
        dest=TEMPLATE,
    )
    # Declare 3 instances of our generic capacitor with values
    c1 = cap(value="10uF")
    c2 = cap(value="0.1uF")
    c3 = cap(value="0.1uF")

    # Create GND and VDD nets
    vdd = Net("VDD")
    gnd = Net("GND")

    # Assign VDD and GND to our parts
    mcu["VDD"] += vdd
    mcu["VSS"] += gnd
    for c in [c1, c2, c3]:
        c[1] += vdd
        c[2] += gnd

    ###
    ### pcbflow PCB Declarations
    ###

    # Create a pcbflow Board instance
    brd = Board((55, 30))
    
    # add two inner copper layers (named GP2, GP3)
    brd.add_inner_copper_layer(2)
    # Place 2 mm mounting holes in the corners
    holes = ((5, 5), (5, 25), (50, 5), (50, 25))
    for hole in holes:
        brd.add_hole(hole, 2.0)
    # Add some text (silkscreen on the top), as copper on the bottom
    brd.add_text((10, 25), "Made with pcbflow", justify="left")
    brd.add_text((10, 25), "Made with pcbflow", layer="GBL", keepout_box=True, justify="left")

    # Place a VDD patch under MCU on layer GP3
    brd.add_named_rect((27, 25), (45, 5), layer="GP3", name="VDD")

    # Assign a convenient reference to the default SKiDL circuit
    ckt = default_circuit

    print("Circuit:  Parts: %d  Nets: %d" % (len(ckt.parts), len(ckt.nets)))

    # Assign part locations (we're adding an extra atrribute to the skidl.Part object)
    mcu.loc = (35, 15)
    c1.loc = (25,15)
    c2.loc = (45,15)
    c3.loc = (37,6.5)
    sides = ["top", "bottom", "top", "bottom"]

    # Instantiate SkiPart(PCBPart) instances
    for part, side in zip(ckt.parts, sides):
        sp = SkiPart(brd.DC(part.loc), part, side=side)
        # "fanout" GND and VDD vias from parts with GND and VDD net connections
        sp.fanout(["VDD"])
        sp.fanout(["GND"], relative_to="inside")

    print(brd.parts_str())
    
    # finish the PCB with an outline and poured copper layers
    brd.add_outline()
    brd.fill_layer("GTL", "GND")
    brd.fill_layer("GBL", "GND")
    brd.fill_layer("GP3", "GND")

    # Save the rendered PCB to asset files 
    brd.save("%s" % (os.path.basename(__file__)[:-3]))
Top Top Document
Bottom Bottom Document
All

To Do

  • Routing and Nets
  • DRC checking
  • More tests
  • CI

Releases

None yet.

Authors

pcbflow was written by Michael Gale and is based on the CuFlow package by James Bowman.

pcbflow's People

Contributors

michaelgale avatar sebouh137 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

pcbflow's Issues

Unable to open KiCad footprints and libraries

I cannot complete any of the examples, except for the ones that do not include any parts:

l_code$ python esp32_motor-pcb-x3_final.py
Circuit:  Parts: 17  Nets: 36
Traceback (most recent call last):
  File "/home/twinlizzie/Ngnuity-Repos/sylvie-2024/schematics/skidl_code/esp32_motor-pcb-x3_final.py", line 270, in <module>
    sp = SkiPart(brd.DC(part.loc), part, side=side)
  File "/home/twinlizzie/miniconda3/lib/python3.10/site-packages/pcbflow/kicad.py", line 286, in __init__
    lfn = self._find_footprint_file(skipart.footprint)
  File "/home/twinlizzie/miniconda3/lib/python3.10/site-packages/pcbflow/kicad.py", line 316, in _find_footprint_file
    raise FileNotFoundError("Unable to find KiCAD footprints directory")
FileNotFoundError: Unable to find KiCAD footprints directory

Not sure how to set the footprint directory. I've tried modifying kicad.py itself, with a little bit of luck, though it only leads to more errors.

Code:

import os
import sys
import math
import glob
import shapely.geometry as sg

from pcbflow import *
from skidl import *

# Set the default tool to KiCad 7 for footprint management.
set_default_tool(KICAD7)

if __name__ == "__main__":
    ###
    ### SKiDL Circuit Declarations
    ###

	# Create ESP32 and TMC5160 headers with updated part names
	esp32_header1 = Part("Connector_Generic", "Conn_01x15", footprint="PinSocket_1x15_P2.54mm_Vertical")
	esp32_header2 = Part("Connector_Generic", "Conn_01x15", footprint="PinSocket_1x15_P2.54mm_Vertical")
	
	tmc5160_header1 = Part("Connector_Generic", "Conn_01x08", footprint="PinSocket_1x08_P2.54mm_Vertical")
	tmc5160_header2 = Part("Connector_Generic", "Conn_01x08", footprint="PinSocket_1x08_P2.54mm_Vertical")
	
	tmc5160_header1b = Part("Connector_Generic", "Conn_01x08", footprint="PinSocket_1x08_P2.54mm_Vertical")
	tmc5160_header2b = Part("Connector_Generic", "Conn_01x08", footprint="PinSocket_1x08_P2.54mm_Vertical")
	
	tmc5160_header1c = Part("Connector_Generic", "Conn_01x08", footprint="PinSocket_1x08_P2.54mm_Vertical")
	tmc5160_header2c = Part("Connector_Generic", "Conn_01x08", footprint="PinSocket_1x08_P2.54mm_Vertical")
	
	# Create 1x4 connector for stepper motor connections
	stepper_motor_header = Part("Connector_Generic", "Conn_01x04", footprint="PinHeader_1x04_P2.54mm_Vertical")
	stepper_motor_header_b = Part("Connector_Generic", "Conn_01x04", footprint="PinHeader_1x04_P2.54mm_Vertical")
	stepper_motor_header_c = Part("Connector_Generic", "Conn_01x04", footprint="PinHeader_1x04_P2.54mm_Vertical")
	
	# Create 1x4 connector for CAN Bus connections
	can_bus_header = Part("Connector_Generic", "Conn_01x04", footprint="PinHeader_1x04_P2.54mm_Vertical")
	
	# Create 100uF 63V capacitor with correct footprint
	capacitor = Part("Device", "C", value="100uF", voltage="63V", footprint="Capacitor_THT:CP_Radial_D10.0mm_P5.00mm")
	capacitor_b = Part("Device", "C", value="100uF", voltage="63V", footprint="Capacitor_THT:CP_Radial_D10.0mm_P5.00mm")
	capacitor_c = Part("Device", "C", value="100uF", voltage="63V", footprint="Capacitor_THT:CP_Radial_D10.0mm_P5.00mm")
	
	# Create a 3-pin terminal block for 36V connections
	terminal_block = Part("Connector_Generic", "Conn_01x03", footprint="TerminalBlock_Phoenix_PT-1,5-2-5.0-H_1x02_P5.00mm_Horizontal")
	
	# Create through-hole solder pads for 36V+ and 36V_GND connections with 2.54mm spacing
	terminal_block_2 = Part("Connector_Generic", "Conn_01x02", footprint="TerminalBlock_Phoenix_MPT-0,5-2-2.54_1x02_P2.54mm_Horizontal")
	
	# Create 36V_V+ and 36V_GND nets.
	V_plus_36V = Net("36V_V+")
	GND_36V = Net("36V_GND")
	
	# Define the GPIO pins according to ESP32 30pin version.
	esp32_vin = esp32_header1[1]
	esp32_gnd1 = esp32_header1[2]
	esp32_3v3 = esp32_header2[1]
	esp32_gnd2 = esp32_header2[2]
	esp32_gpio2 = esp32_header2[4]
	esp32_gpio4 = esp32_header2[5]
	esp32_gpio5 = esp32_header2[8]
	esp32_gpio12 = esp32_header1[4]
	esp32_gpio13 = esp32_header1[3]
	esp32_gpio14 = esp32_header1[5]
	esp32_gpio15 = esp32_header2[3]
	esp32_gpio16 = esp32_header2[6]
	esp32_gpio17 = esp32_header2[7]
	esp32_gpio18 = esp32_header2[9]
	esp32_gpio19 = esp32_header2[10]
	esp32_gpio21 = esp32_header2[11]
	esp32_gpio22 = esp32_header2[14]
	esp32_gpio23 = esp32_header2[15]
	esp32_gpio25 = esp32_header1[8]
	esp32_gpio26 = esp32_header1[7]
	esp32_gpio27 = esp32_header1[6]
	esp32_gpio32 = esp32_header1[10]
	esp32_gpio33 = esp32_header1[9]
	
	# Define the pins for TMC5160
	tmc5160_pins = {
	    'gnd2': tmc5160_header1[8], 
	    '3v3': tmc5160_header1[7],
	    'm2b': tmc5160_header1[6],
	    'm1b': tmc5160_header1[5],
	    'm1a': tmc5160_header1[4],
	    'm2a': tmc5160_header1[3],
	    'gnd1': tmc5160_header1[2],
	    'vmot': tmc5160_header1[1],
	    'en': tmc5160_header2[1],
	    'sdi': tmc5160_header2[2],
	    'sck': tmc5160_header2[3],
	    'csn': tmc5160_header2[4],
	    'sdo': tmc5160_header2[5],
	    'step': tmc5160_header2[7],
	    'dir': tmc5160_header2[8]
	}
	
	# Define the pins for TMC5160b
	tmc5160b_pins = {
	    'gnd2': tmc5160_header1b[8], 
	    '3v3': tmc5160_header1b[7],
	    'm2b': tmc5160_header1b[6],
	    'm1b': tmc5160_header1b[5],
	    'm1a': tmc5160_header1b[4],
	    'm2a': tmc5160_header1b[3],
	    'gnd1': tmc5160_header1b[2],
	    'vmot': tmc5160_header1b[1],
	    'en': tmc5160_header2b[1],
	    'sdi': tmc5160_header2b[2],
	    'sck': tmc5160_header2b[3],
	    'csn': tmc5160_header2b[4],
	    'sdo': tmc5160_header2b[5],
	    'step': tmc5160_header2b[7],
	    'dir': tmc5160_header2b[8]
	}
	
	# Define the pins for TMC5160c
	tmc5160c_pins = {
	    'gnd2': tmc5160_header1c[8], 
	    '3v3': tmc5160_header1c[7],
	    'm2b': tmc5160_header1c[6],
	    'm1b': tmc5160_header1c[5],
	    'm1a': tmc5160_header1c[4],
	    'm2a': tmc5160_header1c[3],
	    'gnd1': tmc5160_header1c[2],
	    'vmot': tmc5160_header1c[1],
	    'en': tmc5160_header2c[1],
	    'sdi': tmc5160_header2c[2],
	    'sck': tmc5160_header2c[3],
	    'csn': tmc5160_header2c[4],
	    'sdo': tmc5160_header2c[5],
	    'step': tmc5160_header2c[7],
	    'dir': tmc5160_header2c[8]
	}
	
	# Create VIN and GND nets.
	vin = Net("VIN")
	gnd = Net("GND")
	
	# Create 3.3v gnd net.
	vcc_gnd = Net("VCC_GND")
	
	# Connect 36V_V+ and 36V_GND to the terminal block
	V_plus_36V += terminal_block[1]  # Connect 36V_V+ to the first pin of the PT terminal block slot 1
	GND_36V += terminal_block[2]     # Connect 36V_GND to the third pin of the PT terminal block slot 2
	
	# Connect VIN and GND to ESP32 header 2.
	vin += terminal_block_2[1] # Connect VIN to the MPT TerminalBlock slot 1
	gnd += terminal_block_2[2] # Connect GND to the MPT TerminalBlock slot 2
	
	# Connect capacitor between 36V_V+ and 36V_GND nets
	capacitor[1, 2] += V_plus_36V, GND_36V
	capacitor_b[1, 2] += V_plus_36V, GND_36V
	capacitor_c[1, 2] += V_plus_36V, GND_36V
	
	# Connect one pin of the limit switch header to the resistor and the other pin to ESP32 3.3v (Pull-down Resistor!)
	# limit_switch_header[1] += resistor1[2], esp32_header1[5]  # Connect pin 1 of limit switch header to one pin of the resistor, and pin 5 on esp32 header 1
	# limit_switch_header[2] += esp32_header2[1]           # Connect pin 2 of limit switch header to ESP32 3.3v pin
	
	# Connect VIN and GND to ESP32 and TMC5160 pins.
	vin += esp32_vin
	gnd += esp32_gnd1
	
	vcc_gnd += esp32_gnd2
	
	# vcc_gnd += resistor1[1] # GND connected to Resistor pin 1
	
	# Connect all the CAN Bus headers to the ESP32 Header 2
	can_bus_header[1] += esp32_3v3 # 3.3v
	can_bus_header[2] += esp32_gnd2 # GND
	can_bus_header[3] += esp32_gpio4 # CAN TX
	can_bus_header[4] += esp32_gpio5 # CAN RX
	
	# First TMC5160 Instance
	esp32_3v3 += tmc5160_pins['3v3']
	esp32_gnd2 += tmc5160_pins['gnd2']
	V_plus_36V += tmc5160_pins['vmot']
	GND_36V += tmc5160_pins['gnd1']
	vcc_gnd += tmc5160_pins['gnd2']
	esp32_gpio13 += tmc5160_pins['dir']
	esp32_gpio12 += tmc5160_pins['step']
	esp32_gpio15 += tmc5160_pins['en']
	esp32_gpio23 += tmc5160_pins['sdi']
	esp32_gpio19 += tmc5160_pins['sdo']
	esp32_gpio18 += tmc5160_pins['sck']
	esp32_gpio14 += tmc5160_pins['csn']
	stepper_motor_header[1] += tmc5160_pins['m2a']
	stepper_motor_header[2] += tmc5160_pins['m1a']
	stepper_motor_header[3] += tmc5160_pins['m1b']
	stepper_motor_header[4] += tmc5160_pins['m2b']
	
	# Second TMC5160 Instance
	esp32_3v3 += tmc5160b_pins['3v3']
	esp32_gnd2 += tmc5160b_pins['gnd2']
	V_plus_36V += tmc5160b_pins['vmot']
	GND_36V += tmc5160b_pins['gnd1']
	vcc_gnd += tmc5160b_pins['gnd2']
	esp32_gpio27 += tmc5160b_pins['dir']
	esp32_gpio26 += tmc5160b_pins['step']
	esp32_gpio17 += tmc5160b_pins['en']
	esp32_gpio23 += tmc5160b_pins['sdi']
	esp32_gpio19 += tmc5160b_pins['sdo']
	esp32_gpio18 += tmc5160b_pins['sck']
	esp32_gpio25 += tmc5160b_pins['csn']
	stepper_motor_header_b[1] += tmc5160b_pins['m2a']
	stepper_motor_header_b[2] += tmc5160b_pins['m1a']
	stepper_motor_header_b[3] += tmc5160b_pins['m1b']
	stepper_motor_header_b[4] += tmc5160b_pins['m2b']
	
	# Third TMC5160 Instance
	esp32_3v3 += tmc5160c_pins['3v3']
	esp32_gnd2 += tmc5160c_pins['gnd2']
	V_plus_36V += tmc5160c_pins['vmot']
	GND_36V += tmc5160c_pins['gnd1']
	vcc_gnd += tmc5160c_pins['gnd2']
	esp32_gpio32 += tmc5160c_pins['dir']
	esp32_gpio2 += tmc5160c_pins['step']
	esp32_gpio22 += tmc5160c_pins['en']
	esp32_gpio23 += tmc5160c_pins['sdi']
	esp32_gpio19 += tmc5160c_pins['sdo']
	esp32_gpio18 += tmc5160c_pins['sck']
	esp32_gpio33 += tmc5160c_pins['csn']
	stepper_motor_header_c[1] += tmc5160c_pins['m2a']
	stepper_motor_header_c[2] += tmc5160c_pins['m1a']
	stepper_motor_header_c[3] += tmc5160c_pins['m1b']
	stepper_motor_header_c[4] += tmc5160c_pins['m2b']

    ###
    ### pcbflow PCB Declarations
    ###

	# Create a pcbflow Board instance
	brd = Board((100, 100))  # Adjust the board size as per your requirement

	brd.add_inner_copper_layer(2)

	# Place 2 mm mounting holes in the corners
	holes = ((5, 5), (5, 25), (50, 5), (50, 25))
	for hole in holes:
		brd.add_hole(hole, 2.0)

	# Assign a convenient reference to the default SKiDL circuit
	ckt = default_circuit

	print("Circuit:  Parts: %d  Nets: %d" % (len(ckt.parts), len(ckt.nets)))

	# Assign part locations
	esp32_header1.loc = (35, 15)
	esp32_header2.loc = (45, 15)
	tmc5160_header1.loc = (25, 15)
	tmc5160_header2.loc = (55, 15)
	tmc5160_header1b.loc = (20, 10)
	tmc5160_header2b.loc = (60, 10)
	tmc5160_header1c.loc = (15, 5)
	tmc5160_header2c.loc = (65, 5)
	stepper_motor_header.loc = (30, 5)
	stepper_motor_header_b.loc = (50, 5)
	stepper_motor_header_c.loc = (70, 5)
	can_bus_header.loc = (65, 5)
	capacitor.loc = (25, 5)
	capacitor_b.loc = (45, 5)
	capacitor_c.loc = (65, 5)
	terminal_block.loc = (70, 5)
	terminal_block_2.loc = (75, 5)

	# Instantiate SkiPart(PCBPart) instances
	sides = ["top"] * 17  # Assuming all parts are on the top side

	for part, side in zip(ckt.parts, sides):
		sp = SkiPart(brd.DC(part.loc), part, side=side)
		# "fanout" GND and VDD vias from parts with GND and VDD net connections
		sp.fanout(["VDD"])
		sp.fanout(["GND"], relative_to="inside")


	# Finish the PCB with an outline and poured copper layers
	brd.add_outline()
	brd.fill_layer("GTL", "GND")
	brd.fill_layer("GBL", "GND")

	# Save the rendered PCB to asset files
	brd.save("%s" % (os.path.basename(__file__)[:-3]))

	# Generate the netlist (if required)
	generate_netlist()  # If you need to generate a netlist, add this line

	print("PCB design completed.")

Outer Limits

I think that this should have a skidl interface. basic rectangle packer with margins for rivers. Then add nmigen for a logic solver.

setup.py error: can't create or remove files in install directory (Windows & Ubuntu)

Sorry, the root cause is clearly that I'm a python newbie. I'm running on Windows 10 with python 3.9 installed from the Microsoft Store.

Python 3.9.4 (tags/v3.9.4:1f2e308, Apr 4 2021, 13:27:16) [MSC v.1928 64 bit (AMD64)] on win32

Following the readme, I've cloned from github and run setup:

PS C:\try\pcbflow> python setup.py install
running install
error: can't create or remove files in install directory

The following error occurred while trying to add or remove files in the
installation directory:

    [Errno 13] Permission denied: 'C:\\Program Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.9_3.9.1264.0_x64__qbz5n2kfra8p0\\Lib\\site-packages\\test-easy-install-18976.write-test'

The installation directory you specified (via --install-dir, --prefix, or
the distutils default setting) was:

    C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1264.0_x64__qbz5n2kfra8p0\Lib\site-packages\  

Perhaps your account does not have write access to this directory?  If the
installation directory is a system-owned directory, you may need to sign in
as the administrator or "root" account.  If you do not have administrative
access to this machine, you may wish to choose a different installation
directory, preferably one that is listed in your PYTHONPATH environment
variable.

For information on other options, you may wish to consult the
documentation at:

  https://setuptools.readthedocs.io/en/latest/easy_install.html

Please make the appropriate changes for your system and try again.

Questions About the Project

@michaelgale I noticed your name on this and thought I would take a look at this since you are also a member of the CadQuery community. It seems like this Python-based workflow could be a nice complement to mechanical design in CadQuery. I do have a couple of questions which I do not think were answered in the readme.

  1. The readme states that this library is experimental/alpha. Is it being used in production anywhere?
  2. I am assuming that it should be possible to create a design that can be configured to toggle between thru-hole and surface-mount parts. Is that a correct assumption? I do have a reason for asking this.

setup.py: error: Could not find module 'geos_c.dll' (or one of its dependencies)...

OK, I gave it a try with a completely different python distribution (anaconda) and a virtual environment (best as I understand it.) Running setup now gives me a different error message. Does this one look familiar to you?

setup.py: error: Could not find module 'geos_c.dll' (or one of its dependencies). Try using the full path with constructor syntax. 

My commands were:

PS C:\try\pcbflow> python -m venv create .venv
PS C:\try\pcbflow> .\.venv\Scripts\activate
(.venv) PS C:\try\pcbflow> python .\setup.py install

it ended with:

...
Installed c:\try\pcbflow\.venv\lib\site-packages\pytest-6.2.3-py3.8.egg
Searching for shapely
Reading https://pypi.org/simple/shapely/
Downloading https://files.pythonhosted.org/packages/de/30/e0492acfbb8d5ddd077dff5e5a3f9f85be420d17950b9941cdc2519bd7f0/Shapely-1.8a1.tar.gz#sha256=a748ab74c187060264e7ce838aaac30eead2a791bbea8cc3ab1dfc3cc0b4d067
Best match: Shapely 1.8a1
Processing Shapely-1.8a1.tar.gz
Writing C:\Users\burt_\AppData\Local\Temp\easy_install-59dgfngt\Shapely-1.8a1\setup.cfg
Running Shapely-1.8a1\setup.py -q bdist_egg --dist-dir C:\Users\burt_\AppData\Local\Temp\easy_install-59dgfngt\Shapely-1.8a1\egg-dist-tmp-uc_n5izi
error: Could not find module 'geos_c.dll' (or one of its dependencies). Try using the full path with constructor syntax.
(.venv) PS C:\try\pcbflow>

Examples error on a fresh install

$ git clone https://github.com/michaelgale/pcbflow.git
Cloning into 'pcbflow'...
remote: Enumerating objects: 645, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 645 (delta 18), reused 15 (delta 15), pack-reused 622
Receiving objects: 100% (645/645), 4.82 MiB | 4.85 MiB/s, done.
Resolving deltas: 100% (450/450), done.
$ cd pcbflow
$ python setup.py install
running install
/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
  warnings.warn(
/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/setuptools/command/easy_install.py:144: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.
  warnings.warn(
running bdist_egg
running egg_info
creating pcbflow.egg-info
writing pcbflow.egg-info/PKG-INFO
writing dependency_links to pcbflow.egg-info/dependency_links.txt
writing requirements to pcbflow.egg-info/requires.txt
writing top-level names to pcbflow.egg-info/top_level.txt
writing manifest file 'pcbflow.egg-info/SOURCES.txt'
reading manifest file 'pcbflow.egg-info/SOURCES.txt'
adding license file 'LICENSE.md'
writing manifest file 'pcbflow.egg-info/SOURCES.txt'
installing library code to build/bdist.macosx-12.3-arm64/egg
running install_lib
running build_py
creating build
creating build/lib
creating build/lib/pcbflow
copying pcbflow/gerber.py -> build/lib/pcbflow
copying pcbflow/board.py -> build/lib/pcbflow
copying pcbflow/excellon.py -> build/lib/pcbflow
copying pcbflow/kicad.py -> build/lib/pcbflow
copying pcbflow/util.py -> build/lib/pcbflow
copying pcbflow/route.py -> build/lib/pcbflow
copying pcbflow/__init__.py -> build/lib/pcbflow
copying pcbflow/sexp_parser.py -> build/lib/pcbflow
copying pcbflow/drc.py -> build/lib/pcbflow
copying pcbflow/hershey.py -> build/lib/pcbflow
copying pcbflow/eagle.py -> build/lib/pcbflow
copying pcbflow/layer.py -> build/lib/pcbflow
copying pcbflow/svgout.py -> build/lib/pcbflow
copying pcbflow/part.py -> build/lib/pcbflow
copying pcbflow/draw.py -> build/lib/pcbflow
creating build/lib/pcbflow/footprints
copying pcbflow/footprints/sot.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/xtal.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/pin_header.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/__init__.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/tssop.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/special_conn.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/special_pcb.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/smd_discrete.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/soic.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/qfn.py -> build/lib/pcbflow/footprints
copying pcbflow/footprints/bga.py -> build/lib/pcbflow/footprints
creating build/bdist.macosx-12.3-arm64
creating build/bdist.macosx-12.3-arm64/egg
creating build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/gerber.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/board.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/excellon.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/kicad.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/util.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
creating build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/sot.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/xtal.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/pin_header.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/__init__.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/tssop.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/special_conn.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/special_pcb.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/smd_discrete.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/soic.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/qfn.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/footprints/bga.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints
copying build/lib/pcbflow/route.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/__init__.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/sexp_parser.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/drc.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/hershey.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/eagle.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/layer.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/svgout.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/part.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
copying build/lib/pcbflow/draw.py -> build/bdist.macosx-12.3-arm64/egg/pcbflow
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/gerber.py to gerber.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/board.py to board.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/excellon.py to excellon.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/kicad.py to kicad.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/util.py to util.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/sot.py to sot.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/xtal.py to xtal.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/pin_header.py to pin_header.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/__init__.py to __init__.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/tssop.py to tssop.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/special_conn.py to special_conn.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/special_pcb.py to special_pcb.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/smd_discrete.py to smd_discrete.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/soic.py to soic.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/qfn.py to qfn.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/footprints/bga.py to bga.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/route.py to route.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/__init__.py to __init__.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/sexp_parser.py to sexp_parser.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/drc.py to drc.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/hershey.py to hershey.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/eagle.py to eagle.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/layer.py to layer.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/svgout.py to svgout.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/part.py to part.cpython-310.pyc
byte-compiling build/bdist.macosx-12.3-arm64/egg/pcbflow/draw.py to draw.cpython-310.pyc
creating build/bdist.macosx-12.3-arm64/egg/EGG-INFO
installing scripts to build/bdist.macosx-12.3-arm64/egg/EGG-INFO/scripts
running install_scripts
running build_scripts
creating build/scripts-3.10
copying scripts/lbrlist.py -> build/scripts-3.10
copying scripts/kilist.py -> build/scripts-3.10
changing mode of build/scripts-3.10/lbrlist.py from 644 to 755
changing mode of build/scripts-3.10/kilist.py from 644 to 755
creating build/bdist.macosx-12.3-arm64/egg/EGG-INFO/scripts
copying build/scripts-3.10/kilist.py -> build/bdist.macosx-12.3-arm64/egg/EGG-INFO/scripts
copying build/scripts-3.10/lbrlist.py -> build/bdist.macosx-12.3-arm64/egg/EGG-INFO/scripts
changing mode of build/bdist.macosx-12.3-arm64/egg/EGG-INFO/scripts/kilist.py to 755
changing mode of build/bdist.macosx-12.3-arm64/egg/EGG-INFO/scripts/lbrlist.py to 755
copying pcbflow.egg-info/PKG-INFO -> build/bdist.macosx-12.3-arm64/egg/EGG-INFO
copying pcbflow.egg-info/SOURCES.txt -> build/bdist.macosx-12.3-arm64/egg/EGG-INFO
copying pcbflow.egg-info/dependency_links.txt -> build/bdist.macosx-12.3-arm64/egg/EGG-INFO
copying pcbflow.egg-info/requires.txt -> build/bdist.macosx-12.3-arm64/egg/EGG-INFO
copying pcbflow.egg-info/top_level.txt -> build/bdist.macosx-12.3-arm64/egg/EGG-INFO
zip_safe flag not set; analyzing archive contents...
pcbflow.__pycache__.__init__.cpython-310: module references __file__
creating dist
creating 'dist/pcbflow-0.1.0-py3.10.egg' and adding 'build/bdist.macosx-12.3-arm64/egg' to it
removing 'build/bdist.macosx-12.3-arm64/egg' (and everything under it)
Processing pcbflow-0.1.0-py3.10.egg
creating /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pcbflow-0.1.0-py3.10.egg
Extracting pcbflow-0.1.0-py3.10.egg to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding pcbflow 0.1.0 to easy-install.pth file
Installing kilist.py script to /Users/russ/.asdf/installs/python/3.10.6/bin
Installing lbrlist.py script to /Users/russ/.asdf/installs/python/3.10.6/bin

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pcbflow-0.1.0-py3.10.egg
Processing dependencies for pcbflow==0.1.0
Searching for cairosvg
Reading https://pypi.org/simple/cairosvg/
/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pkg_resources/__init__.py:123: PkgResourcesDeprecationWarning:  is an invalid version and will not be supported in a future release
  warnings.warn(
/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pkg_resources/__init__.py:123: PkgResourcesDeprecationWarning: 2.0.0rc1.linux-x86-64 is an invalid version and will not be supported in a future release
  warnings.warn(
/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pkg_resources/__init__.py:123: PkgResourcesDeprecationWarning: x86-64 is an invalid version and will not be supported in a future release
  warnings.warn(
/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pkg_resources/__init__.py:123: PkgResourcesDeprecationWarning: 2.1.3.linux-x86-64 is an invalid version and will not be supported in a future release
  warnings.warn(
Downloading https://files.pythonhosted.org/packages/01/a5/1866b42151f50453f1a0d28fc4c39f5be5f412a2e914f33449c42daafdf1/CairoSVG-2.7.1-py3-none-any.whl#sha256=8a5222d4e6c3f86f1f7046b63246877a63b49923a1cd202184c3a634ef546b3b
Best match: CairoSVG 2.7.1
Processing CairoSVG-2.7.1-py3-none-any.whl
Installing CairoSVG-2.7.1-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding CairoSVG 2.7.1 to easy-install.pth file
Installing cairosvg script to /Users/russ/.asdf/installs/python/3.10.6/bin

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/CairoSVG-2.7.1-py3.10.egg
Searching for svgwrite
Reading https://pypi.org/simple/svgwrite/
Downloading https://files.pythonhosted.org/packages/84/15/640e399579024a6875918839454025bb1d5f850bb70d96a11eabb644d11c/svgwrite-1.4.3-py3-none-any.whl#sha256=bb6b2b5450f1edbfa597d924f9ac2dd099e625562e492021d7dd614f65f8a22d
Best match: svgwrite 1.4.3
Processing svgwrite-1.4.3-py3-none-any.whl
Installing svgwrite-1.4.3-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding svgwrite 1.4.3 to easy-install.pth file

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/svgwrite-1.4.3-py3.10.egg
Searching for pytest
Reading https://pypi.org/simple/pytest/
Downloading https://files.pythonhosted.org/packages/42/8f/609a38adb94cf52f8e4bf1aafa072dcf5d08fa3cb76c506517ea0ae042d5/pytest-8.0.0rc1-py3-none-any.whl#sha256=6c30d4c4409c5d227ef936678b72c56b6fbaed28a6ee4eafd2c93ed9a24c65af
Best match: pytest 8.0.0rc1
Processing pytest-8.0.0rc1-py3-none-any.whl
Installing pytest-8.0.0rc1-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding pytest 8.0.0rc1 to easy-install.pth file
Installing py.test script to /Users/russ/.asdf/installs/python/3.10.6/bin
Installing pytest script to /Users/russ/.asdf/installs/python/3.10.6/bin

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pytest-8.0.0rc1-py3.10.egg
Searching for cssselect2
Reading https://pypi.org/simple/cssselect2/
Downloading https://files.pythonhosted.org/packages/9d/3a/e39436efe51894243ff145a37c4f9a030839b97779ebcc4f13b3ba21c54e/cssselect2-0.7.0-py3-none-any.whl#sha256=fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969
Best match: cssselect2 0.7.0
Processing cssselect2-0.7.0-py3-none-any.whl
Installing cssselect2-0.7.0-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding cssselect2 0.7.0 to easy-install.pth file

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/cssselect2-0.7.0-py3.10.egg
Searching for cairocffi
Reading https://pypi.org/simple/cairocffi/
Downloading https://files.pythonhosted.org/packages/17/be/a5d2c16317c6a890502725970589ae7f06cfc66b2e6916ba0a86973403c8/cairocffi-1.6.1-py3-none-any.whl#sha256=aa78ee52b9069d7475eeac457389b6275aa92111895d78fbaa2202a52dac112e
Best match: cairocffi 1.6.1
Processing cairocffi-1.6.1-py3-none-any.whl
Installing cairocffi-1.6.1-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding cairocffi 1.6.1 to easy-install.pth file

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/cairocffi-1.6.1-py3.10.egg
Searching for tomli>=1.0.0
Reading https://pypi.org/simple/tomli/
Downloading https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl#sha256=939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc
Best match: tomli 2.0.1
Processing tomli-2.0.1-py3-none-any.whl
Installing tomli-2.0.1-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding tomli 2.0.1 to easy-install.pth file

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/tomli-2.0.1-py3.10.egg
Searching for exceptiongroup>=1.0.0rc8
Reading https://pypi.org/simple/exceptiongroup/
Downloading https://files.pythonhosted.org/packages/b8/9a/5028fd52db10e600f1c4674441b968cf2ea4959085bfb5b99fb1250e5f68/exceptiongroup-1.2.0-py3-none-any.whl#sha256=4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14
Best match: exceptiongroup 1.2.0
Processing exceptiongroup-1.2.0-py3-none-any.whl
Installing exceptiongroup-1.2.0-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding exceptiongroup 1.2.0 to easy-install.pth file

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/exceptiongroup-1.2.0-py3.10.egg
Searching for pluggy<2.0,>=1.3.0
Reading https://pypi.org/simple/pluggy/
Downloading https://files.pythonhosted.org/packages/05/b8/42ed91898d4784546c5f06c60506400548db3f7a4b3fb441cba4e5c17952/pluggy-1.3.0-py3-none-any.whl#sha256=d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7
Best match: pluggy 1.3.0
Processing pluggy-1.3.0-py3-none-any.whl
Installing pluggy-1.3.0-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding pluggy 1.3.0 to easy-install.pth file

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pluggy-1.3.0-py3.10.egg
Searching for iniconfig
Reading https://pypi.org/simple/iniconfig/
Downloading https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl#sha256=b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
Best match: iniconfig 2.0.0
Processing iniconfig-2.0.0-py3-none-any.whl
Installing iniconfig-2.0.0-py3-none-any.whl to /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Adding iniconfig 2.0.0 to easy-install.pth file

Installed /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/iniconfig-2.0.0-py3.10.egg
Searching for Pillow==9.2.0
Best match: Pillow 9.2.0
Adding Pillow 9.2.0 to easy-install.pth file

Using /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Searching for shapely==2.0a1
Best match: shapely 2.0a1
Adding shapely 2.0a1 to easy-install.pth file

Using /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Searching for tinycss2==1.1.1
Best match: tinycss2 1.1.1
Adding tinycss2 1.1.1 to easy-install.pth file

Using /Users/russ/.local/lib/python3.10/site-packages
Searching for defusedxml==0.7.1
Best match: defusedxml 0.7.1
Adding defusedxml 0.7.1 to easy-install.pth file

Using /Users/russ/.local/lib/python3.10/site-packages
Searching for packaging==21.3
Best match: packaging 21.3
Adding packaging 21.3 to easy-install.pth file

Using /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Searching for numpy==1.23.5
Best match: numpy 1.23.5
Adding numpy 1.23.5 to easy-install.pth file
Installing f2py script to /Users/russ/.asdf/installs/python/3.10.6/bin
Installing f2py3 script to /Users/russ/.asdf/installs/python/3.10.6/bin
Installing f2py3.10 script to /Users/russ/.asdf/installs/python/3.10.6/bin

Using /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Searching for webencodings==0.5.1
Best match: webencodings 0.5.1
Adding webencodings 0.5.1 to easy-install.pth file

Using /Users/russ/.local/lib/python3.10/site-packages
Searching for cffi==1.15.1
Best match: cffi 1.15.1
Adding cffi 1.15.1 to easy-install.pth file

Using /Users/russ/.local/lib/python3.10/site-packages
Searching for pyparsing==3.0.9
Best match: pyparsing 3.0.9
Adding pyparsing 3.0.9 to easy-install.pth file

Using /Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages
Searching for pycparser==2.21
Best match: pycparser 2.21
Adding pycparser 2.21 to easy-install.pth file

Using /Users/russ/.local/lib/python3.10/site-packages
Finished processing dependencies for pcbflow==0.1.0

$ cd examples
$ python basic/blank.py
Traceback (most recent call last):
  File "/Users/russ/Sites/pcbflow/examples/basic/blank.py", line 10, in <module>
    brd.fill_layer("GTL", "GND")
  File "/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pcbflow-0.1.0-py3.10.egg/pcbflow/board.py", line 249, in fill_layer
    lyr.fill_poly = g.difference(exclusions.buffer(self.drc.clearance))
AttributeError: 'NoneType' object has no attribute 'buffer'

$ python basic/holes.py
Traceback (most recent call last):
  File "/Users/russ/Sites/pcbflow/examples/basic/holes.py", line 17, in <module>
    brd.fill_layer("GTL", "GND")
  File "/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pcbflow-0.1.0-py3.10.egg/pcbflow/board.py", line 249, in fill_layer
    lyr.fill_poly = g.difference(exclusions.buffer(self.drc.clearance))
AttributeError: 'NoneType' object has no attribute 'buffer'

$ cd sample
$ python sample.py
WARNING: fanout for R3 requires at least one net name to match against pad names
Traceback (most recent call last):
  File "/Users/russ/Sites/pcbflow/examples/sample/sample.py", line 38, in <module>
    usb_con = EaglePart(
  File "/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/site-packages/pcbflow-0.1.0-py3.10.egg/pcbflow/eagle.py", line 90, in __init__
    tree = ET.parse(self.libraryfile)
  File "/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/xml/etree/ElementTree.py", line 1222, in parse
    tree.parse(source, parser)
  File "/Users/russ/.asdf/installs/python/3.10.6/lib/python3.10/xml/etree/ElementTree.py", line 569, in parse
    source = open(source, "rb")
FileNotFoundError: [Errno 2] No such file or directory: 'sparkfun.lbr'

Add native support for Skidl

Add native support for Skidl data objects. In particular, using generated net lists and/or integration of Skidl's Part and Net data objects.

The support of skidl should be optional in terms of generating a PCB. Simple PCBs can still be generated without any formal definition of components and networks, rather can still be described with drawing geometric primitives. TBD.

Spacing issue with PinSocket and PinHeader holes

There's a strange issue when rendering pin holes for PinHeader and PinSocket footprints. (standard arduino headers)

esp32_motor-pcb-x3_final-pcbflow_preview_all

It seems to add an additional, invisible hole every time a hole is drilled onto the board.

So rather than going 1, 2, 3, 4 -- it'll go 1, 3, 5, etc.

Must be some kind of maths problem. Here's where the bug manifests within the footprint, I just need to be able to locate the exact logic in the code:

  (pad 1 thru_hole rect (at 0 0) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask))
  (pad 2 thru_hole oval (at 0 2.54) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask))
  (pad 3 thru_hole oval (at 0 5.08) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask))
  (pad 4 thru_hole oval (at 0 7.62) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask))
  (pad 5 thru_hole oval (at 0 10.16) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask))
  (pad 6 thru_hole oval (at 0 12.7) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask))
  (pad 7 thru_hole oval (at 0 15.24) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask))
  (pad 8 thru_hole oval (at 0 17.78) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask))

It gets the spacing right for the first two pads, but as soon as it loops through repeated hole shapes - it becomes an exponential pattern.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.