Files
ESP32_Serial_Swiss_Army_Knife/hardware/PCB/validation/pcb-routing-summary.md
T
Commander1024 7d76a41540 Advance PCB carrier to A1 layout
Reposition the ESP32 and RS-232 reference within the notched outline,
preserve the A0 snapshot, and add second-pass two-layer routing
evidence.
Refresh validation reports and draft previews while keeping fabrication
status provisional.
2026-09-21 12:32:01 +02:00

13 KiB

A1 top-left-notch / bottom-USB routing — current result

Date: 2026-09-21. Actual revised board: ../serial-carrier.kicad_pcb.

38/38 connections across 17 multi-pad nets; 0 physical DRC violations, 0 unconnected items; exactly 1 expected U2 footprint parity warning. The warning is the board-only Carrier:MAX3243_Reference_Provisional assignment versus the intentionally blank schematic footprint, not a net mismatch.

Geometry and preservation

Coordinates below are local to absolute origin (100,100) mm; all dimensions mm.

  • Carrier: 82 x 80, outline [(36,0),(82,0),(82,80),(0,80),(0,19),(36,19)].
  • U1 origin: (8,23), formerly (8,4). Header end-pad centres now Y=76.340; USB guide Y=83 is 3 mm below the bottom edge. No ESP32 body was invented.
  • U2 origin: (43,26.670), formerly (43,30). Actual reference F.Fab bare-PCB front edge is absolute Y=100.000, flush with carrier local Y=0.
  • Nominal male metal external dimensions are user-confirmed: shell overhang 3.870, hex-mouth overhang 2.870, flange front 1.930 behind the carrier edge. With this placement their local Y positions are -3.870, -2.870 and +1.930. Integration added seven board-local Dwgs.User graphics for the CAD metal projections and screw-lock axes.
  • H1: (3.5,22.5), H2: (3.5,75). H3/H4 unchanged at (78,4)/(78,76).
  • OLED, resistors and switches unchanged.
  • RF reserve: local X=10..31 / Y=19..32, absolute X=110..131 / Y=119..132, both layers; no tracks, vias or fills inside it. Boundary remains provisional.

The existing A0 board was mutated, not regenerated. The one-time pcb-a0-before-reposition.kicad_pcb backup remains byte-for-byte intact. pcb-routing-input.kicad_pcb is now the A1 unrouted audit input, not A0. pcb-routing-preservation.py verified all 13 complete serialized footprints identical except the four authorized top-level placements, including schematic fields, pad/net definitions, electrical UUID paths and all footprint graphics. Non-owned board-graphic UUIDs and unrelated graphics are preserved. ESP/RS/RF annotations moved with placement; the post-routing silkscreen refresh replaced 91 owned graphics. Its edge clipping avoids silk across U2's flush front edge.

All board saves used SaveBoard(..., True). Project .pro, .prl, schematic, symbol/footprint libraries and library tables retain their original hashes. README and pcb-draft-notes were intentionally updated during integration. The generator's constants/text were updated but it was not run; its automatic project/netclass writes were removed. PCB Editor lock was absent at migration, routing, silkscreen refresh and final preservation check.

Routing and independent measurements

  • F.Cu/B.Cu; 565 segments, 22 through vias.
  • 451 signal segments at 0.25 mm; 114 +3V3/GND segments at 0.5 mm.
  • Vias: 0.7 mm copper / 0.3 mm drill. No copper pours needed.
  • Continuous measured minimum different-net/NPTH clearance: 0.270544 mm.
  • Minimum copper/NPTH-to-edge gap: 1.900 mm.
  • Minimum copper/NPTH-to-RF-reservation gap: 0.025 mm.
  • Minimum via-drill edge to other drilled-hole edge: 0.820544 mm.

Two bounded passes, each with 240 seconds / 1,200,000 expansions per search:

  1. 31.18 seconds, 38/38, 674 segments / 16 vias, physical DRC clean. One GND connection required the router's 0.25 mm fallback; strict width validation correctly failed. Retained as pcb-routing-a1-pass1.kicad_pcb for evidence.
  2. 32.44 seconds, 38/38, 565 segments / 22 vias. Short GND connections (<=15 mm) now route before longer signal fanout; long GND links remain last. All power and ground now use 0.5 mm; no fallback. This is the saved current result.

The grid remains 0.05 mm, physical clearance 0.25 mm plus 0.02 mm routing margin. No rip-up/unbounded retry or external network router was used.

Validation / rerun commands

From hardware/PCB:

/usr/bin/python3 -B validate_pcb_draft.py
/usr/bin/python3 -B validation/pcb-routing-check.py
/usr/bin/python3 -B validation/pcb-routing-preservation.py
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

All passed on A1. Validators perform fresh KiCad DRC, fresh schematic-netlist comparison, geometry checks, continuous copper-distance checks, and routing save-refusal tests. DRC was read-only to preserve project settings; no copper zones exist to refill. Existing ignored DRC checks were not changed; see reports. The preservation audit includes the intentional documentation updates and seven CAD projection graphics while retaining electrical and project preservation checks.

Rerouting remains explicitly destructive to existing/manual copper and requires:

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

Then rerun the validators. The one-shot pcb-routing-reposition.py --apply refuses anything except the original A0 snapshot and must not be rerun on A1.

Current evidence: pcb-routing-a1-pass2.log, pcb-routing-run.json, pcb-routing-drc.json, pcb-routing-all-drc.json, pcb-parity-drc.json, pcb-validation-summary.json, pcb-routing-check.json, pcb-routing-reposition.json, and pcb-routing-preservation.json. The current post-integration board SHA-256 is recorded in pcb-routing-check.json; the CAD projection additions do not change copper.

Still a draft, not fabrication-ready. ESP32 geometry/antenna/USB access, module pinout/header fit, full assembly/height clearances, power integrity and hardware operation remain unqualified. Nominal RS-232 metal dimensions alone are not assembly qualification. Placement PDF, SVG/PNG and carrier-only 3D preview were refreshed after CAD envelope integration. No Gerbers generated.


Historical A0 routing result — superseded by A1 above

The following records the earlier A0 routing/integration. Its dimensions, counts, measurements and no-save reproduction do not describe current A1. A0 pass1, pass2, pass3, baseline and dry-run files are historical; use the A1 and current reports listed above.

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.