shibosoftwaredev/f1c100s-linux-nema17-stepper-controller

A four-layer NEMA 17 motor-controller PCB combining an Allwinner F1C100S Linux computer, USB‑PD/buck power system, W5500 Ethernet, STM32 real-time motion control, DRV8825 stepper driver, protection/temperature/current telemetry, USB interfaces, and local LED/buzzer diagnostics.

Version
0.4.56
License
unset
Stars
0

scripts/find-review-stitches.py

"""Read-only search for solder-land-safe signal escape stitches."""
from route_geometry import *
from shapely.strtree import STRtree
import sys
c=load_circuit('routing/review-placement.circuit.json');root=connectivity(c)
m=json.loads(Path('routing/net-map.json').read_text())['roots']
ports={e['pcb_port_id']:e for e in c if e['type']=='pcb_port'}
sources={e['source_trace_id']:e for e in c if e['type']=='source_trace'}
pads=[]
for e in c:
    if e['type'] in ['pcb_smtpad','pcb_plated_hole']:
        p=ports.get(e.get('pcb_port_id'));n=m[root(p['source_port_id'])] if p else 'NC'
        pads.append((n,e.get('layers',[e.get('layer')]),geometry(e,'outer_' if e['type']=='pcb_plated_hole' else '')))
ptree=STRtree([p[2] for p in pads])
physical=json.loads(Path(os.environ.get('PHYSICAL_INPUT','routing/bulk-top-closure-seed-physical.json')).read_text())
wires=[(w['net'],w['layer'],w['width'],LineString(w['points']).buffer(w['width']/2)) for w in physical['wires']]
wtree=STRtree([w[3] for w in wires])
drawn=json.loads(Path('reports/swap-preparation.json').read_text())['authoredWires']
protected=[(w['net'],w['layer'],LineString(w['points']).buffer(w['width']/2)) for w in drawn]
selected=[]
for job in json.loads(Path(os.environ.get('REVIEW_PLAN','routing/bulk-top-closure-plan.json')).read_text())['jobs']:
    s=sources[job['source']];n=m[root((s.get('connected_source_port_ids',[])+s.get('connected_source_net_ids',[]))[0])]
    if n not in sys.argv[1:] or job['start']['pcb_port_id'] not in ports:continue
    start=job['start'];xy0=(start['x'],start['y']);layer=start['layers'][0];width=max(.12,s.get('min_trace_thickness',.12));out=[]
    for ix in range(round(xy0[0]*20)-38,round(xy0[0]*20)+39):
        for iy in range(round(xy0[1]*20)-38,round(xy0[1]*20)+39):
            xy=ix/20,iy/20;point=Point(xy);line=LineString([xy0,xy]);d=math.dist(xy,xy0)
            if d<.4 or d>1.9 or max(abs(xy[0]),abs(xy[1]))>20.7:continue
            if any(math.dist(xy,(x,y))<3.1 for x in [-15.5,15.5] for y in [-15.5,15.5]):continue
            if any(math.dist(xy,(v['x'],v['y']))<.554 for v in physical['vias']):continue
            pi=set(map(int,ptree.query(point.buffer(.36))))|set(map(int,ptree.query(line.buffer(width/2+.101))))
            if any(pads[i][2].distance(point)<.354 or pads[i][0]!=n and layer in pads[i][1] and pads[i][2].distance(line)<width/2+.1001 for i in pi):continue
            if any(nn!=n and (g.distance(point)<.354 or ll==layer and g.distance(line)<width/2+.1001) for nn,ll,g in protected):continue
            wi=set(map(int,wtree.query(point.buffer(.36))))|set(map(int,wtree.query(line.buffer(width/2+.101))))
            bad=[wires[i] for i in wi if wires[i][0]!=n and (wires[i][3].distance(point)<.354 or wires[i][1]==layer and wires[i][3].distance(line)<width/2+.1001)]
            if any(w>=.299 for nn,ll,w,g in bad):continue
            out.append((round(d+len(bad)*.4,3),xy,[(nn,ll,w) for nn,ll,w,g in bad]))
    out.sort();selected.append(dict(net=n,start=xy0,layer=layer,width=width,candidates=out[:5]))
print(json.dumps(selected))