159 lines
5.6 KiB
Markdown
159 lines
5.6 KiB
Markdown
TODO: Add table of content
|
||
# MSLA PCB Exposure: KiCad → Photon Mono 4
|
||
Using an MSLA (Masked Stereolithography Apparatus) resin printer for creating PCBs is a technique known as "Direct UV Exposure." Instead of printing a plastic part, you use the printer's LCD screen as a dynamic digital mask to cure photosensitive materials (etch resist, solder resist and silkscreen) on a copper board.
|
||
|
||
KiCad PCB layers need to be converted to `.pm4n` files for direct UV exposure on an **Anycubic Photon Mono 4** (9024×5120 px, 17 µm/px, 1494.12 DPI) on the screen size of 153.408 x 87.040 mm.
|
||
|
||
---
|
||
|
||
## Preparation
|
||
|
||
### KiCad: Set your design grid
|
||
In KiCad's PCB editor, go to `Preferences → Preferences → PCB Editor → Grids` and add a custom grid of 0.017 mm. This ensures trace edges land on pixel boundaries and avoids the sub-pixel rounding that causes the ±1px size error people see with arbitrary grids.
|
||
|
||
### Create the `Dummy.pm4n` file
|
||
|
||
Open **CHITUBOX Basic** slicer (or any other slicer that works for your resin printer), select printer **Anycubic Photon Mono 4**, slice any tiny STL (e.g.: 1×1×0.05 mm box), and save as `Dummy.pm4n`.
|
||
|
||
This file is reused for every job — it carries the correct LCD resolution metadata.
|
||
|
||
## Manual processing
|
||
|
||
`UVtools` has a dedicated `PCB Exposure` tool that converts a Gerber file to a pixel-perfect image given your printer's LCD resolution, specifically for exposing copper traces.
|
||
|
||
### 1. Install `UVtools`
|
||
|
||
```bash
|
||
sudo apt-get install -y curl
|
||
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/sn4k3/UVtools/master/Scripts/install-dependencies.sh)"
|
||
```
|
||
|
||
### 2. Run `UVtools`
|
||
|
||
```bash
|
||
cd UVtools
|
||
./UVtools
|
||
```
|
||
|
||
### 3. Export `.pm4n` file from Gerber
|
||
|
||
- You export Gerber from KiCad (not SVG), which natively gives you positive/negative control per layer.
|
||
- You open the `Dummy.pm4n` file in `UVtools` (a minimal valid `.pm4n` sliced by `Chitubox` or `Photon Workshop` with any tiny model), then use `Tools → PCB Exposure` to inject your Gerber layer e.g.: `Flow_Controller_Panel-Front.gbr`.
|
||
- You control `inversion`, `invert` and the `exposure time` at the bottom of the `PCB exposure` dialog.
|
||
- You save it as e.g.: `Flow_Controller_Panel-Front.pm4n` file and print it.
|
||
|
||

|
||
|
||

