feat: Reduce the number of slots on shoulder
Previously every shoulder joint was the same with two slots that specify the neutral position. Experiment reveals this to be too fragile.
This commit is contained in:
parent
6c6c17ea07
commit
e73c6c0fed
|
@ -219,6 +219,8 @@ class TorsionJoint:
|
||||||
assert self.groove_radius_inner > self.spring.radius > self.radius_axle
|
assert self.groove_radius_inner > self.spring.radius > self.radius_axle
|
||||||
assert self.spring.height > self.groove_depth, "Groove is too deep"
|
assert self.spring.height > self.groove_depth, "Groove is too deep"
|
||||||
assert self.groove_depth < self.spring.height - self.spring.thickness * 2
|
assert self.groove_depth < self.spring.height - self.spring.thickness * 2
|
||||||
|
if self.rider_n_slots == 1:
|
||||||
|
assert self.rider_slot_span == 0.0, "Non-zero span is impossible with multiple riders"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total_height(self):
|
def total_height(self):
|
||||||
|
@ -373,7 +375,9 @@ class TorsionJoint:
|
||||||
)
|
)
|
||||||
theta_begin = -math.radians(rider_slot_begin)
|
theta_begin = -math.radians(rider_slot_begin)
|
||||||
theta_span = math.radians(self.rider_slot_span)
|
theta_span = math.radians(self.rider_slot_span)
|
||||||
if abs(math.remainder(self.rider_slot_span, 360)) < TOL:
|
if self.rider_n_slots <= 1:
|
||||||
|
theta_step = 0
|
||||||
|
elif abs(math.remainder(self.rider_slot_span, 360)) < TOL:
|
||||||
theta_step = theta_span / self.rider_n_slots
|
theta_step = theta_span / self.rider_n_slots
|
||||||
else:
|
else:
|
||||||
theta_step = theta_span / (self.rider_n_slots - 1)
|
theta_step = theta_span / (self.rider_n_slots - 1)
|
||||||
|
|
|
@ -50,14 +50,14 @@ class Parameters(Model):
|
||||||
|
|
||||||
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(
|
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(
|
||||||
name="r1",
|
name="r1",
|
||||||
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
|
shoulder_angle_bias = 15.0,
|
||||||
))
|
))
|
||||||
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(
|
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(
|
||||||
name="r2",
|
name="r2",
|
||||||
))
|
))
|
||||||
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(
|
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(
|
||||||
name="r3",
|
name="r3",
|
||||||
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
|
shoulder_angle_bias = 15.0,
|
||||||
))
|
))
|
||||||
wing_l1: MW.WingL = field(default_factory=lambda: MW.WingL(
|
wing_l1: MW.WingL = field(default_factory=lambda: MW.WingL(
|
||||||
name="l1",
|
name="l1",
|
||||||
|
@ -66,7 +66,7 @@ class Parameters(Model):
|
||||||
wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL(
|
wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL(
|
||||||
name="l2",
|
name="l2",
|
||||||
wrist_angle=-30.0,
|
wrist_angle=-30.0,
|
||||||
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
|
shoulder_angle_bias = 15.0,
|
||||||
))
|
))
|
||||||
wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL(
|
wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL(
|
||||||
name="l3",
|
name="l3",
|
||||||
|
@ -84,6 +84,8 @@ class Parameters(Model):
|
||||||
self.wing_l2.base_joint = self.harness.hs_hirth_joint
|
self.wing_l2.base_joint = self.harness.hs_hirth_joint
|
||||||
self.wing_l3.base_joint = self.harness.hs_hirth_joint
|
self.wing_l3.base_joint = self.harness.hs_hirth_joint
|
||||||
|
|
||||||
|
self.wing_r1.shoulder_joint.torsion_joint
|
||||||
|
|
||||||
assert self.wing_r1.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
assert self.wing_r1.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||||
assert self.wing_r2.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
assert self.wing_r2.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||||
assert self.wing_r3.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
assert self.wing_r3.hs_joint_axis_diam == self.harness.hs_joint_axis_diam
|
||||||
|
|
|
@ -32,8 +32,8 @@ class ShoulderJoint(Model):
|
||||||
height=7.5,
|
height=7.5,
|
||||||
),
|
),
|
||||||
rider_slot_begin=0,
|
rider_slot_begin=0,
|
||||||
rider_n_slots=2,
|
rider_n_slots=1,
|
||||||
rider_slot_span=15,
|
rider_slot_span=0,
|
||||||
))
|
))
|
||||||
|
|
||||||
# On the parent side, drill vertical holes
|
# On the parent side, drill vertical holes
|
||||||
|
|
|
@ -10,11 +10,21 @@ class TestJoints(unittest.TestCase):
|
||||||
j = MJ.ShoulderJoint()
|
j = MJ.ShoulderJoint()
|
||||||
assembly = j.torsion_joint.rider_track_assembly()
|
assembly = j.torsion_joint.rider_track_assembly()
|
||||||
self.assertEqual(pairwise_intersection(assembly), [])
|
self.assertEqual(pairwise_intersection(assembly), [])
|
||||||
|
|
||||||
def test_shoulder_collision_0(self):
|
def test_shoulder_collision_0(self):
|
||||||
j = MJ.ShoulderJoint()
|
j = MJ.ShoulderJoint()
|
||||||
assembly = j.assembly()
|
assembly = j.assembly()
|
||||||
self.assertEqual(pairwise_intersection(assembly), [])
|
self.assertEqual(pairwise_intersection(assembly), [])
|
||||||
|
|
||||||
|
def test_shoulder_align(self):
|
||||||
|
j = MJ.ShoulderJoint()
|
||||||
|
a = j.assembly()
|
||||||
|
l_t_c0 = a.get_abs_location("parent_top/lip?conn0")
|
||||||
|
l_b_c0 = a.get_abs_location("parent_bot/lip?conn0")
|
||||||
|
v = l_t_c0 - l_b_c0
|
||||||
|
self.assertAlmostEqual(v.x, 0)
|
||||||
|
self.assertAlmostEqual(v.y, 0)
|
||||||
|
|
||||||
def test_shoulder_joint_dist(self):
|
def test_shoulder_joint_dist(self):
|
||||||
"""
|
"""
|
||||||
Tests the arm radius
|
Tests the arm radius
|
||||||
|
|
|
@ -39,6 +39,7 @@ class WingProfile(Model):
|
||||||
|
|
||||||
shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint(
|
shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint(
|
||||||
))
|
))
|
||||||
|
shoulder_angle_bias: float = 0.0
|
||||||
shoulder_width: float = 36.0
|
shoulder_width: float = 36.0
|
||||||
shoulder_tip_x: float = -200.0
|
shoulder_tip_x: float = -200.0
|
||||||
shoulder_tip_y: float = 160.0
|
shoulder_tip_y: float = 160.0
|
||||||
|
@ -94,7 +95,7 @@ class WingProfile(Model):
|
||||||
self.elbow_top_loc = self.elbow_bot_loc * Cq.Location.from2d(0, self.elbow_height)
|
self.elbow_top_loc = self.elbow_bot_loc * Cq.Location.from2d(0, self.elbow_height)
|
||||||
self.wrist_top_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height)
|
self.wrist_top_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height)
|
||||||
|
|
||||||
self.shoulder_joint.angle_neutral = -self.shoulder_angle_neutral
|
self.shoulder_joint.angle_neutral = -self.shoulder_angle_neutral - self.shoulder_angle_bias
|
||||||
|
|
||||||
@submodel(name="shoulder-joint")
|
@submodel(name="shoulder-joint")
|
||||||
def submodel_shoulder_joint(self) -> Model:
|
def submodel_shoulder_joint(self) -> Model:
|
||||||
|
@ -287,14 +288,14 @@ class WingProfile(Model):
|
||||||
sw = self.shoulder_width
|
sw = self.shoulder_width
|
||||||
|
|
||||||
axle_dist = self.shoulder_joint.parent_lip_ext
|
axle_dist = self.shoulder_joint.parent_lip_ext
|
||||||
theta = math.radians(self.shoulder_joint.angle_neutral)
|
theta = math.radians(self.shoulder_angle_neutral)
|
||||||
c, s = math.cos(-theta), math.sin(-theta)
|
c, s = math.cos(theta), math.sin(theta)
|
||||||
tags = [
|
tags = [
|
||||||
# transforms [axle_dist, -sw/2] about the centre (tip_x, tip_y - sw/2)
|
# transforms [axle_dist, -sw/2] about the centre (tip_x, tip_y - sw/2)
|
||||||
("shoulder", Cq.Location.from2d(
|
("shoulder", Cq.Location.from2d(
|
||||||
self.shoulder_tip_x + axle_dist * c + (-sw/2) * s,
|
self.shoulder_tip_x + axle_dist * c + (-sw/2) * s,
|
||||||
self.shoulder_tip_y - sw / 2 - axle_dist * s + (-sw/2) * c,
|
self.shoulder_tip_y - sw / 2 - axle_dist * s + (-sw/2) * c,
|
||||||
self.shoulder_joint.angle_neutral)),
|
-self.shoulder_angle_neutral)),
|
||||||
("base", Cq.Location.from2d(base_dx, base_dy, 90)),
|
("base", Cq.Location.from2d(base_dx, base_dy, 90)),
|
||||||
]
|
]
|
||||||
result = extrude_with_markers(
|
result = extrude_with_markers(
|
||||||
|
|
Loading…
Reference in New Issue