1919from os .path import isfile , join
2020
2121import numpy as np
22- from scipy . spatial . transform import Rotation as Rot
22+ from dm_control . utils . transformations import *
2323from pykdtree .kdtree import KDTree
2424import trimesh
2525import pyvista as pv
2626from dm_control import mjcf as mjcf_module
2727from dm_control .mujoco .wrapper import mjbindings
2828
29- from muscles import extensors_back , extensors_front , flexors_back , \
30- flexors_front , lateral , neck , tail , torso
29+ from muscles import EXTENSORS_BACK , EXTENSORS_FRONT , FLEXORS_BACK , \
30+ FLEXORS_FRONT , LATERAL , NECK , TAIL , TORSO
3131
3232from utils import array_to_string , slices2paths
3333
34- muscle_legs = extensors_back + extensors_front + \
35- flexors_back + flexors_front
34+ MUSCLE_LEGS = EXTENSORS_BACK + EXTENSORS_FRONT + \
35+ FLEXORS_BACK + FLEXORS_FRONT
3636
37- wrap_geoms_legs = [ 'shoulder_L_wrapping' , 'elbow_L_wrapping' ,
37+ WRAP_GEOMS_LEGS = ( 'shoulder_L_wrapping' , 'elbow_L_wrapping' ,
3838 'wrist_L_wrapping' , 'finger_L_wrapping' , 'hip_L_wrapping' ,
3939 'knee_L_wrapping' , 'toe_L_wrapping' ,
4040
4141 'shoulder_R_wrapping' , 'elbow_R_wrapping' ,
4242 'wrist_R_wrapping' , 'finger_R_wrapping' , 'hip_R_wrapping' ,
43- 'knee_R_wrapping' , 'toe_R_wrapping' ]
43+ 'knee_R_wrapping' , 'toe_R_wrapping' )
4444
4545
4646def getClosestGeom (kd_tree , point , mjcf , mtu ):
@@ -57,14 +57,14 @@ def getClosestGeom(kd_tree, point, mjcf, mtu):
5757 closest_geom_body: The closest geometric body (as a Mujoco body object)
5858 to the target point.
5959 """
60- dist = 100000000000
60+ dist = np . inf
6161 closest_geom_body = 0
6262 for bone , tree in kd_tree .items ():
6363 dist_new , i = tree .query (np .array ([point ]), k = 1 )
6464 geom = mjcf .find ("geom" , bone )
6565 body = geom .parent
6666
67- if mtu in muscle_legs :
67+ if mtu in MUSCLE_LEGS :
6868 if body .name not in ["upper_leg_L" ,
6969 "upper_leg_R" , "lower_leg_L" , "lower_leg_R" ,
7070 "foot_L" , "foot_R" , "toe_L" , "toe_R" ,
@@ -116,9 +116,9 @@ def calculate_transformation(element):
116116 pos = np .zeros (3 )
117117
118118 if element .quat is not None :
119- rot = Rot . from_quat (element .quat ). as_matrix ( )
119+ rot = quat_to_mat (element .get ( ' quat' ) )
120120 else :
121- rot = Rot . identity (). as_matrix ( )
121+ rot = np . eye ( 3 )
122122
123123 all_transformations .append (
124124 np .vstack (
@@ -137,11 +137,35 @@ def calculate_transformation(element):
137137
138138def add_muscles (model , scale_multiplier , muscle_dynamics ,
139139 asset_dir , lengthrange_from_joints ):
140+ """
141+ Add muscles to a Mujoco (MJCF) model.
142+
143+ This function adds muscles to a Mujoco model,
144+ creating MTUs (muscle-tendon units) and defining
145+ their properties.
146+
147+ Args:
148+ model (MJCFModel): The input Mujoco model to which muscles will be added.
149+ scale_multiplier (float): A scaling factor for muscle forces (0 to disable anatomical scaling).
150+ muscle_dynamics (str): Muscle dynamics model, either 'Millard', 'Sigmoid', or 'General'.
151+ asset_dir (str): The directory path containing muscle and bone assets.
152+ lengthrange_from_joints (bool): If True, compute length ranges from joint limits.
153+
154+ Returns:
155+ None
156+
157+ Note:
158+ - The function modifies the input `model` in place by adding muscles and related properties.
159+ - The specific muscles added depend on the provided `muscle_dynamics` and other parameters.
160+
161+ Raises:
162+ NameError: If an unsupported `muscle_dynamics` value is provided.
163+ """
140164 physics = mjcf_module .Physics .from_mjcf_model (model )
141165
142166 mjcf = model
143167
144- muscle_meshes_path = asset_dir + '/ muscles/'
168+ muscle_meshes_path = join ( asset_dir , ' muscles/')
145169 bones_path = asset_dir
146170
147171 bones = [f for f in listdir (bones_path )
@@ -171,8 +195,8 @@ def add_muscles(model, scale_multiplier, muscle_dynamics,
171195
172196 mjcf .option .timestep = 0.005
173197
174- muscles = extensors_front + flexors_front + \
175- extensors_back + flexors_back + torso + neck + tail
198+ muscles = EXTENSORS_FRONT + FLEXORS_FRONT + \
199+ EXTENSORS_BACK + FLEXORS_BACK + TORSO + NECK + TAIL
176200
177201 used_muscles = []
178202 volumes = []
@@ -184,7 +208,7 @@ def add_muscles(model, scale_multiplier, muscle_dynamics,
184208 pv_mesh = pv .read (muscle_meshes_path + mtu + '.stl' )
185209 volumes .append (pv_mesh .volume )
186210 # check along which axis to slice
187- if mtu not in lateral :
211+ if mtu not in LATERAL :
188212 plane_normal = [0 , 0 , - 1 ]
189213 start = np .argmax (m .vertices [:, 2 ])
190214 end = np .argmin (m .vertices [:, 2 ])
@@ -213,9 +237,9 @@ def add_muscles(model, scale_multiplier, muscle_dynamics,
213237 used_muscles .append (mtu )
214238
215239 # print("adding spatial", spatial.name)
216- if mtu in flexors_back or mtu in flexors_front :
240+ if mtu in FLEXORS_BACK or mtu in FLEXORS_FRONT :
217241 spatial .dclass = "flexors"
218- elif mtu in extensors_back or mtu in extensors_front :
242+ elif mtu in EXTENSORS_BACK or mtu in EXTENSORS_FRONT :
219243 spatial .dclass = "extensors"
220244
221245 counter = 0 # used for site naming
@@ -229,9 +253,9 @@ def add_muscles(model, scale_multiplier, muscle_dynamics,
229253 # Add site to tendon
230254 min_dist = 0.05
231255 max_dist = 0.11
232- if mtu in tail :
256+ if mtu in TAIL :
233257 max_dist = 0.05
234- elif mtu in neck :
258+ elif mtu in NECK :
235259 min_dist = 0.11
236260 max_dist = 0.15
237261
@@ -266,28 +290,28 @@ def add_muscles(model, scale_multiplier, muscle_dynamics,
266290 # check for wrapping geoms
267291 if idx != len (paths ) - 1 :
268292 geoms = physics .named .data .geom_xpos .axes .row .names
269- dist = 100000000000
293+ dist = np . inf
270294 closest_g = None
271295 closest_geom_pos = None
272296 for g_name in geoms :
273297 if 'wrapping' in g_name :
274298 pos = physics .named .data .geom_xpos [g_name ]
275299 new_dist = np .linalg .norm (pos - point )
276- if (mtu in lateral or mtu in neck ) and \
277- g_name not in wrap_geoms_legs and \
300+ if (mtu in LATERAL or mtu in NECK ) and \
301+ g_name not in WRAP_GEOMS_LEGS and \
278302 pos [2 ] < point [2 ] and \
279303 new_dist < dist :
280304 closest_g = g_name
281305 dist = new_dist
282306 closest_geom_pos = pos
283- elif (mtu in flexors_back or
284- mtu in flexors_front or
285- mtu in extensors_front or
286- mtu in extensors_back ) and \
307+ elif (mtu in FLEXORS_BACK or
308+ mtu in FLEXORS_FRONT or
309+ mtu in EXTENSORS_FRONT or
310+ mtu in EXTENSORS_BACK ) and \
287311 pos [2 ] < point [2 ] and \
288312 dist > 0.01 and \
289313 new_dist < dist and \
290- g_name in wrap_geoms_legs :
314+ g_name in WRAP_GEOMS_LEGS :
291315 # in the legs we are interested only in wrapping
292316 # geometries that are lower than the site we
293317 # are adding
@@ -296,15 +320,15 @@ def add_muscles(model, scale_multiplier, muscle_dynamics,
296320 closest_geom_pos = pos
297321
298322 if dist < 0.1 :
299- if (mtu in flexors_back or mtu in flexors_front ) \
323+ if (mtu in FLEXORS_BACK or mtu in FLEXORS_FRONT ) \
300324 and closest_geom_pos [2 ] < point [2 ]:
301325 spatial .add ('geom' , geom = closest_g ,
302326 sidesite = closest_g + '_backward' )
303- elif (mtu in extensors_back or mtu in extensors_front ) \
327+ elif (mtu in EXTENSORS_BACK or mtu in EXTENSORS_FRONT ) \
304328 and closest_geom_pos [2 ] < point [2 ]:
305329 spatial .add ('geom' , geom = closest_g ,
306330 sidesite = closest_g + '_forward' )
307- elif mtu in neck :
331+ elif mtu in NECK :
308332 pos1 = physics .named .data .site_xpos [closest_g + '_forward' ]
309333 d1 = np .linalg .norm (pos1 - point )
310334 pos2 = physics .named .data .site_xpos [closest_g + '_backward' ]
@@ -315,7 +339,7 @@ def add_muscles(model, scale_multiplier, muscle_dynamics,
315339 else :
316340 spatial .add ('geom' , geom = closest_g ,
317341 sidesite = closest_g + '_backward' )
318- elif mtu in torso and dist < 0.05 :
342+ elif mtu in TORSO and dist < 0.05 :
319343 spatial .add ('geom' , geom = closest_g ,
320344 sidesite = closest_g + '_forward' )
321345
@@ -325,7 +349,7 @@ def add_muscles(model, scale_multiplier, muscle_dynamics,
325349 gaintype = "muscle" , biastype = "muscle" )
326350
327351 prms = [0 ] * 10
328- prms [0 ] = 0.04
352+ prms [0 ] = 0.01
329353 prms [1 ] = 0.04
330354 if muscle_dynamics == 'Millard' :
331355 muscle .dynprm = prms
0 commit comments