Skip to content

Commit

Permalink
Implement support for fab openpn
Browse files Browse the repository at this point in the history
  • Loading branch information
yaqwsx committed Jan 6, 2024
1 parent 3427a8d commit db18615
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/fabrication/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Note: click on the name of the manufacturer to see corresponding documentation:
- [PCBWay](pcbway.md): board manufacturing, assembly. [https://www.pcbway.com/](https://www.pcbway.com/)
- [OSH Park](oshpark.md): board manufacturing. [https://oshpark.com/](https://oshpark.com/)
- [Neoden YY1](neodenyy1.md): desktop PCB assembly. [https://neodenusa.com/neoden-yy1-pick-place-machine](https://neodenusa.com/neoden-yy1-pick-place-machine)
- [OpenPNP](openpn.md): Open system for pick'n'place machines. [https://openpnp.org/](https://openpnp.org/)

## Adding New Fabrication Houses

Expand Down
10 changes: 10 additions & 0 deletions docs/fabrication/openpnp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Fabrication: OpenPNP

The basic usage of this exporter is:
```
kikit fab openpn [OPTIONS] BOARD OUTPUTDIR
```

This exporter creates a single file `components.pos` that mimics KiCAD native
`.pos` output. However, unlike KiCAD, it adds a unique identifier to component
references to ensure they are unique (in the case of panels).
57 changes: 57 additions & 0 deletions kikit/fab/openpnp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import datetime
from pathlib import Path

from pcbnewTransition import pcbnew

import kikit

from .common import ensurePassingDrc, ensureValidBoard, expandNameTemplate, naturalComponentKey

def exportOpenPnp(board, outputdir, drc, nametemplate):
ensureValidBoard(board)
loadedBoard = pcbnew.LoadBoard(board)

if drc:
ensurePassingDrc(loadedBoard)

Path(outputdir).mkdir(parents=True, exist_ok=True)
posname = expandNameTemplate(nametemplate, "components", loadedBoard) + ".pos"

footprints= sorted(loadedBoard.GetFootprints(), key=lambda f: naturalComponentKey(f.GetReference()))

if len(footprints) == 0:
raise RuntimeError("No components in board, nothing to do")

footprint_texts = [
["# Ref", "Val", "Package", "PosX", "PosY", "Rot", "Side"]
]
for f in footprints:
sideName = "top" if f.GetLayer() == pcbnew.F_Cu else "bottom"
footprint_texts.append([
f"{f.GetReference()}-{f.m_Uuid.AsString()}",
f"{f.GetValue()}",
f"{f.GetFPIDAsString()}",
f"{pcbnew.ToMM(f.GetX())}",
f"{pcbnew.ToMM(f.GetY())}",
f"{f.GetOrientation().AsDegrees()}",
f"{sideName}"])

colWidths = [
max([len(row[i]) for row in footprint_texts]) for i in range(len(footprint_texts[0]))
]

def format_row(file, row):
SPACING = 5
for elem, pad in zip(row, colWidths):
file.write(elem)
file.write(" " * (pad - len(elem) + SPACING))
file.write("\n")

with open(Path(outputdir) / posname, "w", encoding="utf-8") as outfile:
outfile.write(f"### Footprint positions - created on {datetime.datetime.now()} ###\n")
outfile.write(f"### Printed by KiKit {kikit.__version__}\n")
outfile.write(f"## Unit = mm, Angle = deg.\n")
outfile.write(f"## Side : All\n")
for row in footprint_texts:
format_row(outfile, row)

12 changes: 12 additions & 0 deletions kikit/fab_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,17 @@ def neodenyy1(**kwargs):
app = fakeKiCADGui()
return execute(neodenyy1.exportNeodenYY1, kwargs)

@click.command()
@fabCommand
def openpnp(**kwargs):
"""
Prepare fabrication files for OpenPnP
"""
from kikit.fab import openpnp
from kikit.common import fakeKiCADGui
app = fakeKiCADGui()
return execute(openpnp.exportOpenPnp, kwargs)

@click.group()
def fab():
"""
Expand All @@ -125,3 +136,4 @@ def fab():
fab.add_command(pcbway)
fab.add_command(oshpark)
fab.add_command(neodenyy1)
fab.add_command(openpnp)

0 comments on commit db18615

Please sign in to comment.