Repository navigation
Description
What were you trying to achieve?
Add four M2.5 mounting holes, two fiducials and a handful of test points to the
Class-A boards, so each one can be mounted, assembled and brought up.
What are the expected results?
The placer reserves each part's real courtyard, and kicad-cli pcb drc
reports no courtyards_overlap.
What are the received results?
courtyards_overlap on every routed run, always between a mechanical part and
whatever the placer put beside it. The first run of the standalone
protected_power_entry reported four, every one a mounting hole:
error courtyards_overlap | Footprint J2, Footprint H1
error courtyards_overlap | Footprint C10, Footprint H3
error courtyards_overlap | Footprint J1, Footprint H1
error courtyards_overlap | Footprint H1, Footprint D2
H1 alone collided with three different parts, which is what a too-small
reservation looks like to a packing algorithm. On the routed board TP2 sits
at (15.75, 37.73) and H3 at (17.25, 40.73) — 3.354 mm between centres, where
the two courtyards need 4.0 mm.
Steps To Reproduce
- Put
mounting_hole_m2_5,fiducial_1mmortestpoint_pad_1_5on a board
beside ordinary parts. - Export and route.
kicad-cli pcb drcreports the mechanical part overlapping its neighbour.
In what environment did you encounter the issue?
KiCad 10.0.6, KiCadRoutingTools caad45c, synth from main at dddda6f.
Additional information you deem important
Two bugs, one symptom. Read in order:
kicad_footprint_loader::courtyard_rect matches (fp_rect and (fp_line
blocks on F.CrtYd and nothing else. All three of these footprints draw their
courtyard as a single fp_circle:
| Footprint | F.CrtYd geometry |
Across |
|---|---|---|
MountingHole:MountingHole_2.5mm |
fp_circle r 2.75 |
5.5 mm |
TestPoint:TestPoint_Pad_D1.5mm |
fp_circle r 1.25 |
2.5 mm |
Fiducial:Fiducial_1mm_Mask2mm |
fp_circle r 1.25 |
2.5 mm |
So courtyard_rect returns None for each of them, and
pcb_courtyard_geometry_for_part falls through to its second branch —
crates/synth-layout/src/lib.rs:3368:
if let Some(dim) = part.footprint_dimensions.as_ref() {
return ((0.0, 0.0), (dim.width_mm, dim.height_mm));
}which drops courtyard_margin_mm. A mounting hole therefore reserves
2.5 × 2.5 mm — the hole — against a 5.5 mm courtyard, and its neighbours are
packed 1.5 mm a side too close. The DRC that follows is correct.
That the margin is dropped was confirmed the hard way: raising
mounting_hole_m2_5's declared margin from 0.25 mm to 1.5 mm produced a
byte-identical placement and the same overlaps, because nothing reads it.
The narrow fix is to read the circle: a (fp_circle ...) on F.CrtYd
contributes the bbox of center ± r. That is strictly additive — a footprint
that already draws a rectangle is unaffected — and it fixes these three parts
from the geometry rather than from a transcribed number. It is in the Class-A
stack, with tests over a footprint's text so the parsing is checkable without
an installed library.
The second bug is left open here: the fallback should still honour
courtyard_margin_mm, because it is the branch every footprint with an
fp_poly courtyard takes, and silently reserving the body instead of the
courtyard is the same mistake one level down. That change moves placement for
many more parts than these three, so it wants its own measurement rather than
riding along.
Found while making the Class-A boards standalone: #269, #268, #271. The
Class-C case 4 board carries the same three parts.
Activity
[-]Bug: a footprint whose courtyard is a circle reserves no area, so mounting holes land on other parts[/-][+]Bug: three mechanical parts declare the hole diameter as their courtyard, so the placer packs 2.5 mm too close[/+]fix(registry): three mechanical parts declared a hole where a courtya…
[-]Bug: three mechanical parts declare the hole diameter as their courtyard, so the placer packs 2.5 mm too close[/-][+]Bug: a circular courtyard reads as no courtyard, so mounting holes and test points land on other parts[/+]fix(layout): a circular courtyard is still a courtyard
fix(layout): a circular courtyard is still a courtyard
fix(layout): a circular courtyard is still a courtyard
fix(layout): a circular courtyard is still a courtyard