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/render-local-copper.py
from route_geometry import *
import sys,html
c=load_circuit();root=connectivity(c);m=json.loads(Path('routing/net-map.json').read_text());physical=json.loads(Path(os.environ.get('PHYSICAL_INPUT','routing/physical-copper.json')).read_text())
ports={e['pcb_port_id']:e for e in c if e['type']=='pcb_port'}
parts={e['source_component_id']:e['name'] for e in c if e['type']=='source_component'}
pc={e['pcb_component_id']:parts[e['source_component_id']] for e in c if e['type']=='pcb_component'}
x0,y0,x1,y1=map(float,sys.argv[1:5]);scale=70;w=(x1-x0)*scale;h=(y1-y0)*scale
colors={'N102':'#ff8a00','N178':'#d22323','N182':'#219414','N184':'#00b8d4','N185':'#b452dd','N187':'#0c9d78','N209':'#ee001e','N192':'#ad5d00','N62':'#888888'}
colors.update({'N57':'#2468dc','N211':'#ac35bb','N58':'#e45e85','N59':'#d00000'})
out=[f'<svg xmlns="http://www.w3.org/2000/svg" width="{w*2}" height="{(h+40)*2}"><rect width="100%" height="100%" fill="white"/>']
def color(n):return '#d00000' if n==os.environ.get('HIGHLIGHT_NET') else colors.get(n,'#b7bec4')
for i,l in enumerate(LAYERS):
dx=(i%2)*w;dy=(i//2)*(h+40)
out.append(f'<text x="{dx+10}" y="{dy+25}" font-size="22">{l}</text><svg x="{dx}" y="{dy+40}" width="{w}" height="{h}" viewBox="{x0} {-y1} {x1-x0} {y1-y0}"><g transform="scale(1,-1)">')
for z in range(math.floor(x0),math.ceil(x1)+1):out.append(f'<path d="M{z} {y0}V{y1}" stroke="#eee" stroke-width=".01"/>')
for z in range(math.floor(y0),math.ceil(y1)+1):out.append(f'<path d="M{x0} {z}H{x1}" stroke="#eee" stroke-width=".01"/>')
for wire in physical['wires']:
if wire['layer']!=l:continue
pts=wire['points'];out.append(f'<path d="M'+ ' L'.join(f'{x} {y}' for x,y in pts)+f'" fill="none" stroke="{color(wire["net"])}" stroke-width="{wire["width"]}" stroke-linecap="round"/>')
for e in c:
if e['type'] not in ['pcb_smtpad','pcb_plated_hole'] or l not in e.get('layers',[e.get('layer')]):continue
p=ports.get(e.get('pcb_port_id'));n=m['roots'].get(root(p['source_port_id'])) if p else None
g=geometry(e,'outer_' if e['type']=='pcb_plated_hole' else '')
out.append(f'<path d="M'+ ' L'.join(f'{x} {y}' for x,y in g.exterior.coords)+f'Z" fill="{color(n)}" stroke="#333" stroke-width=".01"/>')
if g.intersects(box(x0,y0,x1,y1)):
at=g.centroid;label=html.escape(pc.get(e.get('pcb_component_id'),'?')+' '+str(n))
out.append(f'<g transform="translate({at.x} {at.y}) scale(1,-1)"><text text-anchor="middle" y="-.08" font-size=".13">{label}</text></g>')
for v in physical['vias']:
out.append(f'<circle cx="{v["x"]}" cy="{v["y"]}" r=".225" fill="{color(v["net"])}" stroke="#111" stroke-width=".015"/><circle cx="{v["x"]}" cy="{v["y"]}" r=".15" fill="white"/>')
for e in c:
if e['type']=='pcb_hole':
g=geometry(e,'hole_')
out.append('<path d="M'+' L'.join(f'{x} {y}' for x,y in g.exterior.coords)+'Z" fill="white" stroke="#111" stroke-width=".025"/>')
out.append('</g></svg>')
out.append('</svg>');Path('reports/local-copper.svg').write_text(''.join(out))