feat: Optional actuator on wrist
This commit is contained in:
parent
7371333a84
commit
ddeaf1194f
|
@ -300,6 +300,8 @@ LINEAR_ACTUATOR_10 = LinearActuator(
|
|||
back_hole_ext=4.5/2,
|
||||
segment1_length=30.0,
|
||||
segment2_length=30.0,
|
||||
segment1_width=15.0,
|
||||
segment2_width=21.0,
|
||||
)
|
||||
LINEAR_ACTUATOR_HEX_NUT = HexNut(
|
||||
mass=0.8,
|
||||
|
|
|
@ -882,8 +882,8 @@ class ElbowJoint(Model):
|
|||
|
||||
angle_neutral: float = 30.0
|
||||
|
||||
actuator: LinearActuator
|
||||
flexor: Flexor = None
|
||||
actuator: Optional[LinearActuator]
|
||||
flexor: Optional[Flexor] = None
|
||||
# Rotates the entire flexor
|
||||
flexor_offset_angle: float = 0
|
||||
# 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.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.flexor = Flexor(
|
||||
actuator=self.actuator,
|
||||
motion_span=self.motion_span
|
||||
)
|
||||
if self.actuator:
|
||||
self.flexor = Flexor(
|
||||
actuator=self.actuator,
|
||||
motion_span=self.motion_span
|
||||
)
|
||||
|
||||
@property
|
||||
def total_thickness(self):
|
||||
|
@ -990,8 +991,9 @@ class ElbowJoint(Model):
|
|||
Cq.Assembly()
|
||||
.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.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
|
||||
|
||||
@target(name="parent-lower")
|
||||
|
@ -1040,12 +1042,15 @@ class ElbowJoint(Model):
|
|||
Cq.Location((0, 0, 0), (0, 1, 0), 90))
|
||||
.add(connector, name="connector",
|
||||
loc=loc_net_housing.inverse * axial_offset)
|
||||
.add(self.actuator_mount(),
|
||||
name="act", loc=self.actuator_mount_loc(child=False))
|
||||
#.constrain("housing", "Fixed")
|
||||
#.constrain("connector", "Fixed")
|
||||
#.solve()
|
||||
)
|
||||
if self.flexor:
|
||||
result.add(
|
||||
self.actuator_mount(),
|
||||
name="act",
|
||||
loc=self.actuator_mount_loc(child=False))
|
||||
return result
|
||||
|
||||
@assembly()
|
||||
|
|
|
@ -51,7 +51,7 @@ class WingProfile(Model):
|
|||
disk_joint=DiskJoint(
|
||||
movement_angle=55,
|
||||
),
|
||||
hole_diam=6.0,
|
||||
hole_diam=4.0,
|
||||
angle_neutral=15.0,
|
||||
actuator=LINEAR_ACTUATOR_50,
|
||||
flexor_offset_angle=-15,
|
||||
|
@ -65,13 +65,14 @@ class WingProfile(Model):
|
|||
radius_disk=13.0,
|
||||
radius_housing=15.0,
|
||||
),
|
||||
hole_pos=[10, 20],
|
||||
lip_length=50,
|
||||
hole_pos=[10],
|
||||
lip_length=30,
|
||||
child_arm_radius=23.0,
|
||||
parent_arm_radius=30.0,
|
||||
hole_diam=4.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
|
||||
wrist_h2: float = 5.0
|
||||
|
@ -90,6 +91,7 @@ class WingProfile(Model):
|
|||
wrist_rotate: float = -30.0
|
||||
# Position of the elbow axle with 0 being bottom and 1 being top (flipped on the left side)
|
||||
elbow_axle_pos: float = 0.3
|
||||
wrist_axle_pos: float = 0.0
|
||||
|
||||
# False for the right side, True for the left side
|
||||
flip: bool
|
||||
|
@ -103,9 +105,8 @@ class WingProfile(Model):
|
|||
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)
|
||||
if self.flip:
|
||||
self.wrist_axle_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height / 2)
|
||||
else:
|
||||
self.wrist_axle_loc = self.wrist_bot_loc
|
||||
self.wrist_axle_pos = 1 - self.wrist_axle_pos
|
||||
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)
|
||||
|
@ -126,7 +127,8 @@ class WingProfile(Model):
|
|||
"""
|
||||
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")
|
||||
def submodel_shoulder_joint(self) -> Model:
|
||||
|
@ -395,7 +397,7 @@ class WingProfile(Model):
|
|||
for p in points
|
||||
])
|
||||
)
|
||||
def _joint_extension_profile(
|
||||
def _child_joint_extension_profile(
|
||||
self,
|
||||
axle_loc: Cq.Location,
|
||||
radius: float,
|
||||
|
@ -640,8 +642,10 @@ class WingProfile(Model):
|
|||
return extrude_with_markers(profile, self.panel_thickness, tags, reverse=front)
|
||||
@target(name="profile-s2-bridge", kind=TargetKind.DXF)
|
||||
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
|
||||
profile = self._joint_extension_profile(
|
||||
profile = self._child_joint_extension_profile(
|
||||
axle_loc=self.wrist_axle_loc,
|
||||
radius=self.wrist_height * (0.5 if self.flip else 1),
|
||||
angle_span=self.wrist_joint.motion_span,
|
||||
|
@ -881,25 +885,24 @@ class WingProfile(Model):
|
|||
if "wrist" in parts:
|
||||
angle = self.wrist_joint.motion_span * elbow_wrist_deflection
|
||||
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:
|
||||
# Mounted backwards to bend in other direction
|
||||
(
|
||||
result
|
||||
.constrain("s2/wrist_top?conn0", f"wrist/parent_upper/lip?conn_{tag_bot}0", "Plane")
|
||||
.constrain("s2/wrist_top?conn1", f"wrist/parent_upper/lip?conn_{tag_bot}1", "Plane")
|
||||
.constrain("s2/wrist_bot?conn0", f"wrist/parent_upper/lip?conn_{tag_top}0", "Plane")
|
||||
.constrain("s2/wrist_bot?conn1", f"wrist/parent_upper/lip?conn_{tag_top}1", "Plane")
|
||||
)
|
||||
for i in range(wrist_n_holes):
|
||||
(
|
||||
result
|
||||
.constrain(f"s2/wrist_top?conn{i}", f"wrist/parent_upper/lip?conn_{tag_bot}{i}", "Plane")
|
||||
.constrain(f"s2/wrist_bot?conn{i}", f"wrist/parent_upper/lip?conn_{tag_top}{i}", "Plane")
|
||||
)
|
||||
if "s3" in parts:
|
||||
result.add(self.assembly_s3(), name="s3")
|
||||
if "s3" in parts and "wrist" in parts:
|
||||
(
|
||||
result
|
||||
.constrain("s3/wrist_top?conn0", f"wrist/child/lip?conn_{tag_bot}0", "Plane")
|
||||
.constrain("s3/wrist_top?conn1", f"wrist/child/lip?conn_{tag_bot}1", "Plane")
|
||||
.constrain("s3/wrist_bot?conn0", f"wrist/child/lip?conn_{tag_top}0", "Plane")
|
||||
.constrain("s3/wrist_bot?conn1", f"wrist/child/lip?conn_{tag_top}1", "Plane")
|
||||
)
|
||||
for i in range(wrist_n_holes):
|
||||
(
|
||||
result
|
||||
.constrain(f"s3/wrist_top?conn{i}", f"wrist/child/lip?conn_{tag_bot}{i}", "Plane")
|
||||
.constrain(f"s3/wrist_bot?conn{i}", f"wrist/child/lip?conn_{tag_top}{i}", "Plane")
|
||||
)
|
||||
if len(parts) > 1:
|
||||
result.solve()
|
||||
|
||||
|
@ -1095,6 +1098,8 @@ class WingL(WingProfile):
|
|||
arrow_height: float = 120.0
|
||||
|
||||
flip: bool = True
|
||||
elbow_axle_pos: float = 0.4
|
||||
wrist_axle_pos: float = 0.5
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.wrist_height <= self.shoulder_joint.height
|
||||
|
|
Loading…
Reference in New Issue