Cosplay/nhf/parts/electronics.py

136 lines
4.3 KiB
Python
Raw Normal View History

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,
)
)