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