BSD 3-Clause "New" or "Revised" License

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

深度分析:GitHub 项目 “michaelgale/pcbflow”

项目背景与痛点

“michaelgale/pcbflow”是一个基于 Python 的 PCB 布局和设计工具,它主要基于 CuFlow 技术实现。在电子设计自动化(EDA)领域,高质量的布局和设计是确保电路板可靠工作和高效生产的关键。传统的 PCB 设计工具通常基于专有技术,且价格高昂,操作复杂,限制了小型企业和个人开发者在 PCB 设计上的自由度和灵活性。

此项开源项目正是为了应对这些痛点而生。它利用 Python 的开源和易用性优势,为非专业人士提供了一个轻量而强大的解决方案,降低了进入壁垒,让任何人都能够轻松设计高质量的电路板。

核心技术揭秘

核心组件和技术栈分析时,可观察到 “pcbflow” 充分利用了 Python 的多种库和工具,包括但不限于:

  • Numpy 和 Matplotlib:用于处理和可视化数据,以优化布局工具。
  • CuFlow:作为主要的技术引擎,它提供了 PCB 设计的核心逻辑。

下面是一张项目的高层架构图,展现出从用户输入到最终布局输出的主要数据流:

graph TD A[用户输入] --> B[参数预处理] B --> C{"有效性验证"} C -->|"通过"| D[数据分析] C -->|"失败"| E[返回错误] D --> F[布局引擎(CuFlow)] F --> G[布局输出] G --> H[可视化结果]

可以看出,流程从接收用户的图形化设计或数据输入开始,通过一系列的数据处理和核验,最终将设计转化为具有实际价值的输出,同时也提供直观的可视化展示。

功能亮点与差异

“pcbflow”的一大亮点在于其易用性和开源性。与其他商业解决方案相比,它不仅降低了整体使用成本,还通过社区支持增强了解决方案的持续改进能力。此外,项目具有强烈的数据驱动设计理念,特别适合对细节敏感的 PCB 设计,确保设计过程中的每一个变更都基于精确的自动化决策过程。

在实现细节上,“pcbflow”采用模块化设计,核心部分实现了文件接口、布局生成、优化策略及可视化功能,允许用户无缝插入自定义逻辑或系统集成。

应用场景与落地建议

生产环境中使用“pcbflow”时,应当注意以下几点:

  1. 在复杂电路板设计上需要更多的测试和验证:尽管基础功能强大,对于需要极其复杂或高性能的设计,仍需进行详尽的测试。
  2. 具体应用前需进一步定制:针对特定业务需求,可能需要全面测试和缺陷修复。

尽管如此,“pcbflow”非常适合进行复杂或初阶PCB设计的科技初创公司或个人开发者使用,为其提供了一种高效且经济的方法。

综合评价

“michaelgale/pcbflow”无疑为用户提供了强大的 PCB 设计能力,尤其吸引了小型企业和开源社区的关注。不过,它也存在一定的局限性,对于非常复杂或专有电路板设计的质量保证需要用户自己去验证和测试。但对于大多数小型企业和个人开发者而言,这仍然是一个令人兴奋的工具,它简化了实现步骤,提高了设计效率。

关于

GitHub 原始描述(英文)

Python based Printed Circuit Board (PCB) layout and design package based on CuFlow.

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
252
价值分
127
活跃状态
活跃

语言占比

Python
Shell

README

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.

评论

暂无评论