Geometry of mirror and rotor spacer

This commit is contained in:
Leni Aniva 2025-05-13 14:29:10 -07:00
parent 5b5ccee94e
commit a684996475
Signed by: aniva
GPG Key ID: D5F96287843E8DFB
2 changed files with 224 additions and 68 deletions

View File

@ -1,6 +1,7 @@
from dataclasses import dataclass, field
import cadquery as Cq
from nhf.build import Model, TargetKind, target, assembly, submodel
from nhf.materials import Role, Material
import nhf.touhou.yasaka_kanako.onbashira as MO
import nhf.utils
@ -8,36 +9,178 @@ import nhf.utils
class Mirror(Model):
"""
Kanako's mirror, made of three levels.
The mirror suface is sandwiched between two layers of wood. As such, its
dimensions have to sit in between that of the aperature on the surface, and
the outer walls. The width/height here refers to the outer edge's width and height
"""
width: float = 50.0
height: float = 70.0
height: float = 60.0
wall_thickness: float = 10.0
inner_gap: float = 3.0
outer_gap: float = 3.0
core_thickness: float = 25.4 / 8
casing_thickness: float = 25.4 / 16
flange_r0: float = 5.0
flange_r1: float = 15.0
flange_y1: float = 12.0
flange_y2: float = 25.0
flange_hole_r: float = 8.0
wing_x1: float = 12.0
wing_x2: float = 20.0
wing_r1: float = 6.0
wing_r2: float = 12.0
tail_r0: float = 5.0
tail_r1: float = 10.0
tail_y1: float = 12.0
tail_y2: float = 25.0
# Necklace hole
hole_diam: float = 5.0
material_mirror: Material = Material.ACRYLIC_TRANSPARENT
material_casing: Material = Material.WOOD_BIRCH
@target(name="core", kind=TargetKind.DXF)
def profile_core(self) -> Cq.Sketch:
return Cq.Sketch().ellipse(self.width/2, self.height/2)
rx = self.width/2 - self.outer_gap
ry = self.height/2 - self.outer_gap
return Cq.Sketch().ellipse(rx, ry)
def core(self) -> Cq.Workplane:
return (
Cq.Workplane()
.placeSketch(self.profile_core())
.extrude(self.core_thickness)
)
@target(name="casing-bot", kind=TargetKind.DXF)
def profile_casing(self) -> Cq.Sketch:
def profile_casing_bot(self) -> Cq.Sketch:
"""
Base of the casing with no holes carved out
"""
dx = self.wall_thickness
return (
Cq.Sketch()
.ellipse(self.width/2+dx, self.height/2+dx)
.ellipse(self.width/2, self.height/2)
)
def casing_bot(self) -> Cq.Workplane:
return (
Cq.Workplane()
.placeSketch(self.profile_casing_bot())
.extrude(self.casing_thickness)
)
def profile_wing(self, sign: float=1) -> Cq.Sketch:
xt = self.width / 2 - self.outer_gap
return (
Cq.Sketch()
.polygon([
(sign*xt, self.wing_r1),
(sign*(xt+self.wing_x1), self.wing_r1),
(sign*(xt+self.wing_x1), self.wing_r2),
(sign*(xt+self.wing_x2), self.wing_r2),
(sign*(xt+self.wing_x2), -self.wing_r2),
(sign*(xt+self.wing_x1), -self.wing_r2),
(sign*(xt+self.wing_x1), -self.wing_r1),
(sign*xt, -self.wing_r1),
])
)
@target(name="casing-mid", kind=TargetKind.DXF)
def profile_casing_mid(self) -> Cq.Sketch:
yt = self.height / 2 - self.outer_gap
rx = self.width/2 - self.outer_gap
ry = self.height/2 - self.outer_gap
yh = (self.flange_y1 + self.flange_y2) / 2
flange = (
Cq.Sketch()
.polygon([
(self.flange_r0, yt),
(self.flange_r0, yt + self.flange_y1),
(self.flange_r1, yt + self.flange_y1),
(self.flange_r1, yt + self.flange_y2),
(-self.flange_r1, yt + self.flange_y2),
(-self.flange_r1, yt + self.flange_y1),
(-self.flange_r0, yt + self.flange_y1),
(-self.flange_r0, yt),
])
.push([
(self.flange_hole_r, yt+yh),
(-self.flange_hole_r, yt+yh),
])
.circle(self.hole_diam/2, mode="s")
)
tail = (
Cq.Sketch()
.polygon([
(+self.tail_r0, -yt),
(+self.tail_r0, -yt - self.tail_y1),
(+self.tail_r1, -yt - self.tail_y1),
(+self.tail_r1, -yt - self.tail_y2),
(-self.tail_r1, -yt - self.tail_y2),
(-self.tail_r1, -yt - self.tail_y1),
(-self.tail_r0, -yt - self.tail_y1),
(-self.tail_r0, -yt),
])
)
return (
self.profile_casing_bot()
.ellipse(rx, ry, mode="s")
.boolean(flange, mode="a")
.boolean(tail, mode="a")
.boolean(self.profile_wing(-1), mode="a")
.boolean(self.profile_wing(1), mode="a")
)
def casing_mid(self) -> Cq.Workplane:
return (
Cq.Workplane()
.placeSketch(self.profile_casing_mid())
.extrude(self.core_thickness)
)
@target(name="casing-top", kind=TargetKind.DXF)
def profile_casing_top(self) -> Cq.Sketch:
"""
Base of the casing with no holes carved out
"""
rx = self.width/2 - self.outer_gap - self.inner_gap
ry = self.height/2 - self.outer_gap - self.inner_gap
return (
self.profile_casing()
.ellipse(self.width/2, self.height/2, mode="s")
self.profile_casing_bot()
.ellipse(rx, ry, mode="s")
)
def casing_top(self) -> Cq.Workplane:
return (
Cq.Workplane()
.placeSketch(self.profile_casing_top())
.extrude(self.casing_thickness)
)
@assembly()
def assembly(self) -> Cq.Assembly:
pass
return (
Cq.Assembly()
.addS(
self.core(),
name="core",
material=self.material_mirror,
role=Role.DECORATION,
loc=Cq.Location(0, 0, self.casing_thickness)
)
.addS(
self.casing_bot(),
name="casing_bot",
material=self.material_casing,
role=Role.CASING,
)
.addS(
self.casing_mid(),
name="casing_mid",
material=self.material_casing,
role=Role.CASING,
loc=Cq.Location(0, 0, self.casing_thickness)
)
.addS(
self.casing_top(),
name="casing_top",
material=self.material_casing,
role=Role.CASING,
loc=Cq.Location(0, 0, self.core_thickness + self.casing_thickness)
)
)

