diff --git a/nhf/parts/box.py b/nhf/parts/box.py index 5fbf21e..7270d29 100644 --- a/nhf/parts/box.py +++ b/nhf/parts/box.py @@ -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}" diff --git a/nhf/touhou/houjuu_nue/joints.py b/nhf/touhou/houjuu_nue/joints.py index 5ceac76..f98822d 100644 --- a/nhf/touhou/houjuu_nue/joints.py +++ b/nhf/touhou/houjuu_nue/joints.py @@ -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 diff --git a/nhf/touhou/houjuu_nue/wing.py b/nhf/touhou/houjuu_nue/wing.py index 7e6262c..179593d 100644 --- a/nhf/touhou/houjuu_nue/wing.py +++ b/nhf/touhou/houjuu_nue/wing.py @@ -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,