Files
ESP32_Serial_Swiss_Army_Knife/hardware/PCB/validation/pcb-routing-summary.md
T
Commander1024 60c1e279d6 Add KiCad module carrier PCB draft
Introduce an editable KiCad 10 schematic and routed two-layer 82 × 80 mm
layout with local provisional footprints, validation tooling, and
component
research. Keep the RS-232 male-module mapping and mechanical clearances
explicitly provisional pending hardware verification.
2026-09-20 23:14:01 +02:00

7.4 KiB

Two-layer draft routing result

Date: 2026-09-20. KiCad 10.0.6; system /usr/bin/python3.

Saved result

Actual copper routing is saved in ../serial-carrier.kicad_pcb, not just a preview or an exported proposal. 38/38 required spanning-tree connections across 17 multi-pad nets routed; KiCad reports 0 unconnected items, 0 errors, 0 warnings. Intentional single-pad unconnected-(...) nets retain their original names and are not connected to anything else.

  • Two copper layers, F.Cu and B.Cu.
  • 569 straight track segments: 425 at 0.25 mm for signals and 144 at 0.5 mm for +3V3/GND. No narrow power-track fallback was necessary.
  • 20 through vias, 0.7 mm copper diameter / 0.3 mm drill.
  • No copper pours: all ground connections were routed explicitly.
  • Original RF rule area, x110..131 / y100..113 mm on both copper layers, preserved. No tracks, vias or fills enter the reservation. Minimum copper-to-reservation gap measured independently is 0.025 mm; this is geometric compliance with the specified provisional boundary, not validation of an antenna's RF needs.
  • All 9 electrical footprints and 4 standalone mounting footprints preserved. Pad positions, shapes, sizes, drills, types, nets, functions, pin types and UUIDs; footprint placement, orientation, library IDs, values, UUIDs and schematic UUID paths; net table, outline and RF rule-area geometry/flags match the input.
  • Generator, README, schematic, project and libraries were not edited by routing. No external network dependency or manufacturing exports were used.

Validation performed

From hardware/PCB:

kicad-cli pcb drc --format json --refill-zones --save-board -o validation/pcb-routing-drc.json serial-carrier.kicad_pcb
kicad-cli pcb drc --format json --all-track-errors --severity-all --exit-code-violations -o validation/pcb-routing-all-drc.json serial-carrier.kicad_pcb
/usr/bin/python3 -B validation/pcb-routing-check.py

Both DRC runs: 0 violations and 0 unconnected items. No DRC settings or exclusions were added or changed. Existing project rules specify 0.25 mm minimum clearance, 0.5 mm copper-edge clearance, 0.25 mm minimum track width and 0.7 mm minimum via diameter.

Independent continuous-geometry audit (pcb-routing-check.json):

Check Measured minimum Requirement
Different-net copper / copper-to-NPTH clearance 0.275 mm 0.25 mm
Copper or NPTH edge to board edge 0.525 mm 0.5 mm
Copper / NPTH edge to RF reserve 0.025 mm No intersection
Via drill edge to another drilled hole edge 0.840175 mm 0.25 mm

The audit uses exact straight-line/point/rectangle distance calculations with copper radii, rather than the router's raster masks. It also verifies dimensions, source-preservation invariants, and three overwrite-refusal cases. Requires locally installed pcbnew, NumPy and Shapely; the router itself only needs pcbnew and NumPy.

DRC still honors the project's pre-existing ignored checks: missing_courtyard, track_not_centered_on_via, tuning_profile_track_geometries, footprint_filters_mismatch, and footprint_type_mismatch. --severity-all does not enable ignored checks. The routing subtask compared electrical UUID linkage and pad-net assignments with the input board. Subsequent integration also ran fresh schematic-parity DRC and added missing symbol metadata fields to the PCB without changing copper. That check reports exactly one expected U2 footprint warning (provisional PCB footprint versus intentionally blank schematic assignment); no net mismatch. See pcb-parity-drc.json and pcb-validation-summary.json.

Method and bounded passes

../route_pcb_draft.py uses a two-layer 8-direction raster A* search, an explicit via cost, exact-pad-centre terminal stubs, conservative foreign-copper and hole obstacles, and only collinear path compression. It preserves the L-shaped edge and RF reservation. Per-net minimum spanning trees connect every physical pad, including duplicate switch contacts; short links precede longer links and GND is last. It does not optimize return-current paths, topology or total via count.

  1. Initial 0.1 mm raster / 0.04 mm safety margin / 250,000 expansions per search: 29/38 connections; DRC 0 violations, 9 unconnected.
  2. Increased search allowance to 1,200,000 expansions: 30/38; DRC 0 violations, 8 unconnected. Some raster header passages were blocked, not just expensive.
  3. Final 0.05 mm raster / 0.02 mm additional safety margin, with 0.25 mm physical clearance unchanged: 38/38 in approximately 26.5 seconds; DRC fully connected. Each pass had a 240-second routing deadline. No unresolved routing remains.

A KiCad Python binding ownership problem in the first replacement attempt caused an exception/segfault before any board save. Replacement now uses board.Delete instead of board.Remove; the subsequent save and no-save rerun both passed. The known startup PROPERTY_ENUM assertions do not prevent validation.

Rerun safety

By default the script never saves. The existing routed board is protected even from a preview unless --replace-routes is given. A preview can be run with:

/usr/bin/python3 -B route_pcb_draft.py --replace-routes --seconds 240

This exact no-save workflow was tested: it again found 38/38 connections, 569 segments and 20 vias, and left the board byte-for-byte unchanged.

The following command discards all existing/manual tracks and vias, then replaces them with fresh draft routing. Back up manual work first:

/usr/bin/python3 -B route_pcb_draft.py --route --overwrite --replace-routes --seconds 240 --max-expansions 1200000

The script refuses a PCB-editor lock, unexpected outline/RF/board structure, unsupported pad orientation/layers, unapproved existing routes, or detected board changes before save. Candidate serialization must preserve immutable geometry and linkage before replacing the board. It deliberately does not run DRC itself: rerun the validation commands after any routing change. Runtime/expansion limits can produce a partial board; inspect both the run report and actual DRC, not just the script exit status.

Evidence and remaining limitations

  • pcb-routing-input.kicad_pcb: unrouted input snapshot, after baseline DRC save.
  • pcb-routing-baseline.json: 38 unconnected / no violations before routing.
  • pcb-routing-pass1-drc.json, pcb-routing-pass2-drc.json: intermediate DRC.
  • pcb-routing-pass2.log, pcb-routing-pass3.log: bounded routing progress.
  • pcb-routing-run.json: final saved-route metrics and connection list.
  • pcb-routing-drc.json, pcb-routing-all-drc.json: final KiCad DRC evidence.
  • pcb-routing-check.py, pcb-routing-check.json: repeatable independent audit.
  • pcb-routing-dry-run.log: successful final no-save reproduction.

Routing-only DRC-saved snapshot SHA-256 (before integration copied schematic metadata fields): bf94b6c9b00c43a97f933054758a2c9d6541981ae09f2f285dcdb567bd73d9b1. The current post-integration hash is recorded by pcb-routing-check.json; geometry, pad-net linkage and copper are unchanged by the metadata copy.

Still DRAFT / NOT FOR FABRICATION. Provisional module/connector geometry, antenna envelope, assembly/courtyard clearances, USB access, male RS-232 connector fit, physical pin mapping, power integrity, EMI and hardware operation are not qualified by routing or DRC. All previously documented mechanical/electrical release gates remain. No physical-device or manufacturing validation performed.