gokul/macro-six-usbc

USB-powered ATmega32U4 controller board with protected/switched 5 V power, six tactile keys, rotary encoder, reset/boot/ISP interfaces, power LED, and six daisy-chained SK6812 RGB LEDs driven through MOSFETs.

Version
0.1.6
License
MIT
Stars
0

enclosure/check-appearance.py

"""Check the styled references against the existing plate and supplier CAD."""
from pathlib import Path
import hashlib
import json
import cadquery as cq
from appearance import make_appearance

ROOT=Path(__file__).resolve().parents[1]
OUT=ROOT/'enclosure/exports'
j=json.loads((ROOT/'outputs/release/board.circuit.json').read_text())
src={e['source_component_id']:e['name'] for e in j if e['type']=='source_component'}
cad={src[e['source_component_id']]:e for e in j if e['type']=='cad_component'}
keys=[(cad[f'SW{i}']['position']['x'],cad[f'SW{i}']['position']['y']) for i in range(1,7)]
parts=make_appearance(keys,8.6)
plate=cq.importers.importStep(str(OUT/'open-plate.step'))
base=cq.importers.importStep(str(OUT/'bottom.step'))

def supplier(name,filename):
    e=cad[name];o=e['model_origin_position']
    return (cq.importers.importStep(str(ROOT/'work/enclosure-models'/filename))
            .translate(tuple(-o.get(k,0) for k in ['x','y','z']))
            .rotate((0,0,0),(0,0,1),e['rotation'].get('z',0))
            .translate((e['position']['x'],e['position']['y'],8.6)))

checks=[]
for part in parts:
    solid=part['solid']
    assert solid.val().isValid(),part['name']
    reference=supplier('SW'+part['name'].split('-')[2],'SW6.step') if part['asset']=='keycaps-reference' else supplier('ENC1','ENC1.step')
    volume=solid.intersect(reference).val().Volume()
    assert volume<1e-5,(part['name'],'supplier interference',volume)
    checks.append({'part':part['name'],'supplier_intersection_mm3':round(volume,7)})
for i,(x,y) in enumerate(keys,1):
    # The entire 4 mm travel envelope must clear the existing plate and base.
    sweep=cq.Workplane('XY').box(18.5,18.5,15,centered=(True,True,False)).translate((x,y,15.1))
    for fixed in [plate,base]:assert sweep.intersect(fixed).val().Volume()<1e-5
for part in parts:
    if part['asset']!='knob-reference':continue
    for fixed in [plate,base]:assert part['solid'].intersect(fixed).val().Volume()<1e-5
for asset in ['keycaps-reference','knob-reference']:
    solids=[s for p in parts if p['asset']==asset for s in p['solid'].solids().vals()]
    cq.exporters.export(cq.Compound.makeCompound(solids),str(OUT/(asset+'.step')))
report={'supplier_checks':checks,'keycap_travel_mm':4,'travel_clear_of_plate_and_base':True,
        'keycap_width_mm':18.5,'knob_diameter_mm':18,'knob_axis_xy_mm':[43,.2499873],
        'physical_fit_verified':False,'references_only':True,
        'pcb_sha256':hashlib.sha256((ROOT/'outputs/release/board.circuit.json').read_bytes()).hexdigest()}
(OUT/'appearance-checks.json').write_text(json.dumps(report,indent=2)+'\n')
print('Styled keycaps and knob: supplier CAD, plate and travel checks passed',flush=True)