Skip to content

Commit 1baad44

Browse files
Add passive joint moments (#32)
* First draft of passive moments in gait2d (not working yet) * symbols qmin, qmax now added to segment constants * example_constants.yml: qmin and qmax specified in radians * example_constants.yml: corrected sign error in qminc But this is not the reason it failed. qminc would only be used when k2 is not zero, and the simulation fails when k2 is zero and k1 is not zero. --------- Co-authored-by: Jason K. Moore <moorepants@gmail.com>
1 parent 1fa38f6 commit 1baad44

5 files changed

Lines changed: 63 additions & 8 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,4 @@ docs/_build/
7878
*.i*86
7979
*.x86_64
8080
*.hex
81+

examples/example_constants.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ ib: 0.1522 # moment of inertia about mass center wrt to rthigh reference frame [
1515
xb: 0.0 # local x location of mass center wrt to the hip joint [m]
1616
yb: -0.191 # local y location of mass center wrt to the hip joint [m]
1717
lb: 0.4410 # joint to joint segment length [m]
18+
qminb: -1.5 # angle (rad) below which a quadratic passive torque is generated
19+
qmaxb: 2.8 # angle (rad) above which a quadratic passive torque is generated
1820
# rshank:
1921
mc: 3.4875 # mass [kg]
2022
ic: 0.0624 # moment of inertia about mass center wrt to rshank reference frame [kg*m^2]
2123
xc: 0.0 # x location of mass center wrt to the knee joint [m]
2224
yc: -0.1917 # y location of mass center wrt to the knee joint [m]
2325
lc: 0.4428 # joint to joint segment length [m]
26+
qminc: -2.8 # angle (rad) below which a quadratic passive torque is generated
27+
qmaxc: 0.0 # angle (rad) above which a quadratic passive torque is generated
2428
# rfoot
2529
md: 1.0875 # mass [kg]
2630
id: 0.0184 # moment of inertia about mass center wrt to rfoot reference frame [kg*m^2]
@@ -29,18 +33,24 @@ yd: -0.0351 # local y location of mass center wrt to the ankle joint [m]
2933
hxd: -0.06 # local x location of heel wrt to the ankle joint [m]
3034
txd: 0.15 # local x location of toe wrt to the ankle joint [m]
3135
fyd: -0.07 # local y location of heel and toe relative to ankle joint [m]
36+
qmind: -1.5 # angle (rad) below which a quadratic passive torque is generated
37+
qmaxd: 1.5 # angle (rad) above which a quadratic passive torque is generated
3238
# lthigh
3339
me: 7.5 # mass [kg]
3440
ie: 0.1522 # moment of inertia about mass center wrt to the lthigh reference frame[kg*m^2]
3541
xe: 0.0 # local x location of mass center wrt to the hip joint [m]
3642
ye: -0.191 # local y location of mass center wrt to the hip joint [m]
3743
le: 0.4410 # segment length [m]
44+
qmine: -1.5 # angle (rad) below which a quadratic passive torque is generated
45+
qmaxe: 2.8 # angle (rad) above which a quadratic passive torque is generated
3846
# lshank
3947
mf: 3.4875 # mass [kg]
4048
if: 0.0624 # moment of inertia about mass center wrt to the lshank reference frame [kg*m^2]
4149
xf: 0.0 # local x location of mass center wrt to the knee joint [m]
4250
yf: -0.1917 # local y location of mass center wrt to the knee joint [m]
4351
lf: 0.4428 # segment length [m]
52+
qminf: -2.8 # angle (rad) below which a quadratic passive torque is generated
53+
qmaxf: 0.0 # angle (rad) above which a quadratic passive torque is generated
4454
# lfoot
4555
mg: 1.0875 # mass [kg]
4656
ig: 0.0184 # moment of inertia about mass center wrt to the lfoot reference frame [kg*m^2]
@@ -49,6 +59,8 @@ yg: -0.0351 # local y location of mass center wrt to the ankle joint [m]
4959
hxg: -0.06 # local x location of heel wrt to the ankle joint [m]
5060
txg: 0.15 # local x location of toe wrt to the ankle joint [m]
5161
fyg: -0.07 # local y location of heel and toe relative to ankle joint [m]
62+
qming: -1.5 # angle (rad) below which a quadratic passive torque is generated
63+
qmaxg: 1.5 # angle (rad) above which a quadratic passive torque is generated
5264
# contact
5365
kc: 5.0e+7 # ground contact stiffness, N/m^3
5466
cc: 0.85 # ground contact damping, s/m

examples/plot_forward_sim.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
that the model falls down on the treadmill. It also compares the evaluation
77
speed of PyDy's and Autolev's models.
88
"""
9+
print("loading modules...")
910
import timeit
1011

1112
from algait2de.gait2de import evaluate_autolev_rhs
@@ -20,11 +21,13 @@
2021

2122
# %%
2223
# Derive the equations of motion, including a constant treadmill motion.
23-
symbolics = derive.derive_equations_of_motion(treadmill=True)
24+
print("deriving equations of motion...")
25+
# symbolics = derive.derive_equations_of_motion(treadmill=True)
26+
symbolics = derive.derive_equations_of_motion(treadmill=True, passive_torques=True)
2427

2528
# %%
2629
# Load a parameter mapping from pygait2d symbol to numerical value, as well as
27-
# a mappig of the symbol string to numerical value.
30+
# a mapping of the symbol string to numerical value.
2831
try:
2932
par_map = simulate.load_constants(symbolics.constants,
3033
'example_constants.yml')
@@ -58,7 +61,7 @@
5861
# %%
5962
# Prepare numerical arrays to be passed to the ODE functions.
6063
specifieds_vals = np.zeros(len(symbolics.specifieds))
61-
specifieds_vals[-1] = 1.0
64+
specifieds_vals[-1] = 1.0 # treadmill speed
6265

6366
args = (specifieds_vals, np.array(list(par_map.values())))
6467

@@ -86,6 +89,7 @@
8689
# Simulate the model for two seconds using the LSODA integrator (switches
8790
# between stiff and non-stiff modes).
8891
time_vector = np.linspace(0.0, 2.0, num=61)
92+
print("simulating...")
8993
trajectories = odeint(rhs, initial_conditions, time_vector, args=args)
9094

9195
# %%

pygait2d/derive.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ def derive_equations_of_motion(
339339
treadmill=False,
340340
hand_of_god=True,
341341
stiffness_exp=3,
342+
passive_torques=False,
342343
):
343344
"""Returns the equations of motion for the planar walking model along with
344345
all of the constants, coordinates, speeds, joint torques, visualization
@@ -368,6 +369,8 @@ def derive_equations_of_motion(
368369
the torso and a torque acting on the torso will be included.
369370
stiffness_exp : float, optional
370371
Exponent of the contact force stiffness force.
372+
passive_torques : boolean, optional
373+
If true, a nonlinear passive torque function is added.
371374
372375
Returns
373376
=======
@@ -420,10 +423,12 @@ def derive_equations_of_motion(
420423
for label in sorted(segment_descriptions.keys()):
421424

422425
segment_class, desc, joint_desc = segment_descriptions[label]
423-
426+
passive_torque = passive_torques # true or false for this particular segment
427+
424428
if label == 'A': # trunk
425429
parent_reference_frame = ground
426430
origin_joint = origin
431+
passive_torque = False # no passive torque between ground and trunk
427432
elif label == 'E': # left thigh
428433
# For the left thigh, set the trunk and hip as the
429434
# reference_frame and origin joint.
@@ -434,7 +439,7 @@ def derive_equations_of_motion(
434439
origin_joint = segments[-1].joint
435440

436441
segment = segment_class(label, desc, parent_reference_frame,
437-
origin_joint, joint_desc, ground)
442+
origin_joint, joint_desc, ground, passive_torque)
438443
segments.append(segment)
439444

440445
# constants, coordinates, speeds, kinematic differential equations

pygait2d/segment.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class BodySegment(object):
5757
viz_cylinder_radius = 0.035 # meters
5858

5959
def __init__(self, label, description, parent_reference_frame,
60-
origin_joint, joint_description, inertial_frame):
60+
origin_joint, joint_description, inertial_frame, passive_torque=False):
6161
"""Initializes a body segment."""
6262

6363
self.label = label
@@ -66,6 +66,7 @@ def __init__(self, label, description, parent_reference_frame,
6666
self.origin_joint = origin_joint
6767
self.joint_description = joint_description
6868
self.inertial_frame = inertial_frame
69+
self.passive_torque = passive_torque;
6970

7071
self._create_symbols()
7172
self._kinematic_differential_equations()
@@ -112,6 +113,13 @@ def _create_symbols(self):
112113
self.mass_center_x_symbol,
113114
self.mass_center_y_symbol]
114115

116+
if self.passive_torque:
117+
# we need these constants to define the passive range of motion
118+
self.qmin_symbol = symbols('qmin{}'.format(subscript), **sym_kwargs)
119+
self.qmax_symbol = symbols('qmax{}'.format(subscript), **sym_kwargs)
120+
self.constants.append(self.qmin_symbol)
121+
self.constants.append(self.qmax_symbol)
122+
115123
# functions of time
116124
self.generalized_coordinate_symbol = \
117125
time_varying('q{}'.format(subscript))
@@ -183,8 +191,33 @@ def _create_rigid_body(self):
183191

184192
def _joint_torque(self):
185193
"""Creates the joint torque vector acting on the segment."""
186-
self.torque = self.joint_torque_symbol * self.reference_frame.z
187-
# TODO : add in passive joint stiffness and damping
194+
torque = self.joint_torque_symbol
195+
196+
# add in passive joint stiffness and damping
197+
if self.passive_torque:
198+
# hard-coded parameters, these are not critical
199+
k1 = 1.0 # linear stiffness (Nm/rad)
200+
k2 = 5000.0 # quadratic stiffness (Nm/rad^2) applied when outside the qmin to qmax range
201+
b = 1.0 # linear damping (Nms/rad)
202+
203+
# turn the three terms off individually, for testing
204+
# currently, setting k1 and k2 to zero makes it work.
205+
# k1 = 0.0;
206+
# k2 = 0.0;
207+
# b = 0.0;
208+
209+
# add a weak linear stiffness and damping
210+
torque += -k1 * self.generalized_coordinate_symbol - b * self.generalized_speed_symbol
211+
212+
# add quadratic stiffness when angle is outside the range qmin to qmax
213+
qmaxdiff = self.generalized_coordinate_symbol - self.qmax_symbol
214+
qmaxpenetration = (Abs(qmaxdiff) + qmaxdiff) / 2 # this is a positive value
215+
qmindiff = self.qmin_symbol - self.generalized_coordinate_symbol
216+
qminpenetration = (Abs(qmindiff) + qmindiff) / 2 # this is a positive value
217+
torque += -k2 * (qmaxpenetration**2 - qminpenetration**2);
218+
219+
# apply this torque on the Z axis of the segment
220+
self.torque = torque * self.reference_frame.z
188221

189222
def _gravity(self):
190223
"""Creates the gravitational force vector acting on the segment."""

0 commit comments

Comments
 (0)