View File

@ -54,9 +54,9 @@ class Onbashira(Model):
bearing_disk_thickness: float = 25.4 / 8
rotor_inner_radius: float = 40.0
rotor_bind_bolt_diam: float = 8.0
rotor_bind_radius: float = 85.0
rotor_spacer_outer_diam: float = 15.0
stator_bind_radius: float = 140.0
material_side: Material = Material.WOOD_BIRCH
@ -194,6 +194,74 @@ class Onbashira(Model):
"""
pass
def bearing_ball(self) -> Cq.Solid:
return Cq.Solid.makeSphere(radius=self.bearing_ball_diam/2, angleDegrees1=-90)
@target(name="rotor-spacer")
def rotor_spacer(self) -> Cq.Solid:
outer = Cq.Solid.makeCylinder(
radius=self.rotor_spacer_outer_diam/2,
height=self.bearing_disk_gap,
)
inner = Cq.Solid.makeCylinder(
radius=self.rotor_bind_bolt_diam/2,
height=self.bearing_disk_gap
)
return outer - inner
def assembly_rotor(self) -> Cq.Assembly:
z_lower = -self.bearing_disk_gap/2 - self.bearing_disk_thickness
a = (
Cq.Assembly()
.addS(
self.bearing_stator(),
name="stator1",
material=self.material_bearing,
role=Role.STATOR,
loc=Cq.Location(0, 0, self.bearing_disk_gap/2)
)
.addS(
self.bearing_rotor(),
name="rotor1",
material=self.material_bearing,
role=Role.ROTOR,
loc=Cq.Location(0, 0, self.bearing_disk_gap/2)
)
.addS(
self.bearing_stator(),
name="stator2",
material=self.material_bearing,
role=Role.STATOR,
loc=Cq.Location(0, 0, z_lower)
)
.addS(
self.bearing_rotor(),
name="rotor2",
material=self.material_bearing,
role=Role.ROTOR,
loc=Cq.Location(0, 0, z_lower)
)
.addS(
self.bearing_gasket(),
name="gasket",
material=self.material_bearing,
role=Role.ROTOR,
loc=Cq.Location(0, 0, -self.bearing_disk_thickness/2)
)
)
for i in range(self.n_bearing_balls):
ball = self.bearing_ball()
loc = Cq.Location.rot2d(i * 360/self.n_bearing_balls) * Cq.Location(self.bearing_track_radius, 0, 0)
a = a.addS(
ball,
name=f"bearing_ball{i}",
material=self.material_bearing_ball,
role=Role.BEARING,
loc=loc,
)
return a
def profile_side_panel(
self,
length: float,
@ -394,61 +462,6 @@ class Onbashira(Model):
result.tagAbsolute("holeStatorR", (ri * math.cos(th), ri * math.sin(th), -h/2), direction="-Z")
return result
def bearing_ball(self) -> Cq.Solid:
return Cq.Solid.makeSphere(radius=self.bearing_ball_diam/2, angleDegrees1=-90)
def assembly_rotor(self) -> Cq.Assembly:
z_lower = -self.bearing_disk_gap/2 - self.bearing_disk_thickness
a = (
Cq.Assembly()
.addS(
self.bearing_stator(),
name="stator1",
material=self.material_bearing,
role=Role.STATOR,
loc=Cq.Location(0, 0, self.bearing_disk_gap/2)
)
.addS(
self.bearing_rotor(),
name="rotor1",
material=self.material_bearing,
role=Role.ROTOR,
loc=Cq.Location(0, 0, self.bearing_disk_gap/2)
)
.addS(
self.bearing_stator(),
name="stator2",
material=self.material_bearing,
role=Role.STATOR,
loc=Cq.Location(0, 0, z_lower)
)
.addS(
self.bearing_rotor(),
name="rotor2",
material=self.material_bearing,
role=Role.ROTOR,
loc=Cq.Location(0, 0, z_lower)
)
.addS(
self.bearing_gasket(),
name="gasket",
material=self.material_bearing,
role=Role.ROTOR,
loc=Cq.Location(0, 0, -self.bearing_disk_thickness/2)
)
)
for i in range(self.n_bearing_balls):
ball = self.bearing_ball()
loc = Cq.Location.rot2d(i * 360/self.n_bearing_balls) * Cq.Location(self.bearing_track_radius, 0, 0)
a = a.addS(
ball,
name=f"bearing_ball{i}",
material=self.material_bearing_ball,
role=Role.BEARING,
loc=loc,
)
return a
def assembly_section(self, **kwargs) -> Cq.Assembly:
a = Cq.Assembly()
side = self.side_panel(**kwargs)