tool: Light panel #9
12
nhf/build.py
12
nhf/build.py
|
@ -90,7 +90,7 @@ class Target:
|
|||
x = (
|
||||
Cq.Workplane()
|
||||
.add(x._faces)
|
||||
.add(x._wires)
|
||||
.add(x.wires)
|
||||
.add(x._edges)
|
||||
)
|
||||
assert isinstance(x, Cq.Workplane)
|
||||
|
@ -214,7 +214,7 @@ class Submodel:
|
|||
def write_to(self, obj, path: str):
|
||||
x = self._method(obj)
|
||||
assert isinstance(x, Model), f"Unexpected type: {type(x)}"
|
||||
x.build_all(path)
|
||||
x.build_all(path, prefix=False)
|
||||
|
||||
@classmethod
|
||||
def methods(cls, subject):
|
||||
|
@ -271,11 +271,17 @@ class Model:
|
|||
total += 1
|
||||
return total
|
||||
|
||||
def build_all(self, output_dir: Union[Path, str] = "build", verbose=1):
|
||||
def build_all(
|
||||
self,
|
||||
output_dir: Union[Path, str] = "build",
|
||||
prefix: bool = True,
|
||||
verbose=1):
|
||||
"""
|
||||
Build all targets in this model and write the results to file
|
||||
"""
|
||||
output_dir = Path(output_dir)
|
||||
if prefix:
|
||||
output_dir = output_dir / self.name
|
||||
targets = Target.methods(self)
|
||||
for t in targets.values():
|
||||
file_name = t.file_name
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
from dataclasses import dataclass
|
||||
import cadquery as Cq
|
||||
from nhf import Material, Role
|
||||
from nhf.build import Model, target, assembly, TargetKind, submodel
|
||||
from nhf.parts.box import MountingBox, Hole
|
||||
from nhf.parts.electronics import ArduinoUnoR3
|
||||
import nhf.utils
|
||||
|
||||
@dataclass
|
||||
class LightPanel(Model):
|
||||
|
||||
# Dimensions of the base panel
|
||||
length: float = 300.0
|
||||
width: float = 200.0
|
||||
|
||||
grid_height: float = 30.0
|
||||
grid_top_height: float = 5.0
|
||||
# Distance from grid to edge
|
||||
grid_margin: float = 20.0
|
||||
# Number of holes in each row of the grid
|
||||
grid_holes: int = 9
|
||||
grid_layers: int = 6
|
||||
grid_hole_width: float = 15.0
|
||||
|
||||
base_thickness: float = 25.4/16
|
||||
grid_thickness: float = 25.4/4
|
||||
base_material: Material = Material.WOOD_BIRCH
|
||||
grid_material: Material = Material.ACRYLIC_TRANSPARENT
|
||||
|
||||
controller: ArduinoUnoR3 = ArduinoUnoR3()
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.grid_holes >= 2
|
||||
super().__init__(name="light-panel")
|
||||
|
||||
@target(name="grid", kind=TargetKind.DXF)
|
||||
def grid_profile(self):
|
||||
w = self.length - self.grid_margin * 2
|
||||
h = self.grid_height + self.grid_top_height
|
||||
|
||||
# The width of one hole (w0) satisfies
|
||||
# n * w0 + (n+1) t = w
|
||||
# where t is the thickness of the edge
|
||||
n = self.grid_holes
|
||||
w0 = self.grid_hole_width
|
||||
t = (w - n * w0) / (n + 1)
|
||||
# The spacing is such that the first and last holes are a distance `margin`
|
||||
# away from the edges, so it satisfies
|
||||
# t + w0/2 + (n-1) * s + w0/2 + t = w
|
||||
step = (w - t*2 - w0) / (n - 1)
|
||||
return (
|
||||
Cq.Sketch()
|
||||
.push([(0, h/2)])
|
||||
.rect(w, h)
|
||||
.push([
|
||||
(i * step + t + w0/2 - w/2, self.grid_height/2)
|
||||
for i in range(0, n)
|
||||
])
|
||||
.rect(w0, self.grid_height, mode='s')
|
||||
)
|
||||
|
||||
def grid(self) -> Cq.Workplane:
|
||||
return (
|
||||
Cq.Workplane('XY')
|
||||
.placeSketch(self.grid_profile())
|
||||
.extrude(self.grid_thickness)
|
||||
)
|
||||
|
||||
@submodel(name="base")
|
||||
def base(self) -> MountingBox:
|
||||
xshift = self.length / 2 - self.controller.length - self.grid_margin / 2
|
||||
yshift = self.grid_margin / 2
|
||||
holes = [
|
||||
Hole(
|
||||
x=x + xshift, y=y + yshift,
|
||||
diam=self.controller.hole_diam,
|
||||
tag=f"controller_conn{i}",
|
||||
)
|
||||
for i, (x, y) in enumerate(self.controller.holes)
|
||||
]
|
||||
return MountingBox(
|
||||
holes=holes,
|
||||
hole_diam=self.controller.hole_diam,
|
||||
length=self.length,
|
||||
width=self.width,
|
||||
centred=(True, False),
|
||||
thickness=self.base_thickness,
|
||||
)
|
||||
|
||||
def assembly(self) -> Cq.Assembly:
|
||||
assembly = (
|
||||
Cq.Assembly()
|
||||
.addS(
|
||||
self.base().generate(),
|
||||
name="base",
|
||||
role=Role.STRUCTURE,
|
||||
material=self.base_material,
|
||||
)
|
||||
)
|
||||
# Grid thickness t is fixed, so the spacing of the grid satisfies
|
||||
# margin + t + (n-1) * spacing + margin = width
|
||||
spacing = (self.width - 2 * self.grid_margin - self.grid_thickness) / (self.grid_layers - 1)
|
||||
shift = self.grid_margin + self.grid_thickness / 2
|
||||
for i in range(self.grid_layers):
|
||||
assembly = assembly.addS(
|
||||
self.grid(),
|
||||
name=f"grid_{i}",
|
||||
role=Role.STRUCTURE,
|
||||
material=self.grid_material,
|
||||
loc=Cq.Location(0, spacing * i + shift, self.base_thickness, 90, 0, 0),
|
||||
)
|
||||
return assembly
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
p = LightPanel()
|
||||
if len(sys.argv) == 1:
|
||||
p.build_all()
|
||||
sys.exit(0)
|
Loading…
Reference in New Issue