cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
3 changed files with 45 additions and 33 deletions
Showing only changes of commit ddeaf1194f - Show all commits

View File

@ -300,6 +300,8 @@ LINEAR_ACTUATOR_10 = LinearActuator(
back_hole_ext=4.5/2, back_hole_ext=4.5/2,
segment1_length=30.0, segment1_length=30.0,
segment2_length=30.0, segment2_length=30.0,
segment1_width=15.0,
segment2_width=21.0,
) )
LINEAR_ACTUATOR_HEX_NUT = HexNut( LINEAR_ACTUATOR_HEX_NUT = HexNut(
mass=0.8, mass=0.8,

View File

@ -882,8 +882,8 @@ class ElbowJoint(Model):
angle_neutral: float = 30.0 angle_neutral: float = 30.0
actuator: LinearActuator actuator: Optional[LinearActuator]
flexor: Flexor = None flexor: Optional[Flexor] = None
# Rotates the entire flexor # Rotates the entire flexor
flexor_offset_angle: float = 0 flexor_offset_angle: float = 0
# Rotates the surface of the mount # Rotates the surface of the mount
@ -893,10 +893,11 @@ class ElbowJoint(Model):
assert self.child_arm_radius > self.disk_joint.radius_housing assert self.child_arm_radius > self.disk_joint.radius_housing
assert self.parent_arm_radius > self.disk_joint.radius_housing assert self.parent_arm_radius > self.disk_joint.radius_housing
self.disk_joint.tongue_length = self.child_arm_radius - self.disk_joint.radius_disk - self.lip_thickness / 2 self.disk_joint.tongue_length = self.child_arm_radius - self.disk_joint.radius_disk - self.lip_thickness / 2
self.flexor = Flexor( if self.actuator:
actuator=self.actuator, self.flexor = Flexor(
motion_span=self.motion_span actuator=self.actuator,
) motion_span=self.motion_span
)
@property @property
def total_thickness(self): def total_thickness(self):
@ -990,8 +991,9 @@ class ElbowJoint(Model):
Cq.Assembly() Cq.Assembly()
.add(self.disk_joint.disk(), name="disk", loc=Cq.Location((0, 0, -dz))) .add(self.disk_joint.disk(), name="disk", loc=Cq.Location((0, 0, -dz)))
.add(self.lip().cut(disk_cut), name="lip", loc=loc_disk.inverse * loc_lip) .add(self.lip().cut(disk_cut), name="lip", loc=loc_disk.inverse * loc_lip)
.add(self.actuator_mount(), name="act", loc=self.actuator_mount_loc(child=True))
) )
if self.flexor:
result.add(self.actuator_mount(), name="act", loc=self.actuator_mount_loc(child=True))
return result return result
@target(name="parent-lower") @target(name="parent-lower")
@ -1040,12 +1042,15 @@ class ElbowJoint(Model):
Cq.Location((0, 0, 0), (0, 1, 0), 90)) Cq.Location((0, 0, 0), (0, 1, 0), 90))
.add(connector, name="connector", .add(connector, name="connector",
loc=loc_net_housing.inverse * axial_offset) loc=loc_net_housing.inverse * axial_offset)
.add(self.actuator_mount(),
name="act", loc=self.actuator_mount_loc(child=False))
#.constrain("housing", "Fixed") #.constrain("housing", "Fixed")
#.constrain("connector", "Fixed") #.constrain("connector", "Fixed")
#.solve() #.solve()
) )
if self.flexor:
result.add(
self.actuator_mount(),
name="act",
loc=self.actuator_mount_loc(child=False))
return result return result
@assembly() @assembly()

View File

@ -51,7 +51,7 @@ class WingProfile(Model):
disk_joint=DiskJoint( disk_joint=DiskJoint(
movement_angle=55, movement_angle=55,
), ),
hole_diam=6.0, hole_diam=4.0,
angle_neutral=15.0, angle_neutral=15.0,
actuator=LINEAR_ACTUATOR_50, actuator=LINEAR_ACTUATOR_50,
flexor_offset_angle=-15, flexor_offset_angle=-15,
@ -65,13 +65,14 @@ class WingProfile(Model):
radius_disk=13.0, radius_disk=13.0,
radius_housing=15.0, radius_housing=15.0,
), ),
hole_pos=[10, 20], hole_pos=[10],
lip_length=50, lip_length=30,
child_arm_radius=23.0, child_arm_radius=23.0,
parent_arm_radius=30.0, parent_arm_radius=30.0,
hole_diam=4.0, hole_diam=4.0,
angle_neutral=-30.0, angle_neutral=-30.0,
actuator=LINEAR_ACTUATOR_10, # The left side wrist is too small for an actuator to work
actuator=None, #LINEAR_ACTUATOR_10,
)) ))
# Distance between the two spacers on the elbow, halved # Distance between the two spacers on the elbow, halved
wrist_h2: float = 5.0 wrist_h2: float = 5.0
@ -90,6 +91,7 @@ class WingProfile(Model):
wrist_rotate: float = -30.0 wrist_rotate: float = -30.0
# Position of the elbow axle with 0 being bottom and 1 being top (flipped on the left side) # Position of the elbow axle with 0 being bottom and 1 being top (flipped on the left side)
elbow_axle_pos: float = 0.3 elbow_axle_pos: float = 0.3
wrist_axle_pos: float = 0.0
# False for the right side, True for the left side # False for the right side, True for the left side
flip: bool flip: bool
@ -103,9 +105,8 @@ class WingProfile(Model):
self.elbow_axle_pos = 1 - self.elbow_axle_pos self.elbow_axle_pos = 1 - self.elbow_axle_pos
self.elbow_axle_loc = self.elbow_bot_loc * Cq.Location.from2d(0, self.elbow_height * self.elbow_axle_pos) self.elbow_axle_loc = self.elbow_bot_loc * Cq.Location.from2d(0, self.elbow_height * self.elbow_axle_pos)
if self.flip: if self.flip:
self.wrist_axle_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height / 2) self.wrist_axle_pos = 1 - self.wrist_axle_pos
else: self.wrist_axle_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height * self.wrist_axle_pos)
self.wrist_axle_loc = self.wrist_bot_loc
assert self.elbow_joint.total_thickness < min(self.s1_thickness, self.s2_thickness) assert self.elbow_joint.total_thickness < min(self.s1_thickness, self.s2_thickness)
assert self.wrist_joint.total_thickness < min(self.s2_thickness, self.s3_thickness) assert self.wrist_joint.total_thickness < min(self.s2_thickness, self.s3_thickness)
@ -126,7 +127,8 @@ class WingProfile(Model):
""" """
s3 does not need to duck under s2 s3 does not need to duck under s2
""" """
return self.s1_thickness - 2 * self.panel_thickness extra = 2 * self.panel_thickness if self.flip else 0
return self.s1_thickness - 2 * self.panel_thickness - extra
@submodel(name="shoulder-joint") @submodel(name="shoulder-joint")
def submodel_shoulder_joint(self) -> Model: def submodel_shoulder_joint(self) -> Model:
@ -395,7 +397,7 @@ class WingProfile(Model):
for p in points for p in points
]) ])
) )
def _joint_extension_profile( def _child_joint_extension_profile(
self, self,
axle_loc: Cq.Location, axle_loc: Cq.Location,
radius: float, radius: float,
@ -640,8 +642,10 @@ class WingProfile(Model):
return extrude_with_markers(profile, self.panel_thickness, tags, reverse=front) return extrude_with_markers(profile, self.panel_thickness, tags, reverse=front)
@target(name="profile-s2-bridge", kind=TargetKind.DXF) @target(name="profile-s2-bridge", kind=TargetKind.DXF)
def profile_s2_bridge(self) -> Cq.Workplane: def profile_s2_bridge(self) -> Cq.Workplane:
# FIXME: Leave some margin here so we can glue the panels
# Generates the extension profile, which is required on both sides # Generates the extension profile, which is required on both sides
profile = self._joint_extension_profile( profile = self._child_joint_extension_profile(
axle_loc=self.wrist_axle_loc, axle_loc=self.wrist_axle_loc,
radius=self.wrist_height * (0.5 if self.flip else 1), radius=self.wrist_height * (0.5 if self.flip else 1),
angle_span=self.wrist_joint.motion_span, angle_span=self.wrist_joint.motion_span,
@ -881,25 +885,24 @@ class WingProfile(Model):
if "wrist" in parts: if "wrist" in parts:
angle = self.wrist_joint.motion_span * elbow_wrist_deflection angle = self.wrist_joint.motion_span * elbow_wrist_deflection
result.add(self.wrist_joint.assembly(angle=angle), name="wrist") result.add(self.wrist_joint.assembly(angle=angle), name="wrist")
wrist_n_holes = len(self.wrist_joint.hole_pos)
if "s2" in parts and "wrist" in parts: if "s2" in parts and "wrist" in parts:
# Mounted backwards to bend in other direction # Mounted backwards to bend in other direction
( for i in range(wrist_n_holes):
result (
.constrain("s2/wrist_top?conn0", f"wrist/parent_upper/lip?conn_{tag_bot}0", "Plane") result
.constrain("s2/wrist_top?conn1", f"wrist/parent_upper/lip?conn_{tag_bot}1", "Plane") .constrain(f"s2/wrist_top?conn{i}", f"wrist/parent_upper/lip?conn_{tag_bot}{i}", "Plane")
.constrain("s2/wrist_bot?conn0", f"wrist/parent_upper/lip?conn_{tag_top}0", "Plane") .constrain(f"s2/wrist_bot?conn{i}", f"wrist/parent_upper/lip?conn_{tag_top}{i}", "Plane")
.constrain("s2/wrist_bot?conn1", f"wrist/parent_upper/lip?conn_{tag_top}1", "Plane") )
)
if "s3" in parts: if "s3" in parts:
result.add(self.assembly_s3(), name="s3") result.add(self.assembly_s3(), name="s3")
if "s3" in parts and "wrist" in parts: if "s3" in parts and "wrist" in parts:
( for i in range(wrist_n_holes):
result (
.constrain("s3/wrist_top?conn0", f"wrist/child/lip?conn_{tag_bot}0", "Plane") result
.constrain("s3/wrist_top?conn1", f"wrist/child/lip?conn_{tag_bot}1", "Plane") .constrain(f"s3/wrist_top?conn{i}", f"wrist/child/lip?conn_{tag_bot}{i}", "Plane")
.constrain("s3/wrist_bot?conn0", f"wrist/child/lip?conn_{tag_top}0", "Plane") .constrain(f"s3/wrist_bot?conn{i}", f"wrist/child/lip?conn_{tag_top}{i}", "Plane")
.constrain("s3/wrist_bot?conn1", f"wrist/child/lip?conn_{tag_top}1", "Plane") )
)
if len(parts) > 1: if len(parts) > 1:
result.solve() result.solve()
@ -1095,6 +1098,8 @@ class WingL(WingProfile):
arrow_height: float = 120.0 arrow_height: float = 120.0
flip: bool = True flip: bool = True
elbow_axle_pos: float = 0.4
wrist_axle_pos: float = 0.5
def __post_init__(self): def __post_init__(self):
assert self.wrist_height <= self.shoulder_joint.height assert self.wrist_height <= self.shoulder_joint.height