commit 4e6332596a2e92be49a85ca28c0573db568513f4 Author: cpu Date: Thu Jun 18 15:15:23 2026 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef9f69a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +gcode/ +gerbers/ +.flatcam-env/ +flatcam-beta/ \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..71ea065 --- /dev/null +++ b/Readme.md @@ -0,0 +1,146 @@ +# KiCad → Stencil G-code pipeline + +Automates the conversion of a KiCad v9 `F.Paste` and `B.Paste` Gerber to G-code for CNC milling a solder paste stencil, using FlatCAM beta 8.995 headless. Tested on Ubuntu 24.04 with Python 3.12 and a Frezu 3040 / FluidNC controller. + +--- + +## Prerequisites + +- Ubuntu 24.04 +- Python 3.10–3.12 +- KiCad v9 +- A flat end mill (corn bit), 0.5 mm recommended + +--- + +## Installation + +### 1. System dependencies + +```bash +sudo apt install python3-venv python3-pip libgeos-dev libspatialindex-dev libxcb-cursor0 +``` + +### 2. Clone FlatCAM beta 8.995 + +```bash +git clone --branch mstanciu_Beta_8.995 --depth 1 https://github.com/dwrobel/flatcam.git flatcam-beta +``` + +### 3. Create a Python venv and install dependencies + +```bash +cd flatcam-beta + +python3 -m venv .flatcam-env +source .flatcam-env/bin/activate + +pip install PyQt6 PyQt6-Qt6 PyQt6-sip + +# Skip ortools (path optimizer), rasterio, and gdal (image import) — not needed for stencils +grep -vE "ortools|rasterio|gdal" requirements.txt | pip install -r /dev/stdin +``` + +### 4. Verify + +```bash +python flatcam.py --version +``` + +You should see the FlatCAM version string printed without errors. + +Go back to the project directory: +```bash +cd .. +``` + +### 5. Export the stencil gerbers + +Export the gerber layers `F.Paste` and `B.Paste` +```bash +kicad-cli pcb export gerbers -o gerbers -l F.Paste,B.Paste ../kicad2panel/panel/Flow_Controller_Panel.kicad_pcb +``` + +--- + +## Usage + +Generate the stencil G-code for both layers: +```bash +./run_stencil.sh gerbers/Flow_Controller_Panel-F_Paste.gtp \ + gcode/Flow_Controller_Panel-F_Paste-stencil.nc + +./run_stencil.sh gerbers/Flow_Controller_Panel-B_Paste.gbp \ + gcode/Flow_Controller_Panel-B_Paste-stencil.nc +``` + +G-code for both layers should be in the: + +``` +gcode/Flow_Controller_Panel-F_Paste-stencil.nc +gcode/Flow_Controller_Panel-B_Paste-stencil.nc +``` + +--- + +## Parameters + +All cutting parameters are at the top of `paste_stencil.tcl`: + +| Variable | Default | Description | +|---|---|---| +| `TOOL_DIA` | `0.5` | End mill diameter in mm | +| `CUT_Z` | `-0.2` | Cutting depth in mm (negative). Set slightly past material thickness | +| `TRAVEL_Z` | `2.0` | Safe travel height in mm | +| `FEEDRATE` | `120` | XY feed rate in mm/min | +| `SPINDLE` | `15000` | Spindle speed in RPM | +| `OVERLAP` | `60` | Tool overlap in % — higher = cleaner clearing, more paths | +| `MARGIN` | `0.0` | Inset from aperture edge in mm. 0 = cut to exact pad size | + +### Depth by material + +| Material | Thickness | Recommended `CUT_Z` | +|---|---|---| +| Brass shim (CW614N) | 0.15 mm | `-0.18` | +| Polyimide (Kapton) | 0.10 mm | `-0.13` | +| Stainless steel shim | 0.15 mm | `-0.18` | + +For stainless, also reduce `FEEDRATE` to `80` mm/min. + +--- + +## Preprocessor + +The script uses the `GRBL_11` preprocessor (`-pp GRBL_11` in `paste_stencil.tcl`), which produces grbl 1.1 compatible G-code. FluidNC implements the grbl protocol so this works directly with no modifications. + +Alternative: `GRBL_11_no_M6` suppresses tool change commands — not needed for a single-tool stencil job but harmless either way. + +--- + +## Workholding notes + +- Stencil material is thin and will flex — use double-sided tape on a flat spoilboard +- Zero Z directly on the stencil surface, not the spoilboard +- For brass shim, clamp the edges with small clips if the tape isn't holding — chatter from an unanchored sheet ruins aperture quality + +--- + +## Troubleshooting + +**FlatCAM hangs after writing G-code** +The `run_stencil.sh` wrapper detects the `TclCommandQuit` log line and kills the process after 3 seconds. This is expected behavior — FlatCAM's Qt GUI cleanup hangs in headless mode. + +**`ImportError: cannot import name 'Inf' from numpy`** +You have the old PyPI FlatCAM 8.5 installed. Follow the installation steps above to switch to the beta 8.995 clone. + +**`ImportError: cannot import name 'cascaded_union' from shapely.ops`** +Same cause — old FlatCAM 8.5 is incompatible with Shapely 2.0. Switch to beta 8.995. + +**G-code cuts everything except the pads** +You used `ncc` (non-copper clear) instead of `paint`. The correct command is `paint` — it pockets the pad polygons. `ncc` clears everything around them, which is the inverse. + +**`gdal` fails to install** +Skip it — `gdal` is only needed for the image import plugin. Use: +```bash +grep -vE "ortools|rasterio|gdal" requirements.txt | pip install -r /dev/stdin +``` \ No newline at end of file diff --git a/paste_stencil.tcl b/paste_stencil.tcl new file mode 100644 index 0000000..e8cf986 --- /dev/null +++ b/paste_stencil.tcl @@ -0,0 +1,79 @@ +# paste_stencil.tcl — FlatCAM beta 8.995 +# Automates B.Paste Gerber -> G-code for stencil milling +# Tool: 0.5mm flat end mill (corn bit) +# +# Usage (headless): +# python flatcam.py --shellfile=paste_stencil.tcl --headless=1 + +# ─── USER CONFIGURATION ─────────────────────────────────────────────────────── + +set GERBER "gerbers/myboard-B_Paste.gbp" ;# path to your B.Paste Gerber +set OUTPUT "gcode/stencil.nc" ;# output G-code file + +# Tool +set TOOL_DIA 0.5 ;# mm — 0.5mm corn bit + +# Stencil material depth +# Brass shim 0.15mm → use -0.18, polyimide 0.1mm → use -0.13 +set CUT_Z -0.3 ;# mm — cutting depth (negative) +set TRAVEL_Z 2.0 ;# mm — safe travel height + +# Feeds & speeds +set FEEDRATE 120 ;# mm/min +set SPINDLE 15000 ;# RPM + +# NCC (copper_clear) settings +# overlap is in PERCENT (0–100), not fraction — 8.995 change from classic +set OVERLAP 60 ;# % — 60% overlap for clean clearing with 0.5mm tool +set MARGIN 0.0 ;# mm — 0 = clear exactly to aperture edge + +# Multidepth — set dpp to 0 to disable (single pass) +set DPP 0.0 ;# mm per pass; 0 = single full-depth pass + +# ─── DERIVED NAMES ──────────────────────────────────────────────────────────── + +set GBR_NAME "paste_gerber" +set NCC_GEO "paste_paint_geo" +set CNC_JOB "paste_cnc" + +# ─── SCRIPT ─────────────────────────────────────────────────────────────────── + +# 1. Fresh project +new + +# 2. Load B.Paste Gerber +open_gerber $GERBER -outname $GBR_NAME + +# 3. Paint (pocket) each aperture opening +# -all processes every polygon in the object +# method lines is most reliable for small SMD apertures +paint $GBR_NAME \ + -tooldia $TOOL_DIA \ + -overlap $OVERLAP \ + -offset $MARGIN \ + -method lines \ + -connect 1 \ + -contour 1 \ + -all \ + -outname $NCC_GEO + +# 4. Generate CNC job +# -dpp 0 means single pass (multidepth disabled) +# -pp default uses the standard grbl-compatible preprocessor +cncjob $NCC_GEO \ + -dia $TOOL_DIA \ + -z_cut $CUT_Z \ + -z_move $TRAVEL_Z \ + -feedrate $FEEDRATE \ + -spindlespeed $SPINDLE \ + -pp GRBL_11 \ + -outname $CNC_JOB + +# 5. Write G-code to file +write_gcode $CNC_JOB $OUTPUT + +puts "Done: $OUTPUT" + +# Clear project so FlatCAM doesn't prompt to save on exit +new +quit_app \ No newline at end of file diff --git a/run_stencil.sh b/run_stencil.sh new file mode 100755 index 0000000..f895fd3 --- /dev/null +++ b/run_stencil.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# run_stencil.sh — headless FlatCAM 8.995 stencil G-code generator +# +# Usage: +# ./run_stencil.sh + +set -euo pipefail + +GERBER="${1:?Usage: $0 }" +OUTPUT="${2:?Usage: $0 }" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +TCL_SCRIPT="$SCRIPT_DIR/paste_stencil.tcl" + +FLATCAM_PY="$HOME/proj/kicad2stencil/flatcam-beta/flatcam.py" +FLATCAM_ENV="$HOME/proj/kicad2stencil/.flatcam-env" + +if [ ! -f "$FLATCAM_PY" ]; then + echo "ERROR: flatcam.py not found at $FLATCAM_PY" + exit 1 +fi + +GERBER_ABS="$(realpath "$GERBER")" +OUTPUT_ABS="$(realpath -m "$OUTPUT")" +mkdir -p "$(dirname "$GERBER_ABS")" +mkdir -p "$(dirname "$OUTPUT_ABS")" + +TMP_TCL=$(mktemp /tmp/paste_stencil_XXXXXX.tcl) +sed \ + -e "s|gerbers/myboard-B_Paste.gbp|${GERBER_ABS}|g" \ + -e "s|gcode/stencil.nc|${OUTPUT_ABS}|g" \ + "$TCL_SCRIPT" > "$TMP_TCL" + +echo "→ Running FlatCAM headless..." +echo " Gerber : $GERBER_ABS" +echo " Output : $OUTPUT_ABS" +echo "" + +source "$FLATCAM_ENV/bin/activate" + +# Run FlatCAM, watch for the WriteGCode confirmation line, then kill it +# FlatCAM hangs on quit due to Qt GUI cleanup — we kill it cleanly once done +python "$FLATCAM_PY" --shellfile="$TMP_TCL" --headless=1 2>&1 | \ +while IFS= read -r line; do + echo "$line" + if [[ "$line" == *"TclCommandQuit"* ]]; then + # Give it a moment to finish flushing the file + sleep 3 + # Kill the FlatCAM process + pkill -f "flatcam.py.*headless" 2>/dev/null || true + fi +done + +rm -f "$TMP_TCL" + +# Verify output was created +if [ -f "$OUTPUT_ABS" ]; then + SIZE=$(wc -l < "$OUTPUT_ABS") + echo "" + echo "✓ Done: $OUTPUT_ABS ($SIZE lines)" +else + echo "" + echo "✗ ERROR: output file not created — check log above" + exit 1 +fi \ No newline at end of file