feat: Staggered shoulder joint

This commit is contained in:
Leni Aniva 2024-07-16 22:26:06 -07:00
parent 2a968f9446
commit c12ccf3495
Signed by: aniva
GPG Key ID: 4D9B1C8D10EA4C50
3 changed files with 81 additions and 40 deletions

View File

@ -46,15 +46,23 @@ class Parameters(Model):
Defines dimensions for the Houjuu Nue cosplay
"""
# Harness
harness: MH.Harness = field(default_factory=lambda: MH.Harness())
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(name="r1"))
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(name="r2"))
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(name="r3"))
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(
name="r1",
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
))
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(
name="r2",
))
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(
name="r3",
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
))
wing_l1: MW.WingL = field(default_factory=lambda: MW.WingL(
name="l1",
wrist_angle=-45.0,
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
))
wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL(
name="l2",
@ -63,6 +71,7 @@ class Parameters(Model):
wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL(
name="l3",
wrist_angle=0.0,
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
))
trident: MT.Trident = field(default_factory=lambda: MT.Trident())

View File

@ -14,7 +14,7 @@ TOL = 1e-6
@dataclass
class ShoulderJoint(Model):
height: float = 100.0
height: float = 60.0
torsion_joint: TorsionJoint = field(default_factory=lambda: TorsionJoint(
radius_track=18,
radius_rider=18,
@ -30,19 +30,23 @@ class ShoulderJoint(Model):
thickness=1.3,
height=7.5,
),
rider_slot_begin=0,
rider_n_slots=2,
rider_slot_span=15,
))
# On the parent side, drill vertical holes
parent_conn_hole_diam: float = 6.0
parent_conn_hole_diam: float = 4.0
# Position of the holes relative
parent_conn_hole_pos: list[float] = field(default_factory=lambda: [20, 30])
parent_conn_hole_pos: list[float] = field(default_factory=lambda: [15])
parent_lip_length: float = 40.0
parent_lip_width: float = 20.0
parent_lip_thickness: float = 8.0
parent_lip_length: float = 25.0
parent_lip_width: float = 30.0
parent_lip_thickness: float = 5.0
parent_lip_ext: float = 40.0
parent_lip_guard_height: float = 10.0
parent_lip_guard_height: float = 8.0
parent_root_wall_thickness: float = 25.4 / 16
# Measured from centre of axle
child_lip_length: float = 45.0
@ -52,13 +56,19 @@ class ShoulderJoint(Model):
child_conn_hole_pos: list[float] = field(default_factory=lambda: [25, 35])
child_core_thickness: float = 3.0
# Rotates the torsion joint to avoid collisions or for some other purpose
axis_rotate_bot: float = 225.0
axis_rotate_top: float = -225.0
@target(name="shoulder-joint/parent")
def parent(self,
root_wall_thickness: float = 25.4 / 16) -> Cq.Assembly:
directrix_id: int = 0
def __post_init__(self):
assert self.parent_lip_length * 2 < self.height
def parent(self, top: bool = False) -> Cq.Assembly:
joint = self.torsion_joint
# Thickness of the lip connecting this joint to the wing root
dz = root_wall_thickness
dz = self.parent_root_wall_thickness
assert self.parent_lip_width <= joint.radius_track * 2
assert self.parent_lip_ext > joint.radius_track
@ -86,14 +96,24 @@ class ShoulderJoint(Model):
loc_dir = Cq.Location((0,0,0), (0, 0, 1), 180)
loc_pos = Cq.Location((self.parent_lip_ext - self.parent_lip_thickness, 0, dz))
rot = -self.axis_rotate_top if top else self.axis_rotate_bot
result = (
Cq.Assembly()
.add(joint.track(), name="track")
.add(joint.track(), name="track",
loc=Cq.Location((0, 0, 0), (0, 0, 1), rot))
.add(lip_guard, name="lip_guard")
.add(lip, name="lip", loc=loc_pos * loc_dir * loc_axis)
)
return result
@target(name="parent-bot")
def parent_bot(self) -> Cq.Assembly:
return self.parent(top=False)
@target(name="parent-top")
def parent_top(self) -> Cq.Assembly:
return self.parent(top=True)
@property
def child_height(self) -> float:
"""
@ -103,7 +123,7 @@ class ShoulderJoint(Model):
joint = self.torsion_joint
return self.height - 2 * joint.total_height + 2 * joint.rider_disk_height
@target(name="shoulder-joint/child")
@target(name="child")
def child(self) -> Cq.Assembly:
"""
Creates the top/bottom shoulder child joint
@ -165,14 +185,17 @@ class ShoulderJoint(Model):
centered=(True, True, False),
combine='cut')
)
theta = self.torsion_joint.spring.angle_neutral - self.torsion_joint.rider_slot_span
loc_rotate = Cq.Location((0, 0, 0), (1, 0, 0), 180)
loc_axis_rotate_bot = Cq.Location((0, 0, 0), (0, 0, 1), self.axis_rotate_bot)
loc_axis_rotate_top = Cq.Location((0, 0, 0), (0, 0, 1), self.axis_rotate_top)
result = (
Cq.Assembly()
.add(core, name="core", loc=Cq.Location())
.add(joint.rider(rider_slot_begin=-90, reverse_directrix_label=True), name="rider_top",
loc=Cq.Location((0, 0, dh), (0, 0, 1), -90))
loc=loc_axis_rotate_top * Cq.Location((0, 0, dh), (0, 0, 1), -90) * Cq.Location((0, 0, 0), (0, 0, 1), theta))
.add(joint.rider(rider_slot_begin=180), name="rider_bot",
loc=Cq.Location((0, 0, -dh), (0, 0, 1), -90) * loc_rotate)
loc=loc_axis_rotate_bot * Cq.Location((0, 0, -dh), (0, 0, 1), -90) * loc_rotate)
.add(lip, name="lip_top",
loc=Cq.Location((0, 0, dh)))
.add(lip, name="lip_bot",
@ -181,10 +204,8 @@ class ShoulderJoint(Model):
return result
@assembly()
def assembly(self,
wing_root_wall_thickness: float = 25.4/16,
) -> Cq.Assembly:
directrix = 0
def assembly(self, deflection: float = 0) -> Cq.Assembly:
directrix = self.directrix_id
mat = Material.RESIN_TRANSPERENT
mat_spring = Material.STEEL_SPRING
result = (
@ -192,27 +213,29 @@ class ShoulderJoint(Model):
.addS(self.child(), name="child",
role=Role.CHILD, material=mat)
.constrain("child/core", "Fixed")
.addS(self.torsion_joint.spring.generate(), name="spring_top",
.addS(self.torsion_joint.spring.generate(deflection=-deflection), name="spring_top",
role=Role.DAMPING, material=mat_spring)
.addS(self.parent(wing_root_wall_thickness),
.addS(self.parent_top(),
name="parent_top",
role=Role.PARENT, material=mat)
.addS(self.torsion_joint.spring.generate(), name="spring_bot",
.addS(self.torsion_joint.spring.generate(deflection=deflection), name="spring_bot",
role=Role.DAMPING, material=mat_spring)
.addS(self.parent(wing_root_wall_thickness),
.addS(self.parent_bot(),
name="parent_bot",
role=Role.PARENT, material=mat)
)
TorsionJoint.add_constraints(result,
rider="child/rider_top",
track="parent_top/track",
spring="spring_top",
directrix=directrix)
TorsionJoint.add_constraints(result,
rider="child/rider_bot",
track="parent_bot/track",
spring="spring_bot",
directrix=directrix)
TorsionJoint.add_constraints(
result,
rider="child/rider_top",
track="parent_top/track",
spring="spring_top",
directrix=directrix)
TorsionJoint.add_constraints(
result,
rider="child/rider_bot",
track="parent_bot/track",
spring="spring_bot",
directrix=directrix)
return result.solve()

View File

@ -37,7 +37,6 @@ class WingProfile(Model):
spacer_thickness: float = 25.4 / 8
shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint(
height=60.0,
))
shoulder_width: float = 30.0
shoulder_tip_x: float = -200.0
@ -94,6 +93,16 @@ class WingProfile(Model):
self.wrist_s = math.sin(self.wrist_theta)
self.wrist_top_x, self.wrist_top_y = self.wrist_to_abs(0, self.wrist_height)
@submodel(name="shoulder-joint")
def submodel_shoulder_joint(self) -> Model:
return self.shoulder_joint
@submodel(name="elbow-joint")
def submodel_elbow_joint(self) -> Model:
return self.elbow_joint
@submodel(name="wrist-joint")
def submodel_wrist_joint(self) -> Model:
return self.wrist_joint
@property
def root_height(self) -> float:
return self.shoulder_joint.height
@ -634,9 +643,9 @@ class WingProfile(Model):
(
result
.constrain("s0/shoulder?conn_top0", "shoulder/parent_top/lip?conn0", "Plane")
.constrain("s0/shoulder?conn_top1", "shoulder/parent_top/lip?conn1", "Plane")
#.constrain("s0/shoulder?conn_top1", "shoulder/parent_top/lip?conn1", "Plane")
.constrain("s0/shoulder?conn_bot0", "shoulder/parent_bot/lip?conn0", "Plane")
.constrain("s0/shoulder?conn_bot1", "shoulder/parent_bot/lip?conn1", "Plane")
#.constrain("s0/shoulder?conn_bot1", "shoulder/parent_bot/lip?conn1", "Plane")
)
if "s1" in parts:
result.add(self.assembly_s1(), name="s1")