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/author-sense-closure.py

"""Explicit local connections for review by the independent copper checker."""
from route_geometry import *
c=load_circuit();root=connectivity(c)
m=json.loads(Path('routing/net-map.json').read_text())['roots']
sources={e['name']:e for e in c if e['type']=='source_trace' and e.get('name')}
out=[]
def add(name, spec):
    points,layer,width=spec['points'],spec.get('layer','top'),spec.get('width',.15)
    s=sources[name];ids=s.get('connected_source_port_ids',[])+s.get('connected_source_net_ids',[])
    route=[dict(route_type='wire',x=x,y=y,layer=layer,width=width) for x,y in points]
    if spec.get('via'):
        x,y=points[-1]
        route.append(dict(route_type='via',x=x,y=y,from_layer=layer,to_layer='bottom' if layer=='top' else 'top',via_diameter=.45,via_hole_diameter=.3))
    out.append(dict(type='pcb_trace',name=name,source_trace_id=s['source_trace_id'],connection_name=m[root(ids[0])],route=route))

add('CURRENT_A_MCU',dict(points=[(17.275078,-1.870962),(17.275078,-2.7),(17.1,-2.95)],layer='bottom',via=True))
add('CURRENT_A_MCU',dict(points=[(17.1,-2.95),(17.54,-2.8)]))
add('CURRENT_B_MCU',dict(points=[(15.32512,-1.870962),(15.32512,-2.55),(15.775,-3),(16.31,-3)],layer='bottom',via=True))
add('CURRENT_A_FILTER_GND',dict(points=[(20,-3.74),(20.8,-3.74),(20.8,-7.61),(20.35,-7.61)],via=True))
add('CURRENT_A_FILTER_GND',dict(points=[(20.35,-7.61),(20.35,-8.1),(20.8,-8.625),(19.6,-8.625)],layer='bottom'))
add('VM_PROTECTED',dict(points=[(19.25,-9.3),(19.25,-11.7),(18.55,-11.7),(18,-12.25),(18,-12.5)],width=.8))
add('TEMP_ALERT_PULLUP',dict(points=[(20.51,-12.7),(20.8,-12.7),(20.8,-15.8),(20.7,-15.8)],via=True))
add('TEMP_ALERT',dict(points=[(20.449986,-17.200001),(20.8,-17.200001),(20.8,-15.8),(20.7,-15.8)]))
add('TEMP_ALERT',dict(points=[(20.7,-15.8),(19.7569,-15.8),(19.7569,-16.2611)],layer='inner1'))
add('TEMP_SCL',dict(points=[(20.449986,-18.199999),(20.8,-18.199999),(20.8,-20.85),(13.5,-20.85),(13.5,-20)]))
add('TEMP_SDA',dict(points=[(18.950014,-18.199999),(18.5,-18.199999),(18.5,-18.5),(16.5,-18.5),(16.5,-19)],via=True))
add('TEMP_SDA',dict(points=[(16.5,-19),(16.5,-20.5),(11.25,-20.5),(11.25,-19.9)],layer='inner2'))
add('CURRENT_B_DECOUPLE',dict(points=[(8.12432,-17.2),(8.27,-17.6),(7.85,-18.175)],layer='bottom'))
add('CURRENT_B_DECOUPLE_GND',dict(points=[(7.57568,-17.2),(6,-17.3),(5.6,-16.85)],layer='bottom',via=True))
add('CURRENT_B_DECOUPLE_GND',dict(points=[(5.6,-16.85),(5.6,-17.7),(12.21,-17.7),(12.21,-16.875)],layer='inner1'))
add('DRV_REF_DIV',dict(points=[(8.51,-14.8),(8.51,-15.2),(10.7,-15.2),(10.7,-17.1)],via=True))
add('DRV_REF_DIV',dict(points=[(8.51,-14.8),(8.51,-15.4),(7.6,-15.4),(7.6,-16.78),(7.06,-16.78)],via=True))
add('DRV_REF_DIV',dict(points=[(7.06,-16.78),(6.1873,-16.7444)],layer='inner2'))
add('DRV_REF_BOTTOM',dict(points=[(12.88,-17.75),(12.88,-18.3),(11,-18.3),(10.7,-18),(10.7,-17.1)],layer='bottom'))
add('DRV_REF_GND',dict(points=[(11.86,-17.75),(11.86,-17.4),(12.21,-16.875)],layer='bottom'))
add('MOTOR_ENABLE_PULLDOWN_GND',dict(points=[(8.99,-17.2),(8.99,-16.6),(7.57568,-16.6),(7.57568,-17.2)],layer='bottom'))
add('MOTOR_ENABLE_PULLDOWN',dict(points=[(10.01,-17.2),(10.1,-16.1),(10.5,-14.1)],layer='bottom'))
add('DRV_REF_CAP',dict(points=[(6.59,-14.9),(6.1873,-14.1719)],layer='bottom'))
add('ISET_210_VREF',dict(points=[(5.51,-14.3),(6.1873,-14.1719)],layer='bottom'))
add('ISET_210_GND',dict(points=[(4.49,-14.3),(4.49,-15.41),(7.61,-15.41),(7.61,-14.9)],layer='bottom'))
add('DRV_REF_CAP_GND',dict(points=[(7.61,-14.9),(7.61,-14.1),(8.05,-13.1)],layer='bottom'))
add('TEMP_GND',dict(points=[(20.449986,-17.700127),(19.8,-17.7),(19.8,-16.8),(20.3,-16.5)],via=True))
add('TEMP_ADDR',dict(points=[(18.950014,-17.200001),(19.3,-17.2),(19.8,-16.8),(20.3,-16.5)]))
add('TEMP_BYPASS_GND',dict(points=[(19.81,-15.95),(20.1,-15.95),(20.1,-16.3),(20.3,-16.5)]))
add('TEMP_BYPASS',dict(points=[(18.950014,-17.700127),(18.25,-17.700127),(18.25,-16.65),(18.5,-16.4),(18.79,-15.95)]))
add('TEMP_VDD',dict(points=[(18.79,-15.95),(19.3,-16.55)],via=True))
add('TEMP_VDD',dict(points=[(19.3,-16.55),(19.3,-19.5),(19.2,-19.5)],layer='inner1'))
add('TEMP_VDD',dict(points=[(19.7,-18.4),(19.7,-19.5),(19.2,-19.5)],layer='inner2',via=True))
add('TEMP_ALERT_PULLUP_3V3',dict(points=[(19.49,-12.7),(19.49,-13),(18.45,-13),(18.45,-15.2),(18.79,-15.95)]))
add('TEMP_GND',dict(points=[(20.3,-16.5),(20.75,-16.95),(20.75,-20.8),(10.6272,-20.8),(10.6272,-20.3)],layer='inner1'))
add('ETH_RAIL_BC_C',dict(points=[(11.3132,-14.3895),(11.4632,-14.8895)],layer='bottom',width=.25,via=True))
add('ETH_RAIL_BC_C',dict(points=[(11.4632,-14.8895),(11.3132,-14.8895)],layer='inner1',width=.25))
add('STATUS_DATA_BUFFER_OUT',dict(points=[(-18.675,-17),(-18.675,-16.35)],layer='bottom',via=True))
add('STATUS_DATA_BUFFER_OUT',dict(points=[(-18.675,-16.35),(-18.675,-13.2),(-12,-13.2),(-11,-14.5),(-4.2063,-14.5),(-4.2063,-14.5221)],layer='inner2'))
add('CURRENT_A_FILTER_CAP',dict(points=[(20,-4.76),(19.6,-5.2),(18.4,-5.2)],via=True))
add('CURRENT_A_FILTER_CAP',dict(points=[(18.4,-5.2),(18.4,-4.2),(17.3,-3.1),(17.1,-2.95)],layer='inner2'))
add('CURRENT_B_FILTER_CAP',dict(points=[(14.235,-2.27),(14.7,-2.9),(16.31,-3)]))
add('CURRENT_B_FILTER_GND',dict(points=[(13.215,-2.27),(12.2,-2.27),(12.2,-3.5)]))
add('CURRENT_B_FILTER_GND',dict(points=[(12.2,-3.5),(11.9,-4.3),(11.9,-4.8),(11.2,-5.5),(11.2,-6),(11.7,-6.5),(11.7,-10.6),(11.8,-10.7),(11.8,-10.8),(14.9,-10.8),(14.95,-10.9)]))
add('CURRENT_A_SUPPLY',dict(points=[(-6.96,-16.375),(-2.1,-16.4),(-2,-16.5),(-1.6,-16.5),(-1.5,-16.4),(-1.4,-16.4),(-1.3,-16.3),(-.4,-16.3),(-.2,-16.5),(-.2,-16.6),(0,-16.8)],layer='inner2',via=True))
add('CURRENT_A_SUPPLY',dict(points=[(0,-16.8),(0,-16.5),(-.4,-16.1),(-.4,-6.7),(-.5,-6.6),(-.5,-6.5),(-.6,-6.4),(-.6,-6.2),(-.7,-6.1),(-.7,-6),(-.8,-5.9),(-.8,-5.8),(-1.2,-5.4),(-1.2,-1.7),(-.4,-.9)],layer='inner1',via=True))
add('CURRENT_A_SUPPLY',dict(points=[(-.4,-.9),(-3,-.9),(-3.0885,-.7696)],layer='inner2'))
add('CURRENT_A_OUTPUT',dict(points=[(18.56,-2.8),(19.61,-1.25)],via=True))
add('CURRENT_A_OUTPUT',dict(points=[(-8.46,-15.925),(-8,-15.4),(-8,-14.1),(-6.2,-12.3),(-6.2,-10.5)],layer='inner1',via=True))
add('CURRENT_A_OUTPUT',dict(points=[(-6.2,-10.5),(-6.7,-10),(-7.1,-10),(-7.2,-9.9),(-7.2,-9.8),(-7.3,-9.7),(-7.3,-9.4),(-7.2,-9.3),(-7.2,-.7),(-7.1,-.6),(-7.1,-.3),(-6.8,0),(-6.7,0),(-6.6,.1),(-6.5,.1),(-6.3,.3),(-6.3,1.4),(-6.7,1.8),(-6.7,2.4),(-6.5,2.6),(-6.5,3.5),(-6.1,3.9),(-6.1,4),(-4.7,5.4),(-4.7,8.5)],via=True))
add('CURRENT_A_OUTPUT',dict(points=[(-4.7,8.5),(-3.7,8.5),(-2.8,9.4),(-2.7,9.4),(-2.6,9.5),(-2.5,9.5),(-1.8,10.2)],layer='inner2',via=True))
add('CURRENT_A_OUTPUT',dict(points=[(-1.8,10.2),(-1.8,10.7),(-3,11.9),(-3,12.5),(-3.4,12.9),(-3.4,13),(-3.5,13.1),(-3.5,14.6),(-3.4,14.7),(-3.4,14.8),(-1.1,17.1),(-1.1,17.6),(-1,17.7),(-1,17.8),(-.9,17.9),(-.3,17.9),(1.2,19.4),(7.7,19.4),(9.1,20.8),(9.7,20.8),(11.3,19.2),(11.4,19.2),(11.5,19.1),(11.8,19.1),(12.1,18.8),(19.5,18.8),(19.7,18.6),(19.7,14.8),(20.6,13.9),(20.6,.9),(20.5,.8),(20.5,.1),(19.9,-.5),(19.9,-.6),(19.8,-.7),(19.8,-.8),(19.7,-.9),(19.7,-1.1),(19.61,-1.25)],layer='inner1'))
add('ETH_RAIL_BC_B',dict(points=[(12.3332,-14.3895),(12.3332,-13),(13.5132,-13.0395)],layer='bottom',width=.25,via=True))
add('ETH_RAIL_BC_B',dict(points=[(13.5132,-13.0395),(14.4,-12.1),(14.4,-10.7),(14.5,-10.6),(14.5,-10.2),(18.1,-6.6),(18.1,-6.4),(18.2485,-6.3198)],layer='inner2',width=.25))
add('CURRENT_B_OUTPUT',dict(points=[(10.14,-18.175),(10.9,-18.2),(11,-18.3),(12.1,-18.3),(12.5,-17.9),(12.5,-17.3),(12.7,-17.1),(12.7,-16.6),(12.4,-16.3)],layer='inner1',via=True))
add('CURRENT_B_OUTPUT',dict(points=[(12.4,-16.3),(12,-16.3),(11.9,-16.2),(11.7,-16.2),(11.65,-16.1)],layer='bottom'))
add('CURRENT_B_FILTER',dict(points=[(10.63,-16.1),(11.15,-15.6),(12.4,-15.6),(12.75,-15.95),(12.75,-16),(12.85,-16.1),(12.85,-16.7),(15.1,-18.95),(15.75,-18.95),(16.15,-19.35),(16.2,-19.35),(16.3,-19.45),(17.7,-19.45),(18.05,-19.8),(18.1,-19.8),(18.2,-19.9),(18.95,-19.9),(19,-19.95),(20.1,-19.95),(20.3,-20.15)],layer='bottom',via=True))
add('CURRENT_B_FILTER',dict(points=[(20.3,-20.15),(20.3,-19.5),(20.25,-19.45),(20.25,-19.4),(20.2,-19.35),(20.2,-17.05),(20,-16.85),(19.95,-16.85),(19.8,-16.7),(19.8,-15.15),(19.75,-15.1),(19.75,-15.05),(19.7,-15),(19.7,-14.95),(18.9,-14.15),(18.9,-10.7),(18.85,-10.65),(18.85,-5),(18.75,-4.9),(18.75,-4.85),(18.7,-4.8),(18.7,-4.15),(18.65,-4.1),(18.65,-4),(17.55,-2.9),(17.55,-2.75),(17.45,-2.65),(17.45,-2.6),(17.4,-2.6),(17.3,-2.5),(16.8,-2.5),(16.31,-3)],layer='inner2'))
add('MOTION_DIR',dict(points=[(2.5582,-6.5024),(2.05,-6.5),(1.5,-7.05),(1.45,-7.05),(1.4,-7.1),(1.35,-7.1),(1.3,-7.15),(.9,-7.15),(.5,-7.55),(.45,-7.55),(.4,-7.6),(-2.55,-7.6),(-2.7,-7.45),(-3.45,-7.45)],layer='inner2',via=True))
add('MOTION_DIR',dict(points=[(-3.45,-7.45),(-3.45,-7.65),(-3.9,-8.1),(-3.9,-8.15),(-4,-8.25),(-4,-8.65),(-3.95,-8.7),(-3.95,-8.75),(-3.65,-9.05),(-3.65,-9.2)],layer='inner1',via=True))
add('MOTION_DIR',dict(points=[(-3.65,-9.2),(-3.85,-9.2),(-4.45,-9.8),(-4.5,-9.8),(-4.55,-9.85),(-6.4,-9.85),(-6.55,-10),(-7.35,-10),(-9.75,-7.6)],layer='inner2',via=True))
add('MOTION_DIR',dict(points=[(-9.75,-7.6),(-9.75,-6.55),(-10,-6.3),(-10,-6.25),(-10.05,-6.2),(-10.05,-5.85),(-10,-5.8),(-10,-5.75),(-9.8,-5.55),(-9.8,-2.85),(-9.75,-2.8),(-9.75,-2.75),(-9.65,-2.65),(-9.65,-1.8),(-9.6,-1.75),(-9.6,-1.65),(-9.55,-1.6),(-9.55,-1.55),(-9.25,-1.25),(-9.25,-.55)],via=True))
add('MOTION_DIR',dict(points=[(-9.25,-.55),(-9.25,-.4),(-9.5,-.15),(-9.5,-.1),(-9.6,0),(-9.6,.1),(-9.65,.15),(-9.65,2.85),(-10.2,3.4),(-10.2,3.45),(-10.25,3.5),(-10.25,3.9),(-10.15,4),(-10.15,4.05),(-10.1,4.05),(-10.05,4.1),(-10,4.1),(-9.95,4.15),(-5.6,4.15),(-5.2,4.55),(2.6,4.55),(2.65,4.6),(4.15,4.6),(5.55,6),(5.65,6),(5.7,6.05),(5.95,6.05),(6.25,6.35)],layer='inner2',via=True))
add('MOTION_DIR',dict(points=[(6.25,6.35),(6.35,6.35),(7.05,7.05),(7.05,14.2),(6.6,14.65),(6.6,15),(6.45,15.15)],layer='inner1',via=True))
add('MOTION_DIR',dict(points=[(6.45,15.15),(6.8,15.15),(7,15.35),(7.05,15.35),(7.1,15.4),(7.45,15.4),(7.5,15.35),(7.55,15.35),(7.85,15.05),(11.55,15.05),(11.6,15),(11.7,15),(11.8,14.9),(11.85,14.9),(13.95,12.8),(18.75,12.8),(19.1,13.15),(19.15,13.15),(19.2,13.2),(19.25,13.2),(19.3,13.25),(19.45,13.25),(20.7,14.5)],layer='bottom',via=True))
add('MOTION_DIR',dict(points=[(20.7,14.5),(20.7,14.3),(20.75,14.25),(20.75,-2.9),(20.8,-2.95),(20.8,-3.2),(20.75,-3.25),(20.75,-3.3),(20.7,-3.35),(20.7,-3.4),(20.65,-3.45),(20.6,-3.45),(20.55,-3.5),(20.1,-3.5),(18.9,-2.3),(18.9,-1.9),(18.85,-1.85),(18.85,-1.8),(17.25,-.2),(17.25,-.15),(17.2,-.1)],layer='inner2'))
add('STATUS_LED_DECOUPLE',dict(points=[(-14.49,-20),(-14.49,-20.6),(-18,-20.6),(-18,-19.5),(-18.915035,-18.949963)],layer='bottom',width=.2))

Path('routing/manual-closure.json').write_text(json.dumps(out,indent=2)+'\n')