component
0705530001
Public Made by Adomby adom
Molex SL header with latch, right angle, 1x2, 2.54 mm, 70553-0001. Footprint from the Molex drawing; 3D is Molex's own model.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
#!/usr/bin/env python3
"""KiCad 10 footprints for the Molex right-angle headers, from each sales drawing's recommended PCB layout.
Pad 1 at the origin, positions along +Y; the body outline (F.Fab, F.SilkS clipped clear of the pads, F.CrtYd)
comes from the same dimensions the 3D builder uses (molex_ra.py). Model: ${KIPRJMOD}/<slug>.step, identity.
usage: molex_fp.py <series> <circuits> <slug> <out.kicad_mod>
"""
import sys, uuid
SILK_W, FAB_W, CRT_W = 0.12, 0.10, 0.05
SILK_OFF, CRT_OFF, PAD_CLR = 0.11, 0.50, 0.20
def U():
return str(uuid.uuid4())
def r2(v):
return f'{round(v + 0.0, 3):g}'
def line(a, b, layer, w):
return (f'\t(fp_line\n\t\t(start {r2(a[0])} {r2(a[1])})\n\t\t(end {r2(b[0])} {r2(b[1])})\n'
f'\t\t(stroke (width {w}) (type solid))\n\t\t(layer "{layer}")\n\t\t(uuid "{U()}")\n\t)\n')
def poly(pts, layer, w, fill=False):
p = ' '.join(f'(xy {r2(x)} {r2(y)})' for x, y in pts)
return (f'\t(fp_poly\n\t\t(pts {p})\n\t\t(stroke (width {w}) (type solid))\n\t\t(fill {"yes" if fill else "no"})\n'
f'\t\t(layer "{layer}")\n\t\t(uuid "{U()}")\n\t)\n')
def rect_lines(x0, y0, x1, y1, layer, w):
c = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
return ''.join(line(c[i], c[(i + 1) % 4], layer, w) for i in range(4))
def text_prop(name, val, at, layer, hide=True, size=1.0):
return (f'\t(property "{name}" "{val}"\n\t\t(at {r2(at[0])} {r2(at[1])} 0)\n\t\t(layer "{layer}")\n'
+ ('\t\t(hide yes)\n' if hide else '') +
f'\t\t(uuid "{U()}")\n\t\t(effects\n\t\t\t(font (size {size} {size}) (thickness {0.15 if size >= 1 else 0.1}))\n\t\t)\n\t)\n')
def pad(num, x, y, size, drill, first=False, npth=False):
if npth:
return (f'\t(pad "" np_thru_hole circle\n\t\t(at {r2(x)} {r2(y)})\n\t\t(size {r2(size)} {r2(size)})\n'
f'\t\t(drill {r2(drill)})\n\t\t(layers "*.Cu" "*.Mask")\n\t\t(uuid "{U()}")\n\t)\n')
shape = 'roundrect' if first else 'circle'
rr = '\t\t(roundrect_rratio 0.143678)\n' if first else ''
return (f'\t(pad "{num}" thru_hole {shape}\n\t\t(at {r2(x)} {r2(y)})\n\t\t(size {r2(size)} {r2(size)})\n'
f'\t\t(drill {r2(drill)})\n\t\t(layers "*.Cu" "*.Mask")\n\t\t(remove_unused_layers no)\n{rr}'
f'\t\t(uuid "{U()}")\n\t)\n')
def clip_hlines(y, x0, x1, keep_out):
"""Horizontal silk segment from x0 to x1 at y, minus intervals that come within PAD_CLR of any pad circle."""
segs = [(min(x0, x1), max(x0, x1))]
for (px, py, r) in keep_out:
if abs(py - y) >= r + PAD_CLR: continue
dx = ((r + PAD_CLR) ** 2 - (py - y) ** 2) ** 0.5
a, b = px - dx, px + dx
out = []
for s, e in segs:
if e <= a or s >= b: out.append((s, e))
else:
if s < a: out.append((s, a))
if e > b: out.append((b, e))
segs = out
return [(s, e) for s, e in segs if e - s > 0.5]
def clip_vlines(x, y0, y1, keep_out):
return [(s, e) for s, e in clip_hlines(x, y0, y1, [(py, px, r) for px, py, r in keep_out])]
def outline_silk(x0, y0, x1, y1, keep_out):
"""Rectangle offset by SILK_OFF, each side clipped clear of pads."""
x0, y0, x1, y1 = x0 - SILK_OFF, y0 - SILK_OFF, x1 + SILK_OFF, y1 + SILK_OFF
out = ''
for y in (y0, y1):
for s, e in clip_hlines(y, x0, x1, keep_out): out += line((s, y), (e, y), 'F.SilkS', SILK_W)
for x in (x0, x1):
for s, e in clip_vlines(x, y0, y1, keep_out): out += line((x, s), (x, e), 'F.SilkS', SILK_W)
return out
def poly_silk(pts, keep_out):
"""Axis-aligned closed outline (already offset outward), each edge clipped clear of pads."""
out = ''
for i in range(len(pts)):
(ax, ay), (bx, by) = pts[i], pts[(i + 1) % len(pts)]
if abs(ay - by) < 1e-9:
for s, e in clip_hlines(ay, ax, bx, keep_out): out += line((s, ay), (e, ay), 'F.SilkS', SILK_W)
else:
for s, e in clip_vlines(ax, ay, by, keep_out): out += line((ax, s), (ax, e), 'F.SilkS', SILK_W)
return out
def spec(series, n):
"""Return dict: pads [(num, x, y)], pad size, drill, npth [(x,y,d)], fab rects [(x0,y0,x1,y1)],
silk rects, courtyard extra rects, pin-1 marker side, descr."""
if series == '70553':
p = 2.54; A = (n - 1) * p
B = {2: 5.33, 3: 8.13, 4: 10.67, 9: 23.37}[n]; W = B + 2.04
ut = 13.21 - 0.32
yc = A / 2
pads = [(str(k + 1), 0.0, k * p) for k in range(n)]
fab = [(ut - 11.30, yc - W / 2, ut, yc + W / 2), (ut - 12.45, yc - B / 2, ut - 11.30, yc + B / 2),
(ut - 13.59, yc - B / 2, ut - 12.45, yc + B / 2)]
silk = [fab[0]]
return dict(pads=pads, size=1.74, drill=1.09, npth=[], fab=fab, silk=silk, mark=-1,
descr=f'Molex SL right-angle header with latch, 70553-{ {2: "0001", 4: "0003", 9: "0008"}[n] }, '
f'1x{n:02d}, 2.54 mm pitch, no pegs; pads, drill and body per Molex SDA-70553-XXXX rev M '
f'(recommended PC board layout, 1.09 mm holes for a 1.57 mm board)',
tags='Molex SL 70553 right angle header latch 2.54mm THT')
if series == '74164':
p = 2.54; ncol = n // 2; Bs = (ncol - 1) * p; K = Bs + 2 * 3.555; P = 15.54; Wo = P + 4.26
uA = 1.44 + 11.46 + 2.54; yc = Bs / 2
pads = []
for k in range(ncol):
pads += [(str(2 * k + 1), 0.0, k * p), (str(2 * k + 2), p, k * p)]
xpeg = uA - 1.44
npth = [(xpeg, yc - K / 2, 2.36), (xpeg, yc + K / 2, 2.36)]
fab = [(uA - 11.43, yc - Wo / 2, uA, yc + Wo / 2), (uA - 16.23, yc - P / 2, uA - 11.43, yc + P / 2)]
o = SILK_OFF; xm, xr, xf = uA - 11.43, uA - 16.23, uA
silk_poly = [(xr - o, yc - P / 2 - o), (xm - o, yc - P / 2 - o), (xm - o, yc - Wo / 2 - o), (xf + o, yc - Wo / 2 - o),
(xf + o, yc + Wo / 2 + o), (xm - o, yc + Wo / 2 + o), (xm - o, yc + P / 2 + o), (xr - o, yc + P / 2 + o)]
silk = []
keepout = (-0.8, -4.8, -0.8 + 16.3, Bs + 4.8)
return dict(pads=pads, size=1.70, drill=0.99, npth=npth, fab=fab, silk=silk, mark=-1, keepout=keepout,
silk_poly=silk_poly,
descr='Molex C-Grid right-angle shrouded header with PC-board stab pegs, 74164-0110, 2x05, '
'2.54 mm pitch; pads, peg holes and body per Molex SD-74164-001 rev B1 (recommended P.C. '
'board hole layout; keep-out of note 10 drawn as the courtyard). Pins: odd = row A, '
'even = row B, two per position',
tags='Molex C-Grid 74164 right angle shrouded header pegs 2.54mm THT')
if series == '87833':
p = 2.00; ncol = n // 2
Atab, Btab, Ctab = {8: (10.65, 6.00, 9.00), 10: (12.65, 8.00, 11.00)}[n]
u1 = 4.70 + 1.70 + 2.00; yc = Btab / 2
pads = []
for k in range(ncol):
pads += [(str(2 * k + 1), 0.0, k * p), (str(2 * k + 2), p, k * p)]
fab = [(u1 - 4.70, yc - Atab / 2, u1, yc + Atab / 2), (u1 - 6.40, yc - Ctab / 2, u1 - 4.70, yc + Ctab / 2)]
silk = [fab[0]]
return dict(pads=pads, size=1.40, drill=0.90, npth=[], fab=fab, silk=silk, mark=-1,
descr=f'Molex Milli-Grid right-angle shrouded header, 87833-{n:02d}32, 2x{ncol:02d}, 2.00 mm pitch, '
'centre friction lock, dual side slots; pads, drill and body per Molex SD-87833-0001 rev '
'A15 (recommended PCB layout, 0.90 mm holes). CKT 1 and 2 share the first position',
tags='Molex Milli-Grid 87833 right angle shrouded header 2.00mm THT')
if series == '90130':
p = 2.54; ncol = n // 2; A = (ncol - 1) * p; Bw = 12.50
u1 = 7.68 + 2.858 + 2.54; yc = A / 2
pads = []
for k in range(ncol):
pads += [(str(2 * k + 1), 0.0, k * p), (str(2 * k + 2), -p, k * p)]
fab = [(-u1, yc - Bw / 2, -(u1 - 10.90), yc + Bw / 2)]
silk = fab
return dict(pads=pads, size=1.70, drill=1.00, npth=[], fab=fab, silk=silk, mark=+1,
descr='Molex C-Grid III dual-row shrouded header, right angle (style 3), 90130-3108, 2x04, '
'2.54 mm pitch; pads, drill and body per Molex SDA-90130 rev CA6 sheet 3 (recommended P.C. '
'board hole pattern, 1.00 mm holes for a 1.60 mm board). CKT 1 and 2 share the first position',
tags='Molex C-Grid III 90130 right angle shrouded header 2.54mm THT')
raise SystemExit('unknown series')
def build(series, n, slug):
s = spec(series, n)
pr = s['size'] / 2
keep = [(x, y, pr) for _, x, y in s['pads']] + [(x, y, d / 2) for x, y, d in s['npth']]
xs = [x for _, x, _ in s['pads']]; ys = [y for _, _, y in s['pads']]
bx0 = min([r[0] for r in s['fab']] + [x - pr for x in xs] + [x - d / 2 for x, _, d in s['npth']])
bx1 = max([r[2] for r in s['fab']] + [x + pr for x in xs] + [x + d / 2 for x, _, d in s['npth']])
by0 = min([r[1] for r in s['fab']] + [y - pr for y in ys] + [y - d / 2 for _, y, d in s['npth']])
by1 = max([r[3] for r in s['fab']] + [y + pr for y in ys] + [y + d / 2 for _, y, d in s['npth']])
if 'keepout' in s:
k = s['keepout']; bx0, by0, bx1, by1 = min(bx0, k[0]), min(by0, k[1]), max(bx1, k[2]), max(by1, k[3])
c0x, c0y, c1x, c1y = [round(v / 0.01) * 0.01 for v in (bx0 - CRT_OFF, by0 - CRT_OFF, bx1 + CRT_OFF, by1 + CRT_OFF)]
o = f'(footprint "{slug}"\n\t(version 20241229)\n\t(generator "adom_molex_fp")\n\t(layer "F.Cu")\n'
o += f'\t(descr "{s["descr"]}")\n\t(tags "{s["tags"]}")\n'
o += text_prop('Reference', 'REF**', (bx0 + (bx1 - bx0) / 2, c0y - 0.9), 'F.SilkS', hide=True)
o += text_prop('Value', slug, (bx0 + (bx1 - bx0) / 2, c1y + 0.9), 'F.Fab', hide=True)
o += text_prop('Datasheet', '', (0, 0), 'F.Fab', hide=True, size=1.27)
o += text_prop('Description', s['descr'].split(';')[0], (0, 0), 'F.Fab', hide=True, size=1.27)
o += '\t(attr through_hole)\n\t(duplicate_pad_numbers_are_jumpers no)\n'
# fab: body rectangles + exposed pin runs + pin-1 marker
for r in s['fab']:
o += rect_lines(*r, 'F.Fab', FAB_W)
m = s['mark']
o += poly([(m * 0.9, -0.5), (m * 0.9, 0.5), (m * 0.25, 0.0)], 'F.Fab', FAB_W)
# silk: body outlines clipped clear of pads, pin-1 triangle outside the pad field
for r in s['silk']:
o += outline_silk(*r, keep)
if s.get('silk_poly'):
o += poly_silk(s['silk_poly'], keep)
pr1 = pr + PAD_CLR + 0.15
o += poly([(m * (pr1 + 0.65), -0.4), (m * (pr1 + 0.65), 0.4), (m * pr1, 0.0)], 'F.SilkS', SILK_W, fill=True)
# courtyard
o += rect_lines(c0x, c0y, c1x, c1y, 'F.CrtYd', CRT_W)
if 'keepout' in s:
k = s['keepout']
o += rect_lines(*k, 'F.Fab', FAB_W)
o += (f'\t(fp_text user "KEEP OUT (Molex note 10)"\n\t\t(at {r2((k[0] + k[2]) / 2)} {r2(k[3] - 1.2)} 0)\n'
f'\t\t(layer "F.Fab")\n\t\t(uuid "{U()}")\n\t\t(effects\n\t\t\t(font (size 0.8 0.8) (thickness 0.1))\n\t\t)\n\t)\n')
o += (f'\t(fp_text user "${{REFERENCE}}"\n\t\t(at {r2(sum(r[0] + r[2] for r in s["fab"][:1]) / 2)} '
f'{r2(sum(r[1] + r[3] for r in s["fab"][:1]) / 2)} 90)\n\t\t(layer "F.Fab")\n\t\t(uuid "{U()}")\n'
f'\t\t(effects\n\t\t\t(font (size 1 1) (thickness 0.15))\n\t\t)\n\t)\n')
for i, (num, x, y) in enumerate(s['pads']):
o += pad(num, x, y, s['size'], s['drill'], first=(num == '1'))
for x, y, d in s['npth']:
o += pad('', x, y, d, d, npth=True)
o += '\t(embedded_fonts no)\n'
o += (f'\t(model "${{KIPRJMOD}}/{slug}.step"\n\t\t(offset (xyz 0 0 0))\n\t\t(scale (xyz 1 1 1))\n'
f'\t\t(rotate (xyz 0 0 0))\n\t)\n)\n')
return o
if __name__ == '__main__':
series, n, slug, out = sys.argv[1], int(sys.argv[2]), sys.argv[3], sys.argv[4]
open(out, 'w').write(build(series, n, slug))
print('wrote', out)