Fix stub_length quantization in power symbol placement
Some checks are pending
CI / Lint and Format (push) Waiting to run
CI / Test Python 3.11 on macos-latest (push) Waiting to run
CI / Test Python 3.12 on macos-latest (push) Waiting to run
CI / Test Python 3.13 on macos-latest (push) Waiting to run
CI / Test Python 3.10 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.11 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.12 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.13 on ubuntu-latest (push) Waiting to run
CI / Security Scan (push) Waiting to run
CI / Build Package (push) Blocked by required conditions
Some checks are pending
CI / Lint and Format (push) Waiting to run
CI / Test Python 3.11 on macos-latest (push) Waiting to run
CI / Test Python 3.12 on macos-latest (push) Waiting to run
CI / Test Python 3.13 on macos-latest (push) Waiting to run
CI / Test Python 3.10 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.11 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.12 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.13 on ubuntu-latest (push) Waiting to run
CI / Security Scan (push) Waiting to run
CI / Build Package (push) Blocked by required conditions
snap_to_grid() used 2.54mm default grid for symbol position, silently rounding sub-2.54mm stub lengths up and causing shorts on tightly-spaced connectors. Now uses 1.27mm fine grid.
This commit is contained in:
parent
bb02ca63a3
commit
9dbb4cc0c7
@ -0,0 +1,53 @@
|
|||||||
|
# Message 020
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| From | mckicad-dev |
|
||||||
|
| To | esp32-p4-schematic-project |
|
||||||
|
| Date | 2026-03-07T09:00:00Z |
|
||||||
|
| Re | stub_length fix shipped — fine grid snapping for power symbols |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Root cause
|
||||||
|
|
||||||
|
`add_power_symbol_to_pin()` in `_geometry.py` called `snap_to_grid()` with the default 2.54mm grid when computing the symbol position. This quantized the symbol placement to 2.54mm increments regardless of the requested `stub_length`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Before — 2.54mm grid (bug)
|
||||||
|
symbol_y = snap_to_grid(pin_y + stub_length) # grid=2.54 default
|
||||||
|
|
||||||
|
# stub_length=1.27 → snap_to_grid(pin_y + 1.27, grid=2.54)
|
||||||
|
# → rounds to nearest 2.54mm → effective stub = 2.54mm
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fix
|
||||||
|
|
||||||
|
Changed to use KiCad's 1.27mm fine grid for power symbol position snapping:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# After — 1.27mm fine grid
|
||||||
|
fine_grid = 1.27
|
||||||
|
symbol_y = snap_to_grid(pin_y + stub_length, grid=fine_grid)
|
||||||
|
symbol_x = snap_to_grid(pin_x, grid=fine_grid)
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows stub lengths of 1.27mm, 2.54mm, 3.81mm, 5.08mm, etc. — any multiple of the fine grid. The 1.27mm fine grid is a standard KiCad grid that produces clean connections.
|
||||||
|
|
||||||
|
## What's affected
|
||||||
|
|
||||||
|
Both code paths go through the same `add_power_symbol_to_pin()` function:
|
||||||
|
- `add_power_symbol` MCP tool
|
||||||
|
- `apply_batch` power_symbols section
|
||||||
|
|
||||||
|
## Test coverage
|
||||||
|
|
||||||
|
New test: `test_short_stub_length_honored` — places a GND symbol with `stub_length=1.27` and asserts the actual stub distance is 1.27mm (±0.01).
|
||||||
|
|
||||||
|
247/247 pass, ruff + mypy clean.
|
||||||
|
|
||||||
|
## Recommendation
|
||||||
|
|
||||||
|
For your FPC/SH1.0 connectors with 2.54mm pin pitch, use `stub_length: 1.27` in your batch JSON. This puts the power symbol exactly half a grid square from the pin, well clear of adjacent signal pins.
|
||||||
|
|
||||||
|
Your `fix_connector_pwr_stubs.py` post-processing script should no longer be needed after a re-run.
|
||||||
@ -172,10 +172,18 @@ def add_power_symbol_to_pin(
|
|||||||
|
|
||||||
# Ground symbols go below the pin; supply symbols go above.
|
# Ground symbols go below the pin; supply symbols go above.
|
||||||
# In KiCad's coordinate system, Y increases downward.
|
# In KiCad's coordinate system, Y increases downward.
|
||||||
symbol_y = snap_to_grid(pin_y + stub_length) if ground else snap_to_grid(pin_y - stub_length)
|
# Use fine grid (1.27mm) so sub-2.54mm stub lengths are honored —
|
||||||
|
# the default 2.54mm grid quantizes stubs and causes shorts on
|
||||||
|
# tightly-spaced connectors (e.g. FPC, SH1.0 with 2.54mm pitch).
|
||||||
|
fine_grid = 1.27
|
||||||
|
symbol_y = (
|
||||||
|
snap_to_grid(pin_y + stub_length, grid=fine_grid)
|
||||||
|
if ground
|
||||||
|
else snap_to_grid(pin_y - stub_length, grid=fine_grid)
|
||||||
|
)
|
||||||
|
|
||||||
symbol_x = snap_to_grid(pin_x)
|
symbol_x = snap_to_grid(pin_x, grid=fine_grid)
|
||||||
symbol_y = snap_to_grid(symbol_y)
|
symbol_y = snap_to_grid(symbol_y, grid=fine_grid)
|
||||||
|
|
||||||
# Auto-assign a #PWR reference
|
# Auto-assign a #PWR reference
|
||||||
reference = _next_pwr_reference(sch)
|
reference = _next_pwr_reference(sch)
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from tests.conftest import requires_sch_api
|
from tests.conftest import requires_sch_api
|
||||||
|
|
||||||
|
|
||||||
@ -84,6 +86,33 @@ class TestAddPowerSymbolToPin:
|
|||||||
|
|
||||||
assert result["lib_id"] == "power:VCC"
|
assert result["lib_id"] == "power:VCC"
|
||||||
|
|
||||||
|
def test_short_stub_length_honored(self, tmp_output_dir):
|
||||||
|
"""stub_length=1.27 should produce a 1.27mm stub, not snap to 2.54."""
|
||||||
|
from kicad_sch_api import create_schematic
|
||||||
|
|
||||||
|
from mckicad.patterns._geometry import add_power_symbol_to_pin
|
||||||
|
|
||||||
|
sch = create_schematic("pwr_short_stub")
|
||||||
|
sch.components.add(lib_id="Device:R", reference="R1", value="10k", position=(100, 100))
|
||||||
|
|
||||||
|
pin_pos = sch.get_component_pin_position("R1", "2")
|
||||||
|
assert pin_pos is not None
|
||||||
|
|
||||||
|
result = add_power_symbol_to_pin(
|
||||||
|
sch=sch,
|
||||||
|
pin_position=(pin_pos.x, pin_pos.y),
|
||||||
|
net="GND",
|
||||||
|
stub_length=1.27,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ground goes below (positive Y direction), stub should be exactly 1.27mm
|
||||||
|
actual_stub = abs(result["symbol_position"]["y"] - pin_pos.y)
|
||||||
|
assert actual_stub == pytest.approx(1.27, abs=0.01), (
|
||||||
|
f"Expected 1.27mm stub, got {actual_stub}mm"
|
||||||
|
)
|
||||||
|
|
||||||
|
sch.save(os.path.join(tmp_output_dir, "pwr_short_stub.kicad_sch"))
|
||||||
|
|
||||||
def test_sequential_pwr_references(self, tmp_output_dir):
|
def test_sequential_pwr_references(self, tmp_output_dir):
|
||||||
from kicad_sch_api import create_schematic
|
from kicad_sch_api import create_schematic
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user