abse/smartwatch-flex-top-only

Three-panel flex smartwatch with two parallel R3.9 bends, all components flat-top, low-profile JST connector harnesses, split heartbeat optical windows and screw-retained PCB mounting. Modeled 39 × 50.5 × 14.5mm prototype; 100% routing, zero native DRC and shorts. Hardware qualification pending.

Version
0.2.20
License
unset
Stars
0

scripts/audit-pcb-insertion.py

"""Check that the populated PCB and removable cradle can pass the fixed posts."""
from pathlib import Path
import json,numpy as np,trimesh
from mount_mesh_utils import numerical_face_contact
root=Path(__file__).resolve().parent.parent
moving,fixed=trimesh.collision.CollisionManager(),trimesh.collision.CollisionManager()
names=[]
boxes={}
actual_meshes={}
for filename,manager in [('upright-pcb',moving),('pcb-cradle',moving),('motor-support-shim',moving),('relocated-motor',moving),('motor-inline-connector',moving),('case-body',fixed)]:
    scene=trimesh.load(root/f'mechanical/{filename}.glb',force='scene')
    for node in scene.graph.nodes_geometry:
        T,n=scene.graph[node];mesh=scene.geometry[n].copy();mesh.apply_transform(T)
        name=filename+'/'+node;manager.add_object(name,mesh)
        boxes[name]=mesh.bounds.copy()
        actual_meshes[name]=mesh
        if manager is moving:names.append(name)
failures=[]
contact_proofs={}
heights=np.arange(0,16.001,.2)
for z in heights:
    T=trimesh.transformations.translation_matrix([0,0,float(z)])
    for name in names:moving.set_transform(name,T)
    hit,pairs,data=moving.in_collision_other(fixed,return_names=True,return_data=True)
    for c in data:
        pair=sorted(c.names)
        a=boxes[pair[0]].copy();b=boxes[pair[1]].copy()
        if not pair[0].startswith('case-body/'):a[:,2]+=z
        else:b[:,2]+=z
        # FCL reports nonzero depth for some coplanar annular-cap triangles.
        # A separating AABB proves there is no volume intersection, including
        # the intended cradle-seat/post-cap contact at the seated position.
        separated=np.any(np.maximum(a[0]-b[1],b[0]-a[1])>=0)
        if c.depth>.000005 and not separated:
            proof_key=(tuple(pair),float(z))
            if proof_key not in contact_proofs:
                a_mesh=actual_meshes[pair[0]].copy();b_mesh=actual_meshes[pair[1]].copy()
                if not pair[0].startswith('case-body/'):a_mesh.apply_transform(T)
                else:b_mesh.apply_transform(T)
                contact_proofs[proof_key]=numerical_face_contact(a_mesh,b_mesh)
            initial_contact=contact_proofs[proof_key]
            if not initial_contact:failures.append({'heightAboveSeatedMM':float(z),'objects':pair,'penetrationMM':float(c.depth)})
report={'status':'PASS' if not failures else 'FAIL','insertionPositionsChecked':len(heights),
    'travelMM':16,'stepMM':.2,'failures':failures,
    'method':'FCL mesh collision sweep of the complete populated native PCB, cradle, motor support, motor and inline connector through the actual open case body onto the four integral posts. Top bezel, front retainers and screws are absent during insertion. Numerical seated-face contacts require an independent Boolean sliver and 5um surface-distance proof.',
    'scope':'Open-body and post clearance during PCB/cradle insertion; wiring, battery handling, motor installation and display-flex assembly still need prototype verification.'}
(root/'reports/pcb-insertion.json').write_text(json.dumps(report,indent=2)+'\n')
print(json.dumps(report,indent=2));assert report['status']=='PASS'