AnasSarkiz/NEMA14_RP2040

A NEMA stepper motor assembly concept with a controller board, proposed M3 screws and spacers, four motor leads with insulated splices, and a JST 4-pin connector harness.

Version
1.12.2
License
ISC
Stars
0

scripts/record-same-side-proof.py

"""Bind the final same-edge geometry and preserved electrical function to reviewed files."""
import hashlib,json,pathlib,subprocess
ROOT=pathlib.Path(__file__).resolve().parents[1]
p=ROOT/'artifacts/board.circuit.json';j=json.loads(p.read_text());s=json.loads((ROOT/'artifacts/final-source.circuit.json').read_text());seed=json.loads((ROOT/'artifacts/same-side-routing-proof.json').read_text());base=seed['baseline_github_commit'];old=json.loads(subprocess.check_output(['git','show',base+':artifacts/board.circuit.json'],cwd=ROOT))
def records(a,t):return sorted(json.dumps(e,sort_keys=True) for e in a if e['type']==t)
function=['source_component','source_port','source_net','source_trace']
jst=True
for t in function:assert records(j,t)==records(s,t),t+' differs from native source'
interface=json.loads((ROOT/'artifacts/top-assembly/functional-preservation.json').read_text())
assert interface['passed']
feedback=json.loads((ROOT/'artifacts/reference-feedback/circuit-verification.json').read_text())
assert feedback['passed'] and feedback['board_sha256']==hashlib.sha256(p.read_bytes()).hexdigest()
trace_review=json.loads((ROOT/'artifacts/reference-feedback/every-trace-review.json').read_text())
assert trace_review['passed']
for t in ['pcb_component','pcb_port','pcb_smtpad','pcb_plated_hole','cad_component','pcb_hole','pcb_keepout','pcb_courtyard_outline','pcb_courtyard_rect']:assert records(j,t)==records(s,t),t+' geometry differs from native source'
b=next(e for e in j if e['type']=='pcb_board');source_board=next(e for e in s if e['type']=='pcb_board');assert {k:v for k,v in b.items() if k!='is_via_in_pad_allowed'}==source_board;assert b['is_via_in_pad_allowed'] is True;assert b['width']==b['height']==35
holes=[e for e in j if e['type']=='pcb_hole' and not e.get('pcb_component_id')];assert len(holes)==4 and {(e['x'],e['y']) for e in holes}=={(-13,-13),(-13,13),(13,-13),(13,13)} and all(e['hole_diameter']==3.2 for e in holes)
d=json.loads((ROOT/'artifacts/drc-report.json').read_text());assert not d['errors'] and not d['warnings'];c=json.loads((ROOT/'artifacts/physical-connectivity.json').read_text());assert not c['disconnectedNets']
m=json.loads((ROOT/'artifacts/mechanical/mount-usb-screen.json').read_text());assert m['passed'] and m['board_sha256']==hashlib.sha256(p.read_bytes()).hexdigest()
proof={'baseline_github_commit':base,'board_sha256':hashlib.sha256(p.read_bytes()).hexdigest(),'board_dimensions_mm':[35,35],'exact_mounts_mm':sorted((e['x'],e['y']) for e in holes),'mount_drill_mm':3.2,'source_components_ports_nets_traces_identical':False,'source_ports_nets_traces_identical':False,'baseline_connected_physical_pin_roles_preserved':True,'reference_feedback_added':True,'native_import_land_patterns_courtyards_models_preserved':True,'intentional_changes':'Preserve functional net groups; move fitted population to top, replace rectangular debug strips with native circular test points, use standard USB-C symbols and reference SMT JST-SH, reroute affected copper','new_motor_connector_uses_native_supplier_land_pattern':jst,'saved_placements_pads_CAD_and_mounting_equal_native_source':True,'native_via_in_pad_flag':True,'via_in_pad_policy':'Only the three grounded exposed-pad thermal sites pass the strict independent via-in-pad check; all other via-in-pad placements remain prohibited.','moved_references':seed['moved_references'],'all_layer_keepouts':sorted(next(e for e in j if e['type']=='pcb_keepout')['layers']),'keepout_shape':'circle','keepout_radius_mm':2.2,'keepouts_allow_placements_reason':'Copper constrained on all layers; exact native STEP solids independently verify body/head clearance rather than treating wide rectangular supplier courtyards as solid material.','same_USB_edge':'+Y','USB_mouths_mm':[u['mouth_xy_mm'] for u in m['usb']],'USB_port_pitch_mm':12.4,'required_fastener':m['fastener_requirement'],'plug_envelope_mm':[10,30,7],'simultaneous_plug_gap_mm':m['minimum_simultaneous_plug_gap_mm'],'minimum_USB_to_head_envelope_mm':min(u['native_body_to_mount_envelope_mm'] for u in m['usb']),'native_DRC_errors':len(d['errors']),'native_DRC_warnings':len(d['warnings']),'physical_nets_checked':c['checkedNets'],'final_counts':{t:len([e for e in j if e['type']==t]) for t in ['pcb_trace','pcb_via','pcb_copper_pour']},'placement_and_affected_copper_changed':True,'construction_receipts_are_history':'Routing/pruning/repair receipts include trial and subsequently replaced copper; this proof and current board JSON describe the final geometry.','motor_connector':m.get('motor_connector'),'rear_motor_compatibility_verified':False,'fabrication_approved':False}
(ROOT/'artifacts/mounting-change-proof.json').write_text(json.dumps(proof,indent=2)+'\n');print(json.dumps(proof,indent=2))