feat: Stable positioning of actuators
This commit is contained in:
parent
ac509a1625
commit
656a2ae5bb
|
@ -59,6 +59,7 @@ class MountingBox(Model):
|
||||||
generate_reverse_tags: bool = False
|
generate_reverse_tags: bool = False
|
||||||
|
|
||||||
centre_bot_top_tags: bool = False
|
centre_bot_top_tags: bool = False
|
||||||
|
centre_left_right_tags: bool = False
|
||||||
|
|
||||||
# Determines the position of side tags
|
# Determines the position of side tags
|
||||||
flip_y: bool = False
|
flip_y: bool = False
|
||||||
|
@ -103,6 +104,10 @@ class MountingBox(Model):
|
||||||
reverse_plane.moveTo(hole.x, hole.y).tagPlane(hole.rev_tag, '-Z')
|
reverse_plane.moveTo(hole.x, hole.y).tagPlane(hole.rev_tag, '-Z')
|
||||||
|
|
||||||
if self.generate_side_tags:
|
if self.generate_side_tags:
|
||||||
|
if self.centre_left_right_tags:
|
||||||
|
result.faces("<Y").workplane(origin=result.edges("<Y and >Z").val().Center()).tagPlane("left")
|
||||||
|
result.faces(">Y").workplane(origin=result.edges(">Y and >Z").val().Center()).tagPlane("right")
|
||||||
|
else:
|
||||||
result.faces("<Y").workplane(origin=result.vertices("<X and <Y and >Z").val().Center()).tagPlane("left")
|
result.faces("<Y").workplane(origin=result.vertices("<X and <Y and >Z").val().Center()).tagPlane("left")
|
||||||
result.faces(">Y").workplane(origin=result.vertices("<X and >Y and >Z").val().Center()).tagPlane("right")
|
result.faces(">Y").workplane(origin=result.vertices("<X and >Y and >Z").val().Center()).tagPlane("right")
|
||||||
|
|
||||||
|
|
|
@ -944,6 +944,8 @@ class ElbowJoint(Model):
|
||||||
|
|
||||||
material: Material = Material.RESIN_TRANSPERENT
|
material: Material = Material.RESIN_TRANSPERENT
|
||||||
|
|
||||||
|
# If set to true, the joint is flipped upside down.
|
||||||
|
flip: bool = False
|
||||||
angle_neutral: float = 30.0
|
angle_neutral: float = 30.0
|
||||||
|
|
||||||
actuator: Optional[LinearActuator]
|
actuator: Optional[LinearActuator]
|
||||||
|
@ -951,7 +953,7 @@ class ElbowJoint(Model):
|
||||||
# Rotates the entire flexor
|
# Rotates the entire flexor
|
||||||
flexor_offset_angle: float = 0
|
flexor_offset_angle: float = 0
|
||||||
# Rotates the surface of the mount
|
# Rotates the surface of the mount
|
||||||
flexor_mount_rot: float = 90.0
|
flexor_mount_rot: float = 0
|
||||||
|
|
||||||
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
|
||||||
|
@ -977,15 +979,13 @@ class ElbowJoint(Model):
|
||||||
axle is at position 0, and parent direction is -X
|
axle is at position 0, and parent direction is -X
|
||||||
"""
|
"""
|
||||||
return Cq.Location.from2d(-self.parent_arm_radius, 0, 0)
|
return Cq.Location.from2d(-self.parent_arm_radius, 0, 0)
|
||||||
def child_arm_loc(self, flip: bool = False, angle: float = 0.0) -> Cq.Location:
|
def child_arm_loc(self, angle: float = 0.0) -> Cq.Location:
|
||||||
"""
|
"""
|
||||||
2d Location of the centre of the arm surface on the child side, assuming
|
2d Location of the centre of the arm surface on the child side, assuming
|
||||||
axle is at position 0, and parent direction is -X
|
axle is at position 0, and parent direction is -X
|
||||||
|
|
||||||
Set `flip=True` to indicate that the joint is supposed to be installed upside down
|
|
||||||
"""
|
"""
|
||||||
result = Cq.Location.rot2d(self.angle_neutral + angle) * Cq.Location.from2d(self.child_arm_radius, 0, 180)
|
result = Cq.Location.rot2d(self.angle_neutral + angle) * Cq.Location.from2d(self.child_arm_radius, 0, 180)
|
||||||
return result.flip_y() if flip else result
|
return result.flip_y() if self.flip else result
|
||||||
def actuator_mount(self) -> Cq.Workplane:
|
def actuator_mount(self) -> Cq.Workplane:
|
||||||
holes = [
|
holes = [
|
||||||
Hole(x=0, y=0, tag="mount"),
|
Hole(x=0, y=0, tag="mount"),
|
||||||
|
@ -1000,26 +1000,31 @@ class ElbowJoint(Model):
|
||||||
generate_side_tags=False,
|
generate_side_tags=False,
|
||||||
)
|
)
|
||||||
return mbox.generate()
|
return mbox.generate()
|
||||||
def actuator_mount_loc(self, child: bool) -> Cq.Location:
|
def actuator_mount_loc(
|
||||||
# Orientes the hole surface so it faces +X
|
self,
|
||||||
loc_thickness = Cq.Location((-self.lip_thickness, 0, 0), (0, 1, 0), 90)
|
child: bool = False,
|
||||||
|
# If set to true, use the local coordinate system
|
||||||
|
unflip: bool = False,
|
||||||
|
) -> Cq.Location:
|
||||||
# Moves the hole so the axle of the mount is perpendicular to it
|
# Moves the hole so the axle of the mount is perpendicular to it
|
||||||
loc_mount = Cq.Location.from2d(self.flexor.mount_height, 0) * Cq.Location.rot2d(180)
|
loc_mount = Cq.Location.from2d(self.flexor.mount_height, 0) * Cq.Location.rot2d(180)
|
||||||
loc_mount_orient = Cq.Location.rot2d(self.flexor_mount_rot * (-1 if child else 1))
|
loc_mount_orient = Cq.Location.rot2d(self.flexor_mount_rot * (-1 if child else 1))
|
||||||
# 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)
|
||||||
r = (-mount_loc_angle if child else 0) + 180
|
r = (-mount_loc_angle - self.angle_neutral if child else 0) + 180 + self.flexor_offset_angle
|
||||||
loc_rot = Cq.Location.rot2d(r + self.flexor_offset_angle)
|
loc_rot = Cq.Location.rot2d(r)
|
||||||
return loc_rot * loc_span * loc_mount_orient * loc_mount * loc_thickness
|
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
|
||||||
|
|
||||||
def lip(self) -> Cq.Workplane:
|
def lip(self) -> Cq.Workplane:
|
||||||
|
sign = -1 if self.flip else 1
|
||||||
holes = [
|
holes = [
|
||||||
h
|
h
|
||||||
for i, x in enumerate(self.hole_pos)
|
for i, x in enumerate(self.hole_pos)
|
||||||
for h in [
|
for h in [
|
||||||
Hole(x=x, tag=f"conn_top{i}"),
|
Hole(x=sign * x, tag=f"conn_top{i}"),
|
||||||
Hole(x=-x, tag=f"conn_bot{i}")
|
Hole(x=-sign * x, tag=f"conn_bot{i}")
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
mbox = MountingBox(
|
mbox = MountingBox(
|
||||||
|
@ -1047,17 +1052,22 @@ class ElbowJoint(Model):
|
||||||
Cq.Location((-lip_dz, 0, 0), (1, 0, 0), 90) *
|
Cq.Location((-lip_dz, 0, 0), (1, 0, 0), 90) *
|
||||||
Cq.Location((0, 0, 0), (0, 1, 0), 90)
|
Cq.Location((0, 0, 0), (0, 1, 0), 90)
|
||||||
)
|
)
|
||||||
loc_disk = flip_x * flip_z * Cq.Location((-self.child_arm_radius, 0, 0), (0, 0, 1), angle)
|
loc_disk = flip_x * flip_z * Cq.Location((-self.child_arm_radius, 0, 0))
|
||||||
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)
|
||||||
result = (
|
result = (
|
||||||
Cq.Assembly()
|
Cq.Assembly()
|
||||||
.add(self.disk_joint.disk(), name="disk", loc=Cq.Location((0, 0, -dz)))
|
.add(self.disk_joint.disk(), name="disk", loc=Cq.Location((0, 0, -dz), (0,0,1), angle))
|
||||||
.add(self.lip().cut(disk_cut), name="lip", loc=loc_disk.inverse * loc_lip)
|
.add(self.lip().cut(disk_cut), name="lip", loc=loc_disk.inverse * loc_lip)
|
||||||
)
|
)
|
||||||
|
# Orientes the hole surface so it faces +X
|
||||||
|
loc_thickness = Cq.Location((-self.lip_thickness, 0, 0), (0, 1, 0), 90)
|
||||||
if self.flexor:
|
if self.flexor:
|
||||||
result.add(self.actuator_mount(), name="act", loc=self.actuator_mount_loc(child=True))
|
result.add(
|
||||||
|
self.actuator_mount(),
|
||||||
|
name="act",
|
||||||
|
loc=self.actuator_mount_loc(child=True) * loc_thickness)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@target(name="parent-lower")
|
@target(name="parent-lower")
|
||||||
|
@ -1090,31 +1100,32 @@ class ElbowJoint(Model):
|
||||||
)
|
)
|
||||||
housing = self.disk_joint.housing_upper()
|
housing = self.disk_joint.housing_upper()
|
||||||
housing_loc = Cq.Location(
|
housing_loc = Cq.Location(
|
||||||
(0, 0, 0),
|
(0, 0, housing_dz),
|
||||||
(0, 0, 1),
|
(0, 0, 1),
|
||||||
-self.disk_joint.tongue_span / 2 + self.angle_neutral
|
-self.disk_joint.tongue_span / 2 + self.angle_neutral
|
||||||
)
|
)
|
||||||
lip_dz = self.lip_thickness
|
lip_dz = self.lip_thickness
|
||||||
loc_net_housing = axial_offset * housing_loc
|
|
||||||
result = (
|
result = (
|
||||||
Cq.Assembly()
|
Cq.Assembly()
|
||||||
.add(housing, name="housing", loc=Cq.Location((0, 0, housing_dz)))
|
# rotate so 0 degree is at +X
|
||||||
|
.add(housing, name="housing", loc=housing_loc)
|
||||||
.add(self.lip(), name="lip", loc=
|
.add(self.lip(), name="lip", loc=
|
||||||
loc_net_housing.inverse *
|
axial_offset.inverse *
|
||||||
Cq.Location((0, 0, 0), (0, 1, 0), 180) *
|
Cq.Location((0, 0, 0), (0, 1, 0), 180) *
|
||||||
Cq.Location((-lip_dz, 0, 0), (1, 0, 0), 90) *
|
Cq.Location((-lip_dz, 0, 0), (1, 0, 0), 90) *
|
||||||
Cq.Location((0, 0, 0), (0, 1, 0), 90))
|
Cq.Location((0, 0, 0), (0, 1, 0), 90))
|
||||||
.add(connector, name="connector",
|
.add(connector, name="connector")
|
||||||
loc=loc_net_housing.inverse * axial_offset)
|
|
||||||
#.constrain("housing", "Fixed")
|
#.constrain("housing", "Fixed")
|
||||||
#.constrain("connector", "Fixed")
|
#.constrain("connector", "Fixed")
|
||||||
#.solve()
|
#.solve()
|
||||||
)
|
)
|
||||||
if self.flexor:
|
if self.flexor:
|
||||||
|
# Orientes the hole surface so it faces +X
|
||||||
|
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",
|
name="act",
|
||||||
loc=self.actuator_mount_loc(child=False))
|
loc=self.actuator_mount_loc(child=False) * loc_thickness)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@assembly()
|
@assembly()
|
||||||
|
|
|
@ -14,7 +14,7 @@ from nhf.parts.box import box_with_centre_holes, MountingBox, Hole
|
||||||
from nhf.parts.joints import HirthJoint
|
from nhf.parts.joints import HirthJoint
|
||||||
from nhf.parts.planar import extrude_with_markers
|
from nhf.parts.planar import extrude_with_markers
|
||||||
from nhf.touhou.houjuu_nue.joints import RootJoint, ShoulderJoint, ElbowJoint, DiskJoint
|
from nhf.touhou.houjuu_nue.joints import RootJoint, ShoulderJoint, ElbowJoint, DiskJoint
|
||||||
from nhf.touhou.houjuu_nue.electronics import LINEAR_ACTUATOR_10, LINEAR_ACTUATOR_50, ElectronicBoard
|
from nhf.touhou.houjuu_nue.electronics import LINEAR_ACTUATOR_21, LINEAR_ACTUATOR_50, ElectronicBoard
|
||||||
import nhf.utils
|
import nhf.utils
|
||||||
|
|
||||||
@dataclass(kw_only=True)
|
@dataclass(kw_only=True)
|
||||||
|
@ -57,7 +57,8 @@ class WingProfile(Model):
|
||||||
hole_diam=4.0,
|
hole_diam=4.0,
|
||||||
angle_neutral=15.0,
|
angle_neutral=15.0,
|
||||||
actuator=LINEAR_ACTUATOR_50,
|
actuator=LINEAR_ACTUATOR_50,
|
||||||
flexor_offset_angle=-15,
|
flexor_offset_angle=0,
|
||||||
|
flip=False,
|
||||||
))
|
))
|
||||||
# Distance between the two spacers on the elbow, halved
|
# Distance between the two spacers on the elbow, halved
|
||||||
elbow_h2: float = 5.0
|
elbow_h2: float = 5.0
|
||||||
|
@ -74,7 +75,9 @@ class WingProfile(Model):
|
||||||
parent_arm_radius=30.0,
|
parent_arm_radius=30.0,
|
||||||
hole_diam=4.0,
|
hole_diam=4.0,
|
||||||
angle_neutral=-30.0,
|
angle_neutral=-30.0,
|
||||||
actuator=LINEAR_ACTUATOR_10,
|
actuator=LINEAR_ACTUATOR_21,
|
||||||
|
flexor_offset_angle=0,
|
||||||
|
flip=True,
|
||||||
))
|
))
|
||||||
# Distance between the two spacers on the elbow, halved
|
# Distance between the two spacers on the elbow, halved
|
||||||
wrist_h2: float = 5.0
|
wrist_h2: float = 5.0
|
||||||
|
@ -608,12 +611,15 @@ class WingProfile(Model):
|
||||||
("shoulder_top", Cq.Location.from2d(0, h + shoulder_h, 270)),
|
("shoulder_top", Cq.Location.from2d(0, h + shoulder_h, 270)),
|
||||||
]
|
]
|
||||||
h = self.elbow_height / 2
|
h = self.elbow_height / 2
|
||||||
loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.parent_arm_loc()
|
rot_elbow = Cq.Location.rot2d(self.elbow_rotate)
|
||||||
|
loc_elbow = rot_elbow * self.elbow_joint.parent_arm_loc()
|
||||||
tags_elbow = [
|
tags_elbow = [
|
||||||
("elbow_bot", self.elbow_axle_loc * loc_elbow *
|
("elbow_bot", self.elbow_axle_loc * loc_elbow *
|
||||||
Cq.Location.from2d(0, -self.elbow_h2)),
|
Cq.Location.from2d(0, -self.elbow_h2)),
|
||||||
("elbow_top", self.elbow_axle_loc * loc_elbow *
|
("elbow_top", self.elbow_axle_loc * loc_elbow *
|
||||||
Cq.Location.from2d(0, self.elbow_h2)),
|
Cq.Location.from2d(0, self.elbow_h2)),
|
||||||
|
("elbow_act", self.elbow_axle_loc * rot_elbow *
|
||||||
|
self.elbow_joint.actuator_mount_loc()),
|
||||||
]
|
]
|
||||||
profile = self.profile_s1()
|
profile = self.profile_s1()
|
||||||
tags = tags_shoulder + tags_elbow
|
tags = tags_shoulder + tags_elbow
|
||||||
|
@ -639,6 +645,17 @@ class WingProfile(Model):
|
||||||
segment_thickness=self.s1_thickness,
|
segment_thickness=self.s1_thickness,
|
||||||
dx=self.elbow_h2,
|
dx=self.elbow_h2,
|
||||||
)
|
)
|
||||||
|
@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,
|
||||||
|
)
|
||||||
@assembly()
|
@assembly()
|
||||||
def assembly_s1(self) -> Cq.Assembly:
|
def assembly_s1(self) -> Cq.Assembly:
|
||||||
result = (
|
result = (
|
||||||
|
@ -651,13 +668,17 @@ class WingProfile(Model):
|
||||||
.constrain("front@faces@>Z", "back@faces@<Z", "Point",
|
.constrain("front@faces@>Z", "back@faces@<Z", "Point",
|
||||||
param=self.s1_thickness)
|
param=self.s1_thickness)
|
||||||
)
|
)
|
||||||
for t in ["shoulder_bot", "shoulder_top", "elbow_bot", "elbow_top"]:
|
for o, t in [
|
||||||
|
(self.spacer_s1_shoulder(), "shoulder_bot"),
|
||||||
|
(self.spacer_s1_shoulder(), "shoulder_top"),
|
||||||
|
(self.spacer_s1_elbow(), "elbow_top"),
|
||||||
|
(self.spacer_s1_elbow(), "elbow_bot"),
|
||||||
|
(self.spacer_s1_elbow_act(), "elbow_act"),
|
||||||
|
]:
|
||||||
is_top = t.endswith("_top")
|
is_top = t.endswith("_top")
|
||||||
is_parent = t.startswith("shoulder")
|
|
||||||
o = self.spacer_s1_shoulder().generate() if is_parent else self.spacer_s1_elbow().generate()
|
|
||||||
self._assembly_insert_spacer(
|
self._assembly_insert_spacer(
|
||||||
result,
|
result,
|
||||||
o,
|
o.generate(),
|
||||||
point_tag=t,
|
point_tag=t,
|
||||||
flipped=not is_top,
|
flipped=not is_top,
|
||||||
)
|
)
|
||||||
|
@ -683,19 +704,22 @@ 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(flip=self.flip)
|
loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.child_arm_loc()
|
||||||
tags_elbow = [
|
tags_elbow = [
|
||||||
("elbow_bot", self.elbow_axle_loc * loc_elbow *
|
("elbow_bot", self.elbow_axle_loc * loc_elbow *
|
||||||
Cq.Location.from2d(0, self.elbow_h2)),
|
Cq.Location.from2d(0, self.elbow_h2)),
|
||||||
("elbow_top", self.elbow_axle_loc * loc_elbow *
|
("elbow_top", self.elbow_axle_loc * loc_elbow *
|
||||||
Cq.Location.from2d(0, -self.elbow_h2)),
|
Cq.Location.from2d(0, -self.elbow_h2)),
|
||||||
]
|
]
|
||||||
loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.parent_arm_loc()
|
rot_wrist = Cq.Location.rot2d(self.wrist_rotate)
|
||||||
|
loc_wrist = rot_wrist * self.wrist_joint.parent_arm_loc()
|
||||||
tags_wrist = [
|
tags_wrist = [
|
||||||
("wrist_bot", self.wrist_axle_loc * loc_wrist *
|
("wrist_bot", self.wrist_axle_loc * loc_wrist *
|
||||||
Cq.Location.from2d(0, -self.wrist_h2)),
|
Cq.Location.from2d(0, -self.wrist_h2)),
|
||||||
("wrist_top", self.wrist_axle_loc * loc_wrist *
|
("wrist_top", self.wrist_axle_loc * loc_wrist *
|
||||||
Cq.Location.from2d(0, self.wrist_h2)),
|
Cq.Location.from2d(0, self.wrist_h2)),
|
||||||
|
("wrist_act", self.wrist_axle_loc * rot_wrist *
|
||||||
|
self.wrist_joint.actuator_mount_loc()),
|
||||||
]
|
]
|
||||||
profile = self.profile_s2()
|
profile = self.profile_s2()
|
||||||
tags = tags_elbow + tags_wrist
|
tags = tags_elbow + tags_wrist
|
||||||
|
@ -750,6 +774,17 @@ class WingProfile(Model):
|
||||||
segment_thickness=self.s2_thickness,
|
segment_thickness=self.s2_thickness,
|
||||||
dx=self.wrist_h2,
|
dx=self.wrist_h2,
|
||||||
)
|
)
|
||||||
|
@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,
|
||||||
|
)
|
||||||
@assembly()
|
@assembly()
|
||||||
def assembly_s2(self) -> Cq.Assembly:
|
def assembly_s2(self) -> Cq.Assembly:
|
||||||
result = (
|
result = (
|
||||||
|
@ -770,10 +805,15 @@ class WingProfile(Model):
|
||||||
.constrain("back?wrist_bot", "bridge_back?wrist_bot", "Plane")
|
.constrain("back?wrist_bot", "bridge_back?wrist_bot", "Plane")
|
||||||
.constrain("back?wrist_top", "bridge_back?wrist_top", "Plane")
|
.constrain("back?wrist_top", "bridge_back?wrist_top", "Plane")
|
||||||
)
|
)
|
||||||
for t in ["elbow_bot", "elbow_top", "wrist_bot", "wrist_top"]:
|
for o, t in [
|
||||||
|
(self.spacer_s2_elbow(), "elbow_bot"),
|
||||||
|
(self.spacer_s2_elbow(), "elbow_top"),
|
||||||
|
(self.spacer_s2_wrist(), "wrist_bot"),
|
||||||
|
(self.spacer_s2_wrist(), "wrist_top"),
|
||||||
|
(self.spacer_s2_wrist_act(), "wrist_act"),
|
||||||
|
]:
|
||||||
is_top = t.endswith("_top")
|
is_top = t.endswith("_top")
|
||||||
is_parent = t.startswith("elbow")
|
is_parent = t.startswith("elbow")
|
||||||
o = self.spacer_s2_elbow() if is_parent else self.spacer_s2_wrist()
|
|
||||||
self._assembly_insert_spacer(
|
self._assembly_insert_spacer(
|
||||||
result,
|
result,
|
||||||
o.generate(),
|
o.generate(),
|
||||||
|
@ -793,7 +833,7 @@ class WingProfile(Model):
|
||||||
return profile
|
return profile
|
||||||
def surface_s3(self,
|
def surface_s3(self,
|
||||||
front: bool = True) -> Cq.Workplane:
|
front: bool = True) -> Cq.Workplane:
|
||||||
loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.child_arm_loc(flip=not self.flip)
|
loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.child_arm_loc()
|
||||||
tags = [
|
tags = [
|
||||||
("wrist_bot", self.wrist_axle_loc * loc_wrist *
|
("wrist_bot", self.wrist_axle_loc * loc_wrist *
|
||||||
Cq.Location.from2d(0, self.wrist_h2)),
|
Cq.Location.from2d(0, self.wrist_h2)),
|
||||||
|
@ -807,7 +847,7 @@ class WingProfile(Model):
|
||||||
profile = self.profile_s3_extra()
|
profile = self.profile_s3_extra()
|
||||||
if profile is None:
|
if profile is None:
|
||||||
return None
|
return None
|
||||||
loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.child_arm_loc(flip=not self.flip)
|
loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.child_arm_loc()
|
||||||
tags = [
|
tags = [
|
||||||
("wrist_bot", self.wrist_axle_loc * loc_wrist *
|
("wrist_bot", self.wrist_axle_loc * loc_wrist *
|
||||||
Cq.Location.from2d(0, self.wrist_h2)),
|
Cq.Location.from2d(0, self.wrist_h2)),
|
||||||
|
@ -929,32 +969,31 @@ class WingProfile(Model):
|
||||||
if "s1" in parts and "elbow" in parts:
|
if "s1" in parts and "elbow" in parts:
|
||||||
(
|
(
|
||||||
result
|
result
|
||||||
.constrain("s1/elbow_top?conn0", f"elbow/parent_upper/lip?conn_{tag_top}0", "Plane")
|
.constrain("s1/elbow_top?conn0", "elbow/parent_upper/lip?conn_top0", "Plane")
|
||||||
.constrain("s1/elbow_top?conn1", f"elbow/parent_upper/lip?conn_{tag_top}1", "Plane")
|
.constrain("s1/elbow_top?conn1", "elbow/parent_upper/lip?conn_top1", "Plane")
|
||||||
.constrain("s1/elbow_bot?conn0", f"elbow/parent_upper/lip?conn_{tag_bot}0", "Plane")
|
.constrain("s1/elbow_bot?conn0", "elbow/parent_upper/lip?conn_bot0", "Plane")
|
||||||
.constrain("s1/elbow_bot?conn1", f"elbow/parent_upper/lip?conn_{tag_bot}1", "Plane")
|
.constrain("s1/elbow_bot?conn1", "elbow/parent_upper/lip?conn_bot1", "Plane")
|
||||||
)
|
)
|
||||||
if "s2" in parts:
|
if "s2" in parts:
|
||||||
result.add(self.assembly_s2(), name="s2")
|
result.add(self.assembly_s2(), name="s2")
|
||||||
if "s2" in parts and "elbow" in parts:
|
if "s2" in parts and "elbow" in parts:
|
||||||
(
|
(
|
||||||
result
|
result
|
||||||
.constrain("s2/elbow_top?conn0", f"elbow/child/lip?conn_{tag_top}0", "Plane")
|
.constrain("s2/elbow_top?conn0", "elbow/child/lip?conn_top0", "Plane")
|
||||||
.constrain("s2/elbow_top?conn1", f"elbow/child/lip?conn_{tag_top}1", "Plane")
|
.constrain("s2/elbow_top?conn1", "elbow/child/lip?conn_top1", "Plane")
|
||||||
.constrain("s2/elbow_bot?conn0", f"elbow/child/lip?conn_{tag_bot}0", "Plane")
|
.constrain("s2/elbow_bot?conn0", "elbow/child/lip?conn_bot0", "Plane")
|
||||||
.constrain("s2/elbow_bot?conn1", f"elbow/child/lip?conn_{tag_bot}1", "Plane")
|
.constrain("s2/elbow_bot?conn1", "elbow/child/lip?conn_bot1", "Plane")
|
||||||
)
|
)
|
||||||
if "wrist" in parts:
|
if "wrist" in parts:
|
||||||
angle = self.wrist_joint.motion_span * elbow_wrist_deflection
|
angle = self.wrist_joint.motion_span * elbow_wrist_deflection
|
||||||
result.add(self.wrist_joint.assembly(angle=angle), name="wrist")
|
result.add(self.wrist_joint.assembly(angle=angle), name="wrist")
|
||||||
wrist_n_holes = len(self.wrist_joint.hole_pos)
|
wrist_n_holes = len(self.wrist_joint.hole_pos)
|
||||||
if "s2" in parts and "wrist" in parts:
|
if "s2" in parts and "wrist" in parts:
|
||||||
# Mounted backwards to bend in other direction
|
|
||||||
for i in range(wrist_n_holes):
|
for i in range(wrist_n_holes):
|
||||||
(
|
(
|
||||||
result
|
result
|
||||||
.constrain(f"s2/wrist_top?conn{i}", f"wrist/parent_upper/lip?conn_{tag_bot}{i}", "Plane")
|
.constrain(f"s2/wrist_top?conn{i}", f"wrist/parent_upper/lip?conn_top{i}", "Plane")
|
||||||
.constrain(f"s2/wrist_bot?conn{i}", f"wrist/parent_upper/lip?conn_{tag_top}{i}", "Plane")
|
.constrain(f"s2/wrist_bot?conn{i}", f"wrist/parent_upper/lip?conn_bot{i}", "Plane")
|
||||||
)
|
)
|
||||||
if "s3" in parts:
|
if "s3" in parts:
|
||||||
result.add(self.assembly_s3(), name="s3")
|
result.add(self.assembly_s3(), name="s3")
|
||||||
|
@ -962,8 +1001,8 @@ class WingProfile(Model):
|
||||||
for i in range(wrist_n_holes):
|
for i in range(wrist_n_holes):
|
||||||
(
|
(
|
||||||
result
|
result
|
||||||
.constrain(f"s3/wrist_top?conn{i}", f"wrist/child/lip?conn_{tag_bot}{i}", "Plane")
|
.constrain(f"s3/wrist_top?conn{i}", f"wrist/child/lip?conn_top{i}", "Plane")
|
||||||
.constrain(f"s3/wrist_bot?conn{i}", f"wrist/child/lip?conn_{tag_top}{i}", "Plane")
|
.constrain(f"s3/wrist_bot?conn{i}", f"wrist/child/lip?conn_bot{i}", "Plane")
|
||||||
)
|
)
|
||||||
if len(parts) > 1:
|
if len(parts) > 1:
|
||||||
result.solve()
|
result.solve()
|
||||||
|
@ -1167,9 +1206,11 @@ class WingL(WingProfile):
|
||||||
assert self.wrist_height <= self.shoulder_joint.height
|
assert self.wrist_height <= self.shoulder_joint.height
|
||||||
self.wrist_bot_loc = self.wrist_bot_loc.with_angle_2d(self.wrist_angle)
|
self.wrist_bot_loc = self.wrist_bot_loc.with_angle_2d(self.wrist_angle)
|
||||||
self.elbow_joint.angle_neutral = 15.0
|
self.elbow_joint.angle_neutral = 15.0
|
||||||
|
self.elbow_joint.flip = True
|
||||||
self.elbow_rotate = 5.0
|
self.elbow_rotate = 5.0
|
||||||
self.wrist_joint.angle_neutral = self.wrist_bot_loc.to2d_rot() + 30.0
|
self.wrist_joint.angle_neutral = self.wrist_bot_loc.to2d_rot() + 30.0
|
||||||
self.wrist_rotate = -self.wrist_joint.angle_neutral
|
self.wrist_rotate = -self.wrist_joint.angle_neutral
|
||||||
|
self.wrist_joint.flip = False
|
||||||
|
|
||||||
super().__post_init__()
|
super().__post_init__()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue