from dataclasses import dataclass, field from typing import Tuple import cadquery as Cq from nhf import Item, Role from nhf.parts.box import Hole, MountingBox import nhf.utils @dataclass(frozen=True) class ArduinoUnoR3(Item): # From datasheet mass: float = 25.0 length: float = 68.6 width: float = 53.4 # with clearance base_height: float = 5.0 # aesthetic only for illustrating clearance total_height: float = 50.0 roof_height: float = 20.0 # This is labeled in mirrored coordinates from top down (i.e. unmirrored from bottom up) holes: list[Tuple[float, float]] = field(default_factory=lambda: [ (15.24, 2.54), (13.74, 50.80), # x coordinate not labeled on schematic (66.04, 17.78), (66.04, 45.72), ]) hole_diam: float = 3.0 @property def name(self) -> str: return "Arduino Uno R3" @property def role(self) -> Role: return Role.ELECTRONIC def generate(self) -> Cq.Assembly: sketch = ( Cq.Sketch() .polygon([ (0,0), (self.length, 0), (self.length, self.width), (0,self.width) ]) .push([(x, self.width - y) for x,y in self.holes]) .circle(self.hole_diam / 2, mode='s') ) # pillar thickness t = 3.0 pillar_height = self.total_height - self.base_height pillar = Cq.Solid.makeBox( t, t, pillar_height ) roof = Cq.Solid.makeBox( self.length, self.width, t ) result = ( Cq.Workplane('XY') .placeSketch(sketch) .extrude(self.base_height) .union(pillar.located(Cq.Location((0, 0, self.base_height)))) .union(pillar.located(Cq.Location((self.length - t, 0, self.base_height)))) .union(pillar.located(Cq.Location((self.length - t, self.width - t, self.base_height)))) .union(pillar.located(Cq.Location((0, self.width - t, self.base_height)))) .union(roof.located(Cq.Location((0, 0, self.total_height - t)))) ) plane = result.copyWorkplane(Cq.Workplane('XY')) for i, (x, y) in enumerate(self.holes): plane.moveTo(x, self.width - y).tagPlane(f"conn{i}", direction='-Z') return result