cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
4 changed files with 66 additions and 5 deletions
Showing only changes of commit 2ccb4160db - Show all commits

View File

@ -33,12 +33,20 @@ class Hole:
y: float = 0.0 y: float = 0.0
diam: Optional[float] = None diam: Optional[float] = None
tag: Optional[str] = None tag: Optional[str] = None
face: Optional[Cq.Face] = None
@property @property
def rev_tag(self) -> str: def rev_tag(self) -> str:
assert self.tag is not None assert self.tag is not None
return self.tag + "_rev" return self.tag + "_rev"
def cutting_geometry(self, default_diam: Optional[float]=None) -> Cq.Face:
if self.face is not None:
return self.face
diam = self.diam if self.diam is not None else default_diam
assert diam is not None
return Cq.Face.makeFromWires(Cq.Wire.makeCircle(diam/2, Cq.Vector(), Cq.Vector(0,0,1)))
@dataclass @dataclass
class MountingBox(Model): class MountingBox(Model):
""" """
@ -84,8 +92,8 @@ class MountingBox(Model):
.rect(self.length, self.width) .rect(self.length, self.width)
) )
for hole in self.holes: for hole in self.holes:
diam = hole.diam if hole.diam else self.hole_diam face = hole.cutting_geometry(default_diam=self.hole_diam)
result.push([(hole.x, hole.y)]).circle(diam / 2, mode='s') result.push([(hole.x, hole.y)]).each(lambda l:face.moved(l), mode='s')
if self.profile_callback: if self.profile_callback:
result = self.profile_callback(result) result = self.profile_callback(result)
return result return result

View File

@ -103,12 +103,15 @@ class HexNut(Item):
def role(self) -> Role: def role(self) -> Role:
return Role.CONNECTION return Role.CONNECTION
@property
def radius(self) -> float:
return self.width / math.sqrt(3)
def generate(self) -> Cq.Workplane: def generate(self) -> Cq.Workplane:
r = self.width / math.sqrt(3)
result = ( result = (
Cq.Workplane("XY") Cq.Workplane("XY")
.sketch() .sketch()
.regularPolygon(r=r, n=6) .regularPolygon(r=self.radius, n=6)
.circle(r=self.diam_thread/2, mode='s') .circle(r=self.diam_thread/2, mode='s')
.finalize() .finalize()
.extrude(self.thickness) .extrude(self.thickness)
@ -117,3 +120,10 @@ class HexNut(Item):
result.faces(">Z").tag("top") result.faces(">Z").tag("top")
result.copyWorkplane(Cq.Workplane('XY')).tagPlane("dirX", direction="+X") result.copyWorkplane(Cq.Workplane('XY')).tagPlane("dirX", direction="+X")
return result return result
def cutting_face(self) -> Cq.Face:
return (
Cq.Sketch()
.regularPolygon(r=self.radius, n=6)
._faces
)

View File

@ -335,6 +335,15 @@ LINEAR_ACTUATOR_BRACKET = MountingBracket()
BATTERY_BOX = BatteryBox18650() BATTERY_BOX = BatteryBox18650()
# Acrylic hex nut
ELECTRONIC_MOUNT_HEXNUT = HexNut(
mass=0.8,
diam_thread=4,
pitch=0.7,
thickness=3.57,
width=6.81,
)
@dataclass(kw_only=True) @dataclass(kw_only=True)
class Flexor: class Flexor:
""" """

View File

@ -18,7 +18,8 @@ from nhf.touhou.houjuu_nue.electronics import (
LINEAR_ACTUATOR_10, LINEAR_ACTUATOR_10,
LINEAR_ACTUATOR_21, LINEAR_ACTUATOR_21,
LINEAR_ACTUATOR_50, LINEAR_ACTUATOR_50,
ElectronicBoard ElectronicBoard,
ELECTRONIC_MOUNT_HEXNUT,
) )
import nhf.utils import nhf.utils
@ -327,6 +328,9 @@ class WingProfile(Model):
) )
@submodel(name="spacer-s0-electronic") @submodel(name="spacer-s0-electronic")
def spacer_s0_electronic_mount(self) -> MountingBox: def spacer_s0_electronic_mount(self) -> MountingBox:
"""
This one has circular holes for the screws
"""
return MountingBox( return MountingBox(
holes=self.electronic_board.mount_holes, holes=self.electronic_board.mount_holes,
hole_diam=self.electronic_board.mount_hole_diam, hole_diam=self.electronic_board.mount_hole_diam,
@ -337,6 +341,26 @@ class WingProfile(Model):
flip_y=False,#self.flip, flip_y=False,#self.flip,
generate_reverse_tags=True, generate_reverse_tags=True,
) )
@submodel(name="spacer-s0-electronic2")
def spacer_s0_electronic_mount2(self) -> MountingBox:
"""
This one has hexagonal holes
"""
face = ELECTRONIC_MOUNT_HEXNUT.cutting_face()
holes = [
Hole(x=h.x, y=h.y, face=face, tag=h.tag)
for h in self.electronic_board.mount_holes
]
return MountingBox(
holes=holes,
hole_diam=self.electronic_board.mount_hole_diam,
length=self.root_height,
width=self.electronic_board.width,
centred=(True, True),
thickness=self.spacer_thickness,
flip_y=False,#self.flip,
generate_reverse_tags=True,
)
@submodel(name="spacer-s0-shoulder-act") @submodel(name="spacer-s0-shoulder-act")
def spacer_s0_shoulder_act(self) -> MountingBox: def spacer_s0_shoulder_act(self) -> MountingBox:
dx = self.shoulder_joint.draft_height dx = self.shoulder_joint.draft_height
@ -424,6 +448,16 @@ class WingProfile(Model):
.constrain(f"{tag}?{top_tag}", f"top?{tag}", "Plane") .constrain(f"{tag}?{top_tag}", f"top?{tag}", "Plane")
.constrain(f"{tag}?dir", f"top?{tag}_dir", "Axis") .constrain(f"{tag}?dir", f"top?{tag}_dir", "Axis")
) )
result.addS(
self.spacer_s0_electronic_mount2().generate(),
name="electronic_mount2",
role=Role.STRUCTURE | Role.CONNECTION,
material=self.mat_bracket)
for hole in self.electronic_board.mount_holes:
result.constrain(
f"electronic_mount?{hole.tag}",
f"electronic_mount2?{hole.tag}_rev",
"Plane")
if not ignore_electronics: if not ignore_electronics:
result.add(self.electronic_board.assembly(), name="electronic_board") result.add(self.electronic_board.assembly(), name="electronic_board")
for hole in self.electronic_board.mount_holes: for hole in self.electronic_board.mount_holes: