1- # Copyright 2019 The dm_control Authors.
1+ # Copyright 2020 The dm_control Authors.
22#
33# Licensed under the Apache License, Version 2.0 (the "License");
44# you may not use this file except in compliance with the License.
1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414# ============================================================================
15-
1615"""A CMU humanoid walker."""
1716
1817from __future__ import absolute_import
2827from dm_control .composer .observation import observable
2928from dm_control .locomotion .walkers import base
3029from dm_control .locomotion .walkers import legacy_base
30+ from dm_control .locomotion .walkers import rescale
3131from dm_control .locomotion .walkers import scaled_actuators
3232from dm_control .mujoco import wrapper as mj_wrapper
3333import numpy as np
3434import six
3535from six .moves import zip
3636
37- _XML_PATH = os .path .join (os .path .dirname (__file__ ), 'assets/humanoid_CMU.xml' )
38-
37+ _XML_PATH = os .path .join (os .path .dirname (__file__ ),
38+ 'assets/humanoid_CMU_V{model_version}.xml' )
3939_WALKER_GEOM_GROUP = 2
40+ _WALKER_INVIS_GROUP = 1
4041
4142_CMU_MOCAP_JOINTS = (
4243 'lfemurrz' , 'lfemurry' , 'lfemurrx' , 'ltibiarx' , 'lfootrz' , 'lfootrx' ,
113114 PositionActuatorParams ('upperneckry' , [- 20 , 20 ], 20 ),
114115 PositionActuatorParams ('upperneckrz' , [- 20 , 20 ], 20 ),
115116]
117+ PositionActuatorParamsV2020 = collections .namedtuple (
118+ 'PositionActuatorParams' , ['name' , 'forcerange' , 'kp' , 'damping' ])
119+ _POSITION_ACTUATORS_V2020 = [
120+ PositionActuatorParamsV2020 ('headrx' , [- 40 , 40 ], 40 , 2 ),
121+ PositionActuatorParamsV2020 ('headry' , [- 40 , 40 ], 40 , 2 ),
122+ PositionActuatorParamsV2020 ('headrz' , [- 40 , 40 ], 40 , 2 ),
123+ PositionActuatorParamsV2020 ('lclaviclery' , [- 80 , 80 ], 80 , 20 ),
124+ PositionActuatorParamsV2020 ('lclaviclerz' , [- 80 , 80 ], 80 , 20 ),
125+ PositionActuatorParamsV2020 ('lfemurrx' , [- 300 , 300 ], 300 , 15 ),
126+ PositionActuatorParamsV2020 ('lfemurry' , [- 200 , 200 ], 200 , 10 ),
127+ PositionActuatorParamsV2020 ('lfemurrz' , [- 200 , 200 ], 200 , 10 ),
128+ PositionActuatorParamsV2020 ('lfingersrx' , [- 20 , 20 ], 20 , 1 ),
129+ PositionActuatorParamsV2020 ('lfootrx' , [- 120 , 120 ], 120 , 6 ),
130+ PositionActuatorParamsV2020 ('lfootrz' , [- 50 , 50 ], 50 , 3 ),
131+ PositionActuatorParamsV2020 ('lhandrx' , [- 20 , 20 ], 20 , 1 ),
132+ PositionActuatorParamsV2020 ('lhandrz' , [- 20 , 20 ], 20 , 1 ),
133+ PositionActuatorParamsV2020 ('lhumerusrx' , [- 120 , 120 ], 120 , 6 ),
134+ PositionActuatorParamsV2020 ('lhumerusry' , [- 120 , 120 ], 120 , 6 ),
135+ PositionActuatorParamsV2020 ('lhumerusrz' , [- 120 , 120 ], 120 , 6 ),
136+ PositionActuatorParamsV2020 ('lowerbackrx' , [- 300 , 300 ], 300 , 15 ),
137+ PositionActuatorParamsV2020 ('lowerbackry' , [- 180 , 180 ], 180 , 20 ),
138+ PositionActuatorParamsV2020 ('lowerbackrz' , [- 200 , 200 ], 200 , 20 ),
139+ PositionActuatorParamsV2020 ('lowerneckrx' , [- 120 , 120 ],120 , 20 ),
140+ PositionActuatorParamsV2020 ('lowerneckry' , [- 120 , 120 ],120 , 20 ),
141+ PositionActuatorParamsV2020 ('lowerneckrz' , [- 120 , 120 ],120 , 20 ),
142+ PositionActuatorParamsV2020 ('lradiusrx' , [- 90 , 90 ], 90 , 5 ),
143+ PositionActuatorParamsV2020 ('lthumbrx' , [- 20 , 20 ], 20 , 1 ),
144+ PositionActuatorParamsV2020 ('lthumbrz' , [- 20 , 20 ], 20 , 1 ),
145+ PositionActuatorParamsV2020 ('ltibiarx' , [- 160 , 160 ], 160 , 8 ),
146+ PositionActuatorParamsV2020 ('ltoesrx' , [- 20 , 20 ], 20 , 1 ),
147+ PositionActuatorParamsV2020 ('lwristry' , [- 20 , 20 ], 20 , 1 ),
148+ PositionActuatorParamsV2020 ('rclaviclery' , [- 80 , 80 ], 80 , 20 ),
149+ PositionActuatorParamsV2020 ('rclaviclerz' , [- 80 , 80 ], 80 , 20 ),
150+ PositionActuatorParamsV2020 ('rfemurrx' , [- 300 , 300 ], 300 , 15 ),
151+ PositionActuatorParamsV2020 ('rfemurry' , [- 200 , 200 ], 200 , 10 ),
152+ PositionActuatorParamsV2020 ('rfemurrz' , [- 200 , 200 ], 200 , 10 ),
153+ PositionActuatorParamsV2020 ('rfingersrx' , [- 20 , 20 ], 20 , 1 ),
154+ PositionActuatorParamsV2020 ('rfootrx' , [- 120 , 120 ], 120 , 6 ),
155+ PositionActuatorParamsV2020 ('rfootrz' , [- 50 , 50 ], 50 , 3 ),
156+ PositionActuatorParamsV2020 ('rhandrx' , [- 20 , 20 ], 20 , 1 ),
157+ PositionActuatorParamsV2020 ('rhandrz' , [- 20 , 20 ], 20 , 1 ),
158+ PositionActuatorParamsV2020 ('rhumerusrx' , [- 120 , 120 ], 120 , 6 ),
159+ PositionActuatorParamsV2020 ('rhumerusry' , [- 120 , 120 ], 120 , 6 ),
160+ PositionActuatorParamsV2020 ('rhumerusrz' , [- 120 , 120 ], 120 , 6 ),
161+ PositionActuatorParamsV2020 ('rradiusrx' , [- 90 , 90 ], 90 , 5 ),
162+ PositionActuatorParamsV2020 ('rthumbrx' , [- 20 , 20 ], 20 , 1 ),
163+ PositionActuatorParamsV2020 ('rthumbrz' , [- 20 , 20 ], 20 , 1 ),
164+ PositionActuatorParamsV2020 ('rtibiarx' , [- 160 , 160 ], 160 , 8 ),
165+ PositionActuatorParamsV2020 ('rtoesrx' , [- 20 , 20 ], 20 , 1 ),
166+ PositionActuatorParamsV2020 ('rwristry' , [- 20 , 20 ], 20 , 1 ),
167+ PositionActuatorParamsV2020 ('thoraxrx' , [- 300 , 300 ], 300 , 15 ),
168+ PositionActuatorParamsV2020 ('thoraxry' , [- 80 , 80 ], 80 , 8 ),
169+ PositionActuatorParamsV2020 ('thoraxrz' , [- 200 , 200 ], 200 , 12 ),
170+ PositionActuatorParamsV2020 ('upperbackrx' , [- 300 , 300 ], 300 , 15 ),
171+ PositionActuatorParamsV2020 ('upperbackry' , [- 80 , 80 ], 80 , 8 ),
172+ PositionActuatorParamsV2020 ('upperbackrz' , [- 200 , 200 ], 200 , 12 ),
173+ PositionActuatorParamsV2020 ('upperneckrx' , [- 60 , 60 ], 60 , 10 ),
174+ PositionActuatorParamsV2020 ('upperneckry' , [- 60 , 60 ], 60 , 10 ),
175+ PositionActuatorParamsV2020 ('upperneckrz' , [- 60 , 60 ], 60 , 10 ),
176+ ]
177+
116178# pylint: enable=bad-whitespace
117179
118180_UPRIGHT_POS = (0.0 , 0.0 , 0.94 )
@@ -131,6 +193,7 @@ class _CMUHumanoidBase(legacy_base.Walker):
131193 def _build (self ,
132194 name = 'walker' ,
133195 marker_rgba = None ,
196+ include_face = False ,
134197 initializer = None ):
135198 self ._mjcf_root = mjcf .from_path (self ._xml_path )
136199 if name :
@@ -146,6 +209,24 @@ def _build(self,
146209
147210 super (_CMUHumanoidBase , self )._build (initializer = initializer )
148211
212+ if include_face :
213+ head = self ._mjcf_root .find ('body' , 'head' )
214+ face_forwardness = head .pos [1 ]- .02
215+ head_geom = self ._mjcf_root .find ('geom' , 'head' )
216+ nose_size = head_geom .size [0 ] / 4.75
217+ face = head .add (
218+ 'body' , name = 'face' , pos = (0.0 , 0.039 , face_forwardness ))
219+ face .add ('geom' ,
220+ type = 'capsule' ,
221+ name = 'nose' ,
222+ size = (nose_size , 0.01 ),
223+ pos = (0.0 , 0.0 , 0.0 ),
224+ quat = (1 , 0.7 , 0 , 0 ),
225+ mass = 0. ,
226+ contype = 0 ,
227+ conaffinity = 0 ,
228+ group = _WALKER_INVIS_GROUP )
229+
149230 def _build_observables (self ):
150231 return CMUHumanoidObservables (self )
151232
@@ -259,30 +340,56 @@ class CMUHumanoid(_CMUHumanoidBase):
259340
260341 @property
261342 def _xml_path (self ):
262- return _XML_PATH
343+ return _XML_PATH . format ( model_version = '2019' )
263344
264345
265346class CMUHumanoidPositionControlled (CMUHumanoid ):
266347 """A position-controlled CMU humanoid with control range scaled to [-1, 1]."""
267348
268- def _build (self , * args , ** kwargs ):
269- super (CMUHumanoidPositionControlled , self )._build (* args , ** kwargs )
349+ def _build (self , model_version = '2019' , ** kwargs ):
350+ self ._version = model_version
351+ if 'scale_default' in kwargs :
352+ scale_default = kwargs ['scale_default' ]
353+ del kwargs ['scale_default' ]
354+ else :
355+ scale_default = False
356+
357+ super (CMUHumanoidPositionControlled , self )._build (** kwargs )
358+
359+ if scale_default :
360+ # NOTE: This rescaling doesn't affect the attached hands
361+ rescale .rescale_humanoid (self , 1.2 , 1.2 , 70 )
362+
363+ # modify actuators
364+ if self ._version == '2020' :
365+ position_actuators = _POSITION_ACTUATORS_V2020
366+ else :
367+ position_actuators = _POSITION_ACTUATORS
270368 self ._mjcf_root .default .general .forcelimited = 'true'
271369 self ._mjcf_root .actuator .motor .clear ()
272- for actuator_params in _POSITION_ACTUATORS :
370+ for actuator_params in position_actuators :
273371 associated_joint = self ._mjcf_root .find ('joint' , actuator_params .name )
274- scaled_actuators .add_position_actuator (
372+ if hasattr (actuator_params , 'damping' ):
373+ associated_joint .damping = actuator_params .damping
374+ actuator = scaled_actuators .add_position_actuator (
275375 name = actuator_params .name ,
276376 target = associated_joint ,
277377 kp = actuator_params .kp ,
278378 qposrange = associated_joint .range ,
279379 ctrlrange = (- 1 , 1 ),
280380 forcerange = actuator_params .forcerange )
381+ if self ._version == '2020' :
382+ actuator .dyntype = 'filter'
383+ actuator .dynprm = [0.030 ]
281384 limits = zip (* (actuator .joint .range for actuator in self .actuators )) # pylint: disable=not-an-iterable
282385 lower , upper = (np .array (limit ) for limit in limits )
283386 self ._scale = upper - lower
284387 self ._offset = upper + lower
285388
389+ @property
390+ def _xml_path (self ):
391+ return _XML_PATH .format (model_version = self ._version )
392+
286393 def cmu_pose_to_actuation (self , target_pose ):
287394 """Creates the control signal corresponding a CMU mocap joints pose.
288395
@@ -300,6 +407,14 @@ def cmu_pose_to_actuation(self, target_pose):
300407 return (2 * target_pose [self .actuator_order ] - self ._offset ) / self ._scale
301408
302409
410+ class CMUHumanoidPositionControlledV2020 (CMUHumanoidPositionControlled ):
411+ """A 2020 updated CMU humanoid walker; includes nose for head orientation."""
412+
413+ def _build (self , ** kwargs ):
414+ super (CMUHumanoidPositionControlledV2020 , self )._build (
415+ model_version = '2020' , scale_default = True , include_face = True , ** kwargs )
416+
417+
303418class CMUHumanoidObservables (legacy_base .WalkerObservables ):
304419 """Observables for the Humanoid."""
305420
@@ -312,6 +427,15 @@ def body_camera(self):
312427 return observable .MJCFCamera (
313428 self ._entity .body_camera , width = 64 , height = 64 , scene_option = options )
314429
430+ @composer .observable
431+ def egocentric_camera (self ):
432+ options = mj_wrapper .MjvOption ()
433+
434+ # Don't render this walker's geoms.
435+ options .geomgroup [_WALKER_INVIS_GROUP ] = 0
436+ return observable .MJCFCamera (self ._entity .egocentric_camera ,
437+ width = 64 , height = 64 , scene_option = options )
438+
315439 @composer .observable
316440 def head_height (self ):
317441 return observable .MJCFFeature ('xpos' , self ._entity .head )[2 ]
0 commit comments