|
||
|
||
---
|
||
|
||
## Automated script
|
||
|
||
### 1. Install dependencies
|
||
|
||
```bash
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install pygerber Pillow numpy
|
||
```
|
||
|
||
Or activate the `venv` once and put `source .venv/bin/activate` in your shell profile.
|
||
|
||
### 2. Export multiple layers (e.g. copper + soldermask + silkscreen)
|
||
|
||
```bash
|
||
./export.sh \
|
||
--layers Front,Back,F.Mask,B.Mask,F.SilkS,B.SilkS \
|
||
--invert Front,Back,F.Mask,B.Mask,F.SilkS,B.SilkS \
|
||
--mirror Front,F.Mask,F.SilkS \
|
||
--exposure 60 \
|
||
../kicad2panel/panel/Flow_Controller_Panel.kicad_pcb
|
||
```
|
||
It should output:
|
||
```bash
|
||
Plotted to './output/gerbers/Flow_Controller_Panel-Front.gbr'.
|
||
Plotted to './output/gerbers/Flow_Controller_Panel-Back.gbr'.
|
||
Plotted to './output/gerbers/Flow_Controller_Panel-F_Silkscreen.gbr'.
|
||
Plotted to './output/gerbers/Flow_Controller_Panel-B_Silkscreen.gbr'.
|
||
Plotted to './output/gerbers/Flow_Controller_Panel-F_Mask.gbr'.
|
||
Plotted to './output/gerbers/Flow_Controller_Panel-B_Mask.gbr'.
|
||
output/pm4n/Flow_Controller_Panel-Front.pm4n
|
||
output/pm4n/Flow_Controller_Panel-Front.preview.png
|
||
output/pm4n/Flow_Controller_Panel-Back.pm4n
|
||
output/pm4n/Flow_Controller_Panel-Back.preview.png
|
||
output/pm4n/Flow_Controller_Panel-F_Mask.pm4n
|
||
output/pm4n/Flow_Controller_Panel-F_Mask.preview.png
|
||
output/pm4n/Flow_Controller_Panel-B_Mask.pm4n
|
||
output/pm4n/Flow_Controller_Panel-B_Mask.preview.png
|
||
output/pm4n/Flow_Controller_Panel-F_Silkscreen.pm4n
|
||
output/pm4n/Flow_Controller_Panel-F_Silkscreen.preview.png
|
||
output/pm4n/Flow_Controller_Panel-B_Silkscreen.pm4n
|
||
output/pm4n/Flow_Controller_Panel-B_Silkscreen.preview.png
|
||
```
|
||
#### 2.1. Check the layer preview
|
||
Check the `output/pm4n/Flow_Controller_Panel-*.preview.png` images — traces should appear black on white background.
|
||
- background = UV exposed = resist removed = etched away
|
||
- traces = dark = resist kept = copper stays
|
||
|
||
#### 2.2. Check the printer exposure
|
||
Open the `.pm4n` in `Chitubox Basic` slicer to visually verify before printing.
|
||
|
||
#### 2.3. Adjust exposure
|
||
Start with `--exposure 60` and bracket from there — Bungard presensitized at 405nm typically lands between 30–120s depending on board vintage and storage.
|
||
|
||
### 3. Export single layer (e.g. copper)
|
||
|
||
Export the front layer as gerber
|
||
```bash
|
||
kicad-cli pcb export gerbers -o output/gerbers -l F.Cu ../kicad2panel/panel/Flow_Controller_Panel.kicad_pcb
|
||
```
|
||
It should output
|
||
```bash
|
||
Plotted to 'output/gerbers/Flow_Controller_Panel-Front.gtl'.
|
||
```
|
||
|
||
Convert the gerber to pm4n and preview
|
||
```bash
|
||
python3 gerber_to_pm4n.py Dummy.pm4n output/gerbers/Flow_Controller_Panel-Front.gtl \
|
||
--invert --mirror --exposure 120
|
||
```
|
||
It should output
|
||
```bash
|
||
output/pm4n/Flow_Controller_Panel-Front.pm4n
|
||
output/pm4n/Flow_Controller_Panel-Front.preview.png
|
||
```
|
||
|
||
Open the preview image
|
||
```bash
|
||
xdg-open output/pm4n/Flow_Controller_Panel-Front.preview.png
|
||
```
|
||
|
||
Open the `output/pm4n/Flow_Controller_Panel-Front.pm4n` in `Chitubox Basic` slicer to visually verify before printing.
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
**`kicad-cli: command not found`** — add KiCad to PATH:
|
||
```bash
|
||
export PATH="/usr/lib/kicad/bin:$PATH"
|
||
```
|
||
Or on Flatpak:
|
||
```bash
|
||
alias kicad-cli='flatpak run --command=kicad-cli org.kicad.KiCad'
|
||
```
|
||
|
||
**Expected Gerber not found** — KiCad's layer→filename mapping:
|
||
|
||
| Layer | Filename stem |
|
||
|---|---|
|
||
| `F.Cu` | `Front` |
|
||
| `B.Cu` | `Back` |
|
||
| `F.Mask` | `F_Mask` |
|
||
| `B.Mask` | `B_Mask` |
|
||
| `F.SilkS` | `F_Silkscreen` |
|
||
|
||
---
|
||
|