techmannih/nema34-mounted-stepper-controller

A 48 V USB‑C PD 3.1 EPR NEMA‑34 stepper controller PCB combining STM32/TMC5160 control, external MOSFET motor bridges, protected power and regenerative braking, USB data, telemetry, diagnostics, status LEDs, and buzzer alarms.

Version
0.3.92
License
unset
Stars
1

scripts/export-silkscreen-evidence.py

#!/usr/bin/env python3
"""Record the visible final KiCad silkscreen text on both assembly sides."""

from __future__ import annotations

import argparse
import json
from pathlib import Path

import pcbnew


def text_row(item: pcbnew.PCB_TEXT, owner: str) -> dict[str, object]:
    position = item.GetPosition()
    return {
        "text": item.GetText(),
        "owner": owner,
        "layer": "top" if item.GetLayer() == pcbnew.F_SilkS else "bottom",
        "x_mm": round(pcbnew.ToMM(position.x), 6),
        "y_mm": round(pcbnew.ToMM(position.y), 6),
        "height_mm": round(pcbnew.ToMM(item.GetTextHeight()), 6),
        "width_mm": round(pcbnew.ToMM(item.GetTextWidth()), 6),
    }


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("board", type=Path)
    parser.add_argument("output", type=Path)
    args = parser.parse_args()

    board = pcbnew.LoadBoard(str(args.board.resolve()))
    labels: list[dict[str, object]] = []
    for drawing in board.GetDrawings():
        if isinstance(drawing, pcbnew.PCB_TEXT) and drawing.GetLayer() in (pcbnew.F_SilkS, pcbnew.B_SilkS):
            labels.append(text_row(drawing, "board"))
    for footprint in board.GetFootprints():
        for field in (footprint.Reference(), footprint.Value()):
            if field.IsVisible() and field.GetLayer() in (pcbnew.F_SilkS, pcbnew.B_SilkS):
                labels.append(text_row(field, footprint.GetReference()))

    labels.sort(key=lambda item: (str(item["layer"]), str(item["text"]), float(item["x_mm"]), float(item["y_mm"])))
    report = {
        "schema_version": 2,
        "source_board": str(args.board),
        "minimum_recorded_text_height_mm": min((row["height_mm"] for row in labels), default=None),
        "labels": labels,
    }
    args.output.parent.mkdir(parents=True, exist_ok=True)
    args.output.write_text(json.dumps(report, indent=2) + "\n")
    print(json.dumps({"labels": len(labels), "output": str(args.output)}, indent=2))


if __name__ == "__main__":
    main()