feat: Detach mount point from joint

This commit is contained in:
Leni Aniva 2024-07-25 10:41:58 -07:00
parent c1107aed2e
commit 82570528da
Signed by: aniva
GPG Key ID: 4D9B1C8D10EA4C50
3 changed files with 77 additions and 39 deletions

View File

@ -354,7 +354,8 @@ class Flexor:
line_slack: float = 0.0 line_slack: float = 0.0
def __post_init__(self): def __post_init__(self):
assert self.line_slack <= self.line_length < self.actuator.stroke_length assert self.line_slack <= self.line_length, f"Insufficient length: {self.line_slack} >= {self.line_length}"
assert self.line_slack < self.actuator.stroke_length
@property @property
def mount_height(self): def mount_height(self):

View File

@ -1121,8 +1121,6 @@ class ElbowJoint(Model):
parent_arm_radius: float = 40.0 parent_arm_radius: float = 40.0
lip_thickness: float = 5.0 lip_thickness: float = 5.0
# Extra bit on top of the lip to connect to actuator mount
child_lip_extra_length: float = 1.0
lip_length: float = 60.0 lip_length: float = 60.0
hole_pos: list[float] = field(default_factory=lambda: [12, 24]) hole_pos: list[float] = field(default_factory=lambda: [12, 24])
parent_arm_width: float = 10.0 parent_arm_width: float = 10.0
@ -1149,6 +1147,8 @@ class ElbowJoint(Model):
flexor_child_arm_radius: Optional[float] = None flexor_child_arm_radius: Optional[float] = None
flexor_line_length: float = 0.0 flexor_line_length: float = 0.0
flexor_line_slack: float = 0.0 flexor_line_slack: float = 0.0
flexor_parent_angle_fix: Optional[float] = 180.0
flexor_child_angle_fix: Optional[float] = None
def __post_init__(self): def __post_init__(self):
assert self.child_arm_radius > self.disk_joint.radius_housing assert self.child_arm_radius > self.disk_joint.radius_housing
@ -1220,10 +1220,15 @@ class ElbowJoint(Model):
# Moves the hole to be some distance apart from 0 # Moves the hole to be some distance apart from 0
mount_r, mount_loc_angle, mount_parent_r = self.flexor.open_pos() mount_r, mount_loc_angle, mount_parent_r = self.flexor.open_pos()
loc_span = Cq.Location.from2d(mount_r if child else mount_parent_r, 0) loc_span = Cq.Location.from2d(mount_r if child else mount_parent_r, 0)
alpha = (-mount_loc_angle if child else 0) + 180 - self.flexor_offset_angle if self.flexor_parent_angle_fix is not None:
alpha = (-mount_loc_angle if child else 0) + self.flexor_parent_angle_fix - self.flexor_offset_angle
elif self.flexor_child_angle_fix is not None:
alpha = self.flexor_child_angle_fix + (0 if child else mount_loc_angle)
else:
raise ValueError("One of flexor_{parent,child}_angle_fix must be set")
loc_rot = Cq.Location.rot2d(alpha) loc_rot = Cq.Location.rot2d(alpha)
loc = loc_rot * loc_span * loc_mount_orient * loc_mount loc = loc_rot * loc_span * loc_mount_orient * loc_mount
return loc.flip_y() if self.flip and not child and not unflip else loc return loc.flip_y() if self.flip and not unflip else loc
def lip(self) -> Cq.Workplane: def lip(self) -> Cq.Workplane:
sign = -1 if self.flip else 1 sign = -1 if self.flip else 1
@ -1248,7 +1253,7 @@ class ElbowJoint(Model):
return mbox.generate() return mbox.generate()
@target(name="child") @target(name="child")
def child_joint(self) -> Cq.Assembly: def child_joint(self, generate_mount: bool=False) -> Cq.Assembly:
angle = -self.disk_joint.tongue_span / 2 angle = -self.disk_joint.tongue_span / 2
dz = self.disk_joint.disk_thickness / 2 dz = self.disk_joint.disk_thickness / 2
# We need to ensure the disk is on the "other" side so # We need to ensure the disk is on the "other" side so
@ -1265,31 +1270,40 @@ class ElbowJoint(Model):
loc_cut_rel = Cq.Location((0, self.disk_joint.spring.radius_inner, -self.disk_joint.disk_bot_thickness)) loc_cut_rel = Cq.Location((0, self.disk_joint.spring.radius_inner, -self.disk_joint.disk_bot_thickness))
disk_cut = self.disk_joint._disk_cut().located( disk_cut = self.disk_joint._disk_cut().located(
loc_lip.inverse * loc_cut_rel * loc_disk) loc_lip.inverse * loc_cut_rel * loc_disk)
lip_extra = Cq.Solid.makeBox( #lip_extra = Cq.Solid.makeBox(
length=self.child_lip_extra_length, # length=self.child_lip_extra_length,
width=self.total_thickness, # width=self.total_thickness,
height=self.lip_thickness, # height=self.lip_thickness,
).located(Cq.Location(( #).located(Cq.Location((
self.lip_length / 2, # self.lip_length / 2,
-self.total_thickness / 2, # -self.total_thickness / 2,
0, # 0,
))) #)))
result = ( result = (
Cq.Assembly() Cq.Assembly()
.add(self.disk_joint.disk(), name="disk", .add(self.disk_joint.disk(), name="disk",
loc=loc_rot_neutral * Cq.Location((0, 0, -dz), (0,0,1), angle)) loc=loc_rot_neutral * Cq.Location((0, 0, -dz), (0,0,1), angle))
.add(self.lip().cut(disk_cut), name="lip", .add(self.lip().cut(disk_cut), name="lip",
loc=loc_rot_neutral * loc_disk.inverse * loc_lip) loc=loc_rot_neutral * loc_disk.inverse * loc_lip)
.add(lip_extra, name="lip_extra", #.add(lip_extra, name="lip_extra",
loc=loc_rot_neutral * loc_disk.inverse * loc_lip) # loc=loc_rot_neutral * loc_disk.inverse * loc_lip)
) )
# Orientes the hole surface so it faces +X # Orientes the hole surface so it faces +X
loc_thickness = Cq.Location((-self.lip_thickness, 0, 0), (0, 1, 0), 90) loc_thickness = Cq.Location((-self.lip_thickness, 0, 0), (0, 1, 0), 90)
if self.flexor: if self.flexor:
loc_mount = self.actuator_mount_loc(child=True, unflip=True)
result.add( result.add(
self.actuator_mount(), Cq.Edge.makeLine((-1,0,0), (1,0,0)),
name="act", name="act",
loc=self.actuator_mount_loc(child=True) * loc_thickness) loc=loc_mount)
if generate_mount:
# Orientes the hole surface so it faces +X
loc_thickness = Cq.Location((-self.lip_thickness, 0, 0), (0, 1, 0), 90)
result.add(
self.actuator_mount(),
name="act_mount",
loc=loc_mount * loc_thickness,
)
return result return result
@target(name="parent-lower") @target(name="parent-lower")
@ -1342,17 +1356,18 @@ class ElbowJoint(Model):
#.solve() #.solve()
) )
if self.flexor: if self.flexor:
loc_mount = self.actuator_mount_loc(child=False, unflip=True)
result.add( result.add(
Cq.Edge.makeLine((-1,0,0), (1,0,0)), Cq.Edge.makeLine((-1,0,0), (1,0,0)),
name="act", name="act",
loc=self.actuator_mount_loc(child=False, unflip=True)) loc=loc_mount)
if generate_mount: if generate_mount:
# Orientes the hole surface so it faces +X # Orientes the hole surface so it faces +X
loc_thickness = Cq.Location((-self.lip_thickness, 0, 0), (0, 1, 0), 90) loc_thickness = Cq.Location((-self.lip_thickness, 0, 0), (0, 1, 0), 90)
result.add( result.add(
self.actuator_mount(), self.actuator_mount(),
name="act_mount", name="act_mount",
loc=self.actuator_mount_loc(child=False, unflip=True) * loc_thickness loc=loc_mount * loc_thickness
) )
return result return result
@ -1364,7 +1379,7 @@ class ElbowJoint(Model):
assert 0 <= angle <= self.motion_span assert 0 <= angle <= self.motion_span
result = ( result = (
Cq.Assembly() Cq.Assembly()
.addS(self.child_joint(), name="child", .addS(self.child_joint(generate_mount=generate_mount), name="child",
role=Role.CHILD, material=self.material) role=Role.CHILD, material=self.material)
.addS(self.parent_joint_lower(), name="parent_lower", .addS(self.parent_joint_lower(), name="parent_lower",
role=Role.CASING, material=self.material) role=Role.CASING, material=self.material)

View File

@ -23,9 +23,6 @@ from nhf.touhou.houjuu_nue.electronics import (
import nhf.utils import nhf.utils
ELBOW_PARAMS = dict( ELBOW_PARAMS = dict(
disk_joint=DiskJoint(
movement_angle=55,
),
hole_diam=4.0, hole_diam=4.0,
actuator=LINEAR_ACTUATOR_50, actuator=LINEAR_ACTUATOR_50,
parent_arm_width=15, parent_arm_width=15,
@ -508,6 +505,8 @@ class WingProfile(Model):
loc_ext = loc_bot if bot else loc_top loc_ext = loc_bot if bot else loc_top
loc_tip = loc_top if bot else loc_bot loc_tip = loc_top if bot else loc_bot
theta = math.radians(angle_span * (median if child else 1 - median)) theta = math.radians(angle_span * (median if child else 1 - median))
if self.flip:
axle_pos = 1 - axle_pos
y_sign = -1 if bot else 1 y_sign = -1 if bot else 1
sign = -1 if child else 1 sign = -1 if child else 1
dh = axle_pos * height * (overestimate - 1) dh = axle_pos * height * (overestimate - 1)
@ -736,11 +735,14 @@ class WingProfile(Model):
) )
return profile return profile
def surface_s2(self, front: bool = True) -> Cq.Workplane: def surface_s2(self, front: bool = True) -> Cq.Workplane:
loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.child_arm_loc() rot_elbow = Cq.Location.rot2d(self.elbow_rotate)
loc_elbow = rot_elbow * self.elbow_joint.child_arm_loc()
rot_wrist = Cq.Location.rot2d(self.wrist_rotate) rot_wrist = Cq.Location.rot2d(self.wrist_rotate)
loc_wrist = rot_wrist * self.wrist_joint.parent_arm_loc() loc_wrist = rot_wrist * self.wrist_joint.parent_arm_loc()
tags = [ tags = [
("elbow", self.elbow_axle_loc * loc_elbow), ("elbow", self.elbow_axle_loc * loc_elbow),
("elbow_act", self.elbow_axle_loc * rot_elbow *
self.elbow_joint.actuator_mount_loc(child=True)),
("wrist", self.wrist_axle_loc * loc_wrist), ("wrist", self.wrist_axle_loc * loc_wrist),
("wrist_act", self.wrist_axle_loc * rot_wrist * ("wrist_act", self.wrist_axle_loc * rot_wrist *
self.wrist_joint.actuator_mount_loc()), self.wrist_joint.actuator_mount_loc()),
@ -773,6 +775,17 @@ class WingProfile(Model):
segment_thickness=self.s2_thickness, segment_thickness=self.s2_thickness,
child=True, child=True,
) )
@submodel(name="spacer-s1-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,
)
@submodel(name="spacer-s2-wrist") @submodel(name="spacer-s2-wrist")
def spacer_s2_wrist(self) -> MountingBox: def spacer_s2_wrist(self) -> MountingBox:
return self._spacer_from_disk_joint( return self._spacer_from_disk_joint(
@ -822,6 +835,7 @@ class WingProfile(Model):
) )
for o, t in [ for o, t in [
(self.spacer_s2_elbow(), "elbow"), (self.spacer_s2_elbow(), "elbow"),
(self.spacer_s2_elbow_act(), "elbow_act"),
(self.spacer_s2_wrist(), "wrist"), (self.spacer_s2_wrist(), "wrist"),
(self.spacer_s2_wrist_act(), "wrist_act"), (self.spacer_s2_wrist_act(), "wrist_act"),
]: ]:
@ -1055,11 +1069,13 @@ class WingR(WingProfile):
elbow_height: float = 111.0 elbow_height: float = 111.0
elbow_rotate: float = 10.0 elbow_rotate: float = 10.0
elbow_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint( elbow_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint(
disk_joint=DiskJoint(
movement_angle=55,
),
flexor_offset_angle=15, flexor_offset_angle=15,
flexor_mount_angle_child=-75, flexor_mount_angle_child=-75,
flexor_child_arm_radius=None, flexor_child_arm_radius=None,
angle_neutral=10.0, angle_neutral=10.0,
child_lip_extra_length=8,
flip=False, flip=False,
**ELBOW_PARAMS **ELBOW_PARAMS
)) ))
@ -1288,24 +1304,32 @@ class WingR(WingProfile):
@dataclass(kw_only=True) @dataclass(kw_only=True)
class WingL(WingProfile): class WingL(WingProfile):
elbow_bot_loc: Cq.Location = Cq.Location.from2d(260.0, 110.0, 0.0) elbow_bot_loc: Cq.Location = Cq.Location.from2d(260.0, 105.0, 0.0)
elbow_height: float = 90.0 elbow_height: float = 95.0
elbow_rotate: float = 15.0 elbow_rotate: float = 15.0
elbow_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint( elbow_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint(
angle_neutral=30.0, disk_joint=DiskJoint(
flexor_mount_angle_child=170, movement_angle=50,
flexor_mount_angle_parent=-30, ),
flexor_line_length=30.0, angle_neutral=25.0,
flexor_line_slack=5.0, flexor_mount_angle_child=220,
flexor_mount_angle_parent=0,
flexor_line_length=50.0,
flexor_line_slack=10.0,
#flexor_line_length=0.0, #flexor_line_length=0.0,
#flexor_line_slack=0.0, #flexor_line_slack=0.0,
flexor_offset_angle=15, flexor_offset_angle=0,
child_lip_extra_length=5.0, flexor_child_angle_fix=85,
flexor_child_arm_radius=60.0, flexor_parent_angle_fix=None,
flexor_child_arm_radius=50.0,
parent_arm_radius=50.0,
child_arm_radius=50.0,
flexor_pos_smaller=False, flexor_pos_smaller=False,
flip=True, flip=True,
**ELBOW_PARAMS **ELBOW_PARAMS
)) ))
elbow_axle_pos: float = 0.53
elbow_joint_overlap_median: float = 0.5
wrist_angle: float = 0.0 wrist_angle: float = 0.0
wrist_bot_loc: Cq.Location = Cq.Location.from2d(460.0, -10.0, -45.0) wrist_bot_loc: Cq.Location = Cq.Location.from2d(460.0, -10.0, -45.0)
@ -1324,9 +1348,7 @@ class WingL(WingProfile):
arrow_height: float = 120.0 arrow_height: float = 120.0
flip: bool = True flip: bool = True
elbow_axle_pos: float = 0.5
wrist_axle_pos: float = 0.5 wrist_axle_pos: float = 0.5
elbow_joint_overlap_median: float = 0.5
wrist_joint_overlap_median: float = 0.5 wrist_joint_overlap_median: float = 0.5