cosplay: Touhou/Houjuu Nue #4
|
@ -75,6 +75,7 @@ class MountingBox(Model):
|
|||
profile_callback: Optional[Callable[[Cq.Sketch], Cq.Sketch]] = None
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.thickness > 0
|
||||
for i, hole in enumerate(self.holes):
|
||||
if hole.tag is None:
|
||||
hole.tag = f"conn{i}"
|
||||
|
|
|
@ -72,7 +72,7 @@ ELBOW_AXLE_BOLT = FlatHeadBolt(
|
|||
diam_head=6.87,
|
||||
height_head=3.06,
|
||||
diam_thread=4.0,
|
||||
height_thread=20.0,
|
||||
height_thread=15.0,
|
||||
)
|
||||
ELBOW_AXLE_WASHER = Washer(
|
||||
mass=0.0,
|
||||
|
@ -888,11 +888,10 @@ class DiskJoint(Model):
|
|||
|
||||
radius_housing: float = 22.0
|
||||
radius_disk: float = 20.0
|
||||
radius_axle: float = 3.0
|
||||
|
||||
housing_thickness: float = 4.0
|
||||
disk_thickness: float = 8.0
|
||||
tongue_thickness: float = 10.0
|
||||
housing_thickness: float = 2.0
|
||||
disk_thickness: float = 6.0
|
||||
tongue_thickness: float = 12.0
|
||||
|
||||
# Amount by which the wall carves in
|
||||
wall_inset: float = 2.0
|
||||
|
@ -924,7 +923,6 @@ class DiskJoint(Model):
|
|||
|
||||
assert self.housing_upper_carve_offset > 0
|
||||
assert self.spring_tail_hole_height > self.spring.thickness
|
||||
assert self.tongue_thickness <= self.total_thickness
|
||||
|
||||
assert self.axle_bolt.diam_thread == self.axle_washer.diam_thread
|
||||
assert self.axle_bolt.diam_thread == self.axle_hex_nut.diam_thread
|
||||
|
@ -937,6 +935,10 @@ class DiskJoint(Model):
|
|||
return a
|
||||
return None
|
||||
|
||||
@property
|
||||
def radius_axle(self) -> float:
|
||||
return self.axle_bolt.diam_thread
|
||||
|
||||
@property
|
||||
def total_thickness(self) -> float:
|
||||
return self.housing_thickness * 2 + self.disk_thickness
|
||||
|
@ -1268,8 +1270,11 @@ class ElbowJoint(Model):
|
|||
yield -x, f"conn_bot{i}"
|
||||
|
||||
@property
|
||||
def total_thickness(self):
|
||||
return self.disk_joint.total_thickness
|
||||
def total_thickness(self) -> float:
|
||||
candidate1 = self.disk_joint.axle_bolt.height_thread
|
||||
candidate2 = self.disk_joint.total_thickness + self.disk_joint.axle_hex_nut.thickness
|
||||
head_thickness = self.disk_joint.axle_bolt.height_head
|
||||
return head_thickness + max(candidate1, candidate2)
|
||||
|
||||
@property
|
||||
def motion_span(self) -> float:
|
||||
|
@ -1338,6 +1343,8 @@ class ElbowJoint(Model):
|
|||
def post(sketch: Cq.Sketch) -> Cq.Sketch:
|
||||
y_outer = self.disk_joint.total_thickness / 2
|
||||
y_inner = self.disk_joint.tongue_thickness / 2
|
||||
if y_outer < y_inner:
|
||||
return sketch
|
||||
y = (y_outer + y_inner) / 2
|
||||
width = self.lip_side_depression_width
|
||||
height = y_outer - y_inner
|
||||
|
|
|
@ -29,6 +29,11 @@ ELBOW_PARAMS = dict(
|
|||
actuator=LINEAR_ACTUATOR_50,
|
||||
parent_arm_width=15,
|
||||
)
|
||||
ELBOW_DISK_PARAMS = dict(
|
||||
housing_thickness=2.5,
|
||||
disk_thickness=6.8,
|
||||
tongue_thickness=12.3,
|
||||
)
|
||||
WRIST_DISK_PARAMS = dict(
|
||||
movement_angle=30,
|
||||
radius_disk=13.0,
|
||||
|
@ -116,8 +121,8 @@ class WingProfile(Model):
|
|||
self.wrist_axle_loc = self.wrist_bot_loc * \
|
||||
Cq.Location.from2d(0, self.wrist_height * self.wrist_axle_pos)
|
||||
|
||||
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.elbow_joint.total_thickness < min(self.s1_thickness, self.s2_thickness)
|
||||
#assert self.wrist_joint.total_thickness < min(self.s2_thickness, self.s3_thickness)
|
||||
|
||||
self.shoulder_joint.angle_neutral = -self.shoulder_angle_neutral - self.shoulder_angle_bias
|
||||
self.shoulder_axle_loc = Cq.Location.from2d(self.shoulder_tip_x, self.shoulder_tip_y - self.shoulder_width / 2, 0)
|
||||
|
@ -642,6 +647,29 @@ class WingProfile(Model):
|
|||
profile_callback=carve_sides,
|
||||
)
|
||||
return mbox
|
||||
def _actuator_mount(self, thickness: float, joint: ElbowJoint) -> MountingBox:
|
||||
def post(sketch: Cq.Sketch) -> Cq.Sketch:
|
||||
x = thickness / 2 - self.light_strip.height / 2
|
||||
w = self.light_strip.height
|
||||
h = self.light_strip.width
|
||||
return (
|
||||
sketch
|
||||
.push([(x, 0), (-x, 0)])
|
||||
.rect(w, h, mode='s')
|
||||
#.push([(0, x), (0, -x)])
|
||||
#.rect(h, w, mode='s')
|
||||
)
|
||||
|
||||
return MountingBox(
|
||||
length=thickness,
|
||||
width=thickness,
|
||||
thickness=self.spacer_thickness,
|
||||
holes=[Hole(x=0,y=0)],
|
||||
centred=(True, True),
|
||||
hole_diam=joint.hole_diam,
|
||||
centre_left_right_tags=True,
|
||||
profile_callback=post,
|
||||
)
|
||||
|
||||
@target(name="profile-s1", kind=TargetKind.DXF)
|
||||
def profile_s1(self) -> Cq.Sketch:
|
||||
|
@ -709,14 +737,9 @@ class WingProfile(Model):
|
|||
)
|
||||
@submodel(name="spacer-s1-elbow-act")
|
||||
def spacer_s1_elbow_act(self) -> MountingBox:
|
||||
return MountingBox(
|
||||
length=self.s1_thickness,
|
||||
width=self.s1_thickness,
|
||||
thickness=self.spacer_thickness,
|
||||
holes=[Hole(x=0,y=0)],
|
||||
centred=(True, True),
|
||||
hole_diam=self.elbow_joint.hole_diam,
|
||||
centre_left_right_tags=True,
|
||||
return self._actuator_mount(
|
||||
thickness=self.s1_thickness,
|
||||
joint=self.elbow_joint
|
||||
)
|
||||
@assembly()
|
||||
def assembly_s1(self) -> Cq.Assembly:
|
||||
|
@ -838,14 +861,9 @@ class WingProfile(Model):
|
|||
)
|
||||
@submodel(name="spacer-s2-elbow-act")
|
||||
def spacer_s2_elbow_act(self) -> MountingBox:
|
||||
return MountingBox(
|
||||
length=self.s2_thickness,
|
||||
width=self.s2_thickness,
|
||||
thickness=self.spacer_thickness,
|
||||
holes=[Hole(x=0,y=0)],
|
||||
centred=(True, True),
|
||||
hole_diam=self.elbow_joint.hole_diam,
|
||||
centre_left_right_tags=True,
|
||||
return self._actuator_mount(
|
||||
thickness=self.s2_thickness,
|
||||
joint=self.elbow_joint
|
||||
)
|
||||
@submodel(name="spacer-s2-wrist")
|
||||
def spacer_s2_wrist(self) -> MountingBox:
|
||||
|
@ -855,14 +873,9 @@ class WingProfile(Model):
|
|||
)
|
||||
@submodel(name="spacer-s2-wrist-act")
|
||||
def spacer_s2_wrist_act(self) -> MountingBox:
|
||||
return MountingBox(
|
||||
length=self.s2_thickness,
|
||||
width=self.s2_thickness,
|
||||
thickness=self.spacer_thickness,
|
||||
holes=[Hole(x=0,y=0)],
|
||||
centred=(True, True),
|
||||
hole_diam=self.wrist_joint.hole_diam,
|
||||
centre_left_right_tags=True,
|
||||
return self._actuator_mount(
|
||||
thickness=self.s2_thickness,
|
||||
joint=self.wrist_joint
|
||||
)
|
||||
@assembly()
|
||||
def assembly_s2(self) -> Cq.Assembly:
|
||||
|
@ -979,14 +992,9 @@ class WingProfile(Model):
|
|||
)
|
||||
@submodel(name="spacer-s3-wrist-act")
|
||||
def spacer_s3_wrist_act(self) -> MountingBox:
|
||||
return MountingBox(
|
||||
length=self.s3_thickness,
|
||||
width=self.s3_thickness,
|
||||
thickness=self.spacer_thickness,
|
||||
holes=[Hole(x=0,y=0)],
|
||||
centred=(True, True),
|
||||
hole_diam=self.wrist_joint.hole_diam,
|
||||
centre_left_right_tags=True,
|
||||
return self._actuator_mount(
|
||||
thickness=self.s3_thickness,
|
||||
joint=self.wrist_joint
|
||||
)
|
||||
@assembly()
|
||||
def assembly_s3(self) -> Cq.Assembly:
|
||||
|
@ -1160,6 +1168,7 @@ class WingR(WingProfile):
|
|||
disk_joint=DiskJoint(
|
||||
movement_angle=55,
|
||||
spring_angle_at_0=75,
|
||||
**ELBOW_DISK_PARAMS,
|
||||
),
|
||||
flexor_offset_angle=15,
|
||||
flexor_mount_angle_child=-75,
|
||||
|
@ -1416,6 +1425,7 @@ class WingL(WingProfile):
|
|||
disk_joint=DiskJoint(
|
||||
spring_angle_at_0=100,
|
||||
movement_angle=50,
|
||||
**ELBOW_DISK_PARAMS,
|
||||
),
|
||||
angle_neutral=30.0,
|
||||
flexor_mount_angle_child=220,
|
||||
|
@ -1442,6 +1452,7 @@ class WingL(WingProfile):
|
|||
wrist_height: float = 43.0
|
||||
wrist_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint(
|
||||
disk_joint=DiskJoint(
|
||||
tongue_thickness=8.0,
|
||||
**WRIST_DISK_PARAMS,
|
||||
),
|
||||
flip=False,
|
||||
|
|
Loading…
Reference in New Issue