265 lines
7.6 KiB
Python
265 lines
7.6 KiB
Python
from nhf.build import Model, TargetKind, target, assembly, submodel
|
|
from nhf.materials import Role, Material
|
|
import nhf.utils
|
|
from nhf.parts.fasteners import FlatHeadBolt, HexNut, Washer
|
|
from nhf.parts.electronics import ArduinoUnoR3, BatteryBox18650
|
|
|
|
from typing import Optional, Union
|
|
import math
|
|
from dataclasses import dataclass, field
|
|
import cadquery as Cq
|
|
|
|
NUT_COMMON = HexNut(
|
|
# FIXME: weigh
|
|
mass=0.0,
|
|
diam_thread=6.0,
|
|
pitch=1.0,
|
|
thickness=5.0,
|
|
width=9.89,
|
|
)
|
|
BOLT_COMMON = FlatHeadBolt(
|
|
# FIXME: weigh
|
|
mass=0.0,
|
|
diam_head=12.8,
|
|
height_head=2.8,
|
|
diam_thread=6.0,
|
|
height_thread=30.0,
|
|
pitch=1.0,
|
|
)
|
|
|
|
@dataclass
|
|
class Shimenawa(Model):
|
|
"""
|
|
The ring
|
|
"""
|
|
|
|
diam_inner: float = 43.0
|
|
diam_outer: float = 43.0 + 9 * 2
|
|
|
|
diam_hole_outer: float = 8.0
|
|
hole_ext: float = 2.0
|
|
hole_z: float = 15.0
|
|
|
|
pipe_fitting_angle_span: float = 6.0
|
|
|
|
pipe_joint_length: float = 120.0
|
|
pipe_joint_outer_thickness: float = 5.0
|
|
pipe_joint_inner_thickness: float = 4.0
|
|
|
|
pipe_joint_inner_angle_span: float = 120.0
|
|
pipe_joint_taper: float = 5.0
|
|
pipe_joint_taper_length: float = 10.0
|
|
|
|
ear_dr: float = 6.0
|
|
ear_hole_diam: float = 10.0
|
|
ear_radius: float = 15.0
|
|
ear_thickness: float = 10.0
|
|
|
|
main_circumference: float = 3600.0
|
|
|
|
material_fitting: Material = Material.PLASTIC_PLA
|
|
|
|
def __post_init__(self):
|
|
assert self.diam_inner < self.diam_outer
|
|
|
|
@property
|
|
def main_radius(self) -> float:
|
|
return self.main_circumference / (2 * math.pi)
|
|
|
|
@target(name="pipe-fitting-curved")
|
|
def pipe_fitting_curved(self) -> Cq.Workplane:
|
|
r_minor = self.diam_outer/2 + self.pipe_joint_outer_thickness
|
|
a1 = self.pipe_fitting_angle_span
|
|
outer = Cq.Solid.makeTorus(
|
|
radius1=self.main_radius,
|
|
radius2=r_minor,
|
|
)
|
|
inner = Cq.Solid.makeTorus(
|
|
radius1=self.main_radius,
|
|
radius2=self.diam_outer/2,
|
|
)
|
|
angle_intersector = Cq.Solid.makeCylinder(
|
|
radius=self.main_radius + r_minor,
|
|
height=r_minor*2,
|
|
angleDegrees=a1,
|
|
pnt=(0,0,-r_minor)
|
|
).rotate((0,0,0),(0,0,1),-a1/2)
|
|
result = (outer - inner) * angle_intersector
|
|
|
|
ear_outer = Cq.Solid.makeCylinder(
|
|
radius=self.ear_radius,
|
|
height=self.ear_thickness,
|
|
pnt=(0,-self.ear_thickness/2,0),
|
|
dir=(0,1,0),
|
|
)
|
|
ear_hole = Cq.Solid.makeCylinder(
|
|
radius=self.ear_hole_diam/2,
|
|
height=self.ear_thickness,
|
|
pnt=(-self.ear_dr,-self.ear_thickness/2,0),
|
|
dir=(0,1,0),
|
|
)
|
|
ear = (ear_outer - ear_hole).moved(self.main_radius - r_minor, 0, 0)
|
|
result += ear - inner
|
|
return result
|
|
@target(name="pipe-joint-outer")
|
|
def pipe_joint_outer(self) -> Cq.Workplane:
|
|
"""
|
|
Used to joint two pipes together (outside)
|
|
"""
|
|
r1 = self.diam_outer / 2 + self.pipe_joint_outer_thickness
|
|
h = self.pipe_joint_length
|
|
result = (
|
|
Cq.Workplane()
|
|
.cylinder(
|
|
radius=r1,
|
|
height=self.pipe_joint_length,
|
|
)
|
|
)
|
|
cut_interior = Cq.Solid.makeCylinder(
|
|
radius=self.diam_outer/2,
|
|
height=h,
|
|
pnt=(0, 0, -h/2)
|
|
)
|
|
rh = r1 + self.hole_ext
|
|
add_hole = Cq.Solid.makeCylinder(
|
|
radius=self.diam_hole_outer/2,
|
|
height=rh*2,
|
|
pnt=(-rh, 0, 0),
|
|
dir=(1, 0, 0),
|
|
)
|
|
cut_hole = Cq.Solid.makeCylinder(
|
|
radius=BOLT_COMMON.diam_thread/2,
|
|
height=rh*2,
|
|
pnt=(-rh, 0, 0),
|
|
dir=(1, 0, 0),
|
|
)
|
|
z = self.hole_z
|
|
result = (
|
|
result
|
|
+ add_hole.moved(0, 0, -z)
|
|
+ add_hole.moved(0, 0, z)
|
|
- cut_hole.moved(0, 0, -z)
|
|
- cut_hole.moved(0, 0, z)
|
|
- cut_interior
|
|
)
|
|
ear_outer = Cq.Solid.makeCylinder(
|
|
radius=self.ear_radius,
|
|
height=self.ear_thickness,
|
|
pnt=(0, r1, -self.ear_thickness/2),
|
|
)
|
|
ear_hole = Cq.Solid.makeCylinder(
|
|
radius=self.ear_hole_diam/2,
|
|
height=self.ear_thickness,
|
|
pnt=(0,r1+self.ear_dr,-self.ear_thickness/2),
|
|
)
|
|
ear = ear_outer - ear_hole - cut_interior
|
|
return result + ear
|
|
|
|
@target(name="pipe-joint-inner")
|
|
def pipe_joint_inner(self) -> Cq.Workplane:
|
|
"""
|
|
Used to joint two pipes together (inside)
|
|
"""
|
|
r1 = self.diam_inner / 2
|
|
r2 = r1 - self.pipe_joint_taper
|
|
r3 = r2 - self.pipe_joint_inner_thickness
|
|
h = self.pipe_joint_length
|
|
h0 = h - self.pipe_joint_taper_length*2
|
|
core = Cq.Solid.makeCylinder(
|
|
radius=r2,
|
|
height=h0/2,
|
|
)
|
|
centre_cut = Cq.Solid.makeCylinder(
|
|
radius=r3,
|
|
height=h0/2,
|
|
)
|
|
taper = Cq.Solid.makeCone(
|
|
radius1=r2,
|
|
radius2=r1,
|
|
height=(h - h0) / 2,
|
|
pnt=(0, 0, h0/2),
|
|
)
|
|
centre_cut_taper = Cq.Solid.makeCone(
|
|
radius1=r3,
|
|
radius2=r3 + self.pipe_joint_taper,
|
|
height=(h - h0) / 2,
|
|
pnt=(0, 0, h0/2),
|
|
)
|
|
angle_intersector = Cq.Solid.makeCylinder(
|
|
radius=r1,
|
|
height=h,
|
|
angleDegrees=self.pipe_joint_inner_angle_span
|
|
).rotate((0,0,0), (0,0,1), -self.pipe_joint_inner_angle_span/2)
|
|
result = (taper + core - centre_cut - centre_cut_taper) * angle_intersector
|
|
|
|
result += result.mirror("XY")
|
|
|
|
add_hole = Cq.Solid.makeCylinder(
|
|
radius=self.diam_hole_outer/2,
|
|
height=self.hole_ext,
|
|
pnt=(r3, 0, 0),
|
|
dir=(-1, 0, 0),
|
|
)
|
|
cut_hole = Cq.Solid.makeCylinder(
|
|
radius=BOLT_COMMON.diam_thread/2,
|
|
height=r1,
|
|
pnt=(0, 0, 0),
|
|
dir=(r1, 0, 0),
|
|
)
|
|
z = self.hole_z
|
|
# avoid collisions
|
|
nut_x = r3 - self.hole_ext - NUT_COMMON.thickness
|
|
nut = NUT_COMMON.generate().val().rotate((0,0,0),(0,1,0),90)
|
|
result = (
|
|
result
|
|
+ add_hole.moved(0, 0, z)
|
|
+ add_hole.moved(0, 0, -z)
|
|
- cut_hole.moved(0, 0, z)
|
|
- cut_hole.moved(0, 0, -z)
|
|
- nut.moved(nut_x, 0, z)
|
|
- nut.moved(nut_x, 0, -z)
|
|
)
|
|
return result
|
|
@assembly()
|
|
def assembly_pipe_joint(self) -> Cq.Assembly:
|
|
a = (
|
|
Cq.Assembly()
|
|
.addS(
|
|
self.pipe_joint_outer(),
|
|
name="joint_outer",
|
|
material=self.material_fitting,
|
|
role=Role.STRUCTURE,
|
|
)
|
|
.addS(
|
|
self.pipe_joint_inner(),
|
|
name="joint_inner1",
|
|
material=self.material_fitting,
|
|
role=Role.STRUCTURE,
|
|
)
|
|
.addS(
|
|
self.pipe_joint_inner(),
|
|
name="joint_inner2",
|
|
material=self.material_fitting,
|
|
role=Role.STRUCTURE,
|
|
loc=Cq.Location.rot2d(180),
|
|
)
|
|
)
|
|
return a
|
|
|
|
@assembly()
|
|
def assembly(self) -> Cq.Assembly:
|
|
a = (
|
|
Cq.Assembly()
|
|
.addS(
|
|
self.pipe_fitting_curved(),
|
|
name="fitting1",
|
|
material=self.material_fitting,
|
|
role=Role.STRUCTURE,
|
|
)
|
|
.add(
|
|
self.assembly_pipe_joint(),
|
|
name="pipe_joint",
|
|
)
|
|
)
|
|
return a
|