mohan-bee/rc-link-breakaway-panel

A four-layer RC link panel combining an STM32/E28 2.4‑GHz transmitter with USB-RP2040 socket and an STM32/E28 receiver providing six buffered PWM servo outputs, regulated 3.3‑V power, headers, controls, and protection/decoupling.

Version
0.1.5
License
unset
Stars
0

tools/make-panel-geometry.py

"""Generate native cutout vertices; no Gerber edits or external PCB CAD."""
import json
from pathlib import Path
from shapely.geometry import Polygon, box
from shapely.affinity import translate
from shapely.ops import unary_union

root = Path(__file__).resolve().parents[1]
units = []
for name, dx, dy in [("transmitter", -23.5, 0), ("receiver", 36.5, -3)]:
    circuit = json.loads((root / "boards" / f"{name}.circuit.json").read_text())
    board = next(e for e in circuit if e["type"] == "pcb_board")
    units.append(translate(Polygon([(p["x"], p["y"]) for p in board["outline"]]), dx, dy))

# Centre bridges are shared by both boards. Other bridges terminate in the rail.
vertical = [(-58.5, y) for y in [-15, 9]] + [(58.5, y) for y in [-15, 9]]
horizontal = [(x, -30) for x in [-35.5, -1.5, 28.5, 44.5]]
bridges = [box(x-4, y-2, x+4, y+2) for x, y in vertical]
bridges += [box(9.5, y-2, 16.5, y+2) for y in [-15, 9]]
bridges += [box(x-2, y-4, x+2, y+4) for x, y in horizontal]
band = unary_union([u.buffer(3, resolution=32) for u in units]).difference(unary_union(units))
raw_slots = band.difference(unary_union(bridges))
slots = unary_union([p.buffer(-1, resolution=16).buffer(1, resolution=16) for p in raw_slots.geoms])
assert slots.is_valid
assert all(p.area > 1 and not p.interiors for p in slots.geoms)
print("intersection areas", [slots.intersection(u).area for u in units]); slots = slots.difference(unary_union(units).buffer(0.00001))

holes = []
for x, y in vertical + [(x, y) for x in [11.5, 14.5] for y in [-15, 9]]:
    holes += [{"x": x, "y": round(y + i * .85, 4)} for i in range(-3, 4)]
for x, y in horizontal:
    holes += [{"x": round(x + i * .85, 4), "y": y} for i in range(-3, 4)]
assert len(holes) == 84
data = {
    "slots": [[{"x": round(x, 6), "y": round(y, 6)} for x,y in list(p.exterior.coords)[:-1]] for p in slots.geoms],
    "mouseBites": holes,
    "tooling": [{"x": x, "y": y} for x in [-50, 50] for y in [-34.15, 34.15]],
    "fiducials": [{"x": -62.65, "y": 34.15}, {"x": 62.65, "y": 34.15}, {"x": -62.65, "y": -34.15}],
}
(root / "panel-geometry.json").write_text(json.dumps(data, indent=2) + "\n")
print(len(data["slots"]), "routed slots;", len(holes), "mouse-bite drills")