Cosplay/nhf/parts/electronics.py

136 lines
4.3 KiB
Python

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),
(15.24 - 1.270, 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
@dataclass(frozen=True)
class BatteryBox18650(Item):
"""
A number of 18650 batteries in series
"""
mass: float = 17.4 + 68.80 * 3
length: float = 75.70
width_base: float = 61.46 - 18.48 - 20.18 * 2
battery_dist: float = 20.18
height: float = 19.66
# space from bottom to battery begin
thickness: float = 1.66
battery_diam: float = 18.48
battery_height: float = 68.80
n_batteries: int = 3
def __post_init__(self):
assert 2 * self.thickness < min(self.length, self.height)
@property
def name(self) -> str:
return f"BatteryBox 18650*{self.n_batteries}"
@property
def role(self) -> Role:
return Role.ELECTRONIC
def generate(self) -> Cq.Workplane:
width = self.width_base + self.battery_dist * (self.n_batteries - 1) + self.battery_diam
return (
Cq.Workplane('XY')
.box(
length=self.length,
width=width,
height=self.height,
centered=(True, True, False),
)
.copyWorkplane(Cq.Workplane('XY', origin=(0, 0, self.thickness)))
.box(
length=self.length - self.thickness*2,
width=width - self.thickness*2,
height=self.height - self.thickness,
centered=(True, True, False),
combine='cut',
)
.copyWorkplane(Cq.Workplane('XY', origin=(-self.battery_height/2, 0, self.thickness + self.battery_diam/2)))
.rarray(
xSpacing=1,
ySpacing=self.battery_dist,
xCount=1,
yCount=self.n_batteries,
center=True,
)
.cylinder(
radius=self.battery_diam/2,
height=self.battery_height,
direct=(1, 0, 0),
centered=(True, True, False),
combine=True,
)
)