-
Notifications
You must be signed in to change notification settings - Fork 679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Advice modeling simple block sliding on floor #343
Comments
The model you posted loads with no issue and has only 4 DoFs (yet the error is complaining about DOF 5), so the problem is elsewhere, something about the walker that you are adding? |
Edit: see below |
Ah, in the target task this line |
Revisited w/ the composer tutorial. I compressed it down to a single file: from dm_control import composer
from dm_control.composer.observation import observable
import numpy as np
from dm_control.locomotion.arenas import floors
from dm_control import mjcf
def make_frank():
random_state = np.random.RandomState(42)
rgba = random_state.uniform([0, 0, 0, 1], [1, 1, 1, 1])
model = mjcf.RootElement()
model.compiler.angle = 'radian' # Use radians.
box = model.worldbody.add('body', pos=[0.05,0.05,0.05])
box.add(
'geom', name='torso', type='box', size=[0.05,0.05,0.05], rgba=rgba)
x = box.add("joint", axis=[1,0,0], type="slide", pos=(0,0,0))
model.actuator.add("motor", gear="100", joint=x)
# y = box.add("joint", axis=[0,1,0], type="slide", name="my", pos=(0,0,0))
# model.actuator.add("motor", gear="100", joint=y)
return model
class Creature(composer.Entity):
def _build(self):
self._model = make_frank()
def _build_observables(self):
return CreatureObservables(self)
@property
def mjcf_model(self):
return self._model
@property
def actuators(self):
return tuple(self._model.find_all('actuator'))
class CreatureObservables(composer.Observables):
@composer.observable
def joint_positions(self):
all_joints = self._entity.mjcf_model.find_all('joint')
return observable.MJCFFeature('qpos', all_joints)
@composer.observable
def joint_velocities(self):
all_joints = self._entity.mjcf_model.find_all('joint')
return observable.MJCFFeature('qvel', all_joints)
NUM_SUBSTEPS = 25
class BasicTask(composer.Task):
def __init__(self, creature):
self._creature = creature
self._arena = floors.Floor()
self._arena.add_free_entity(self._creature)
self._arena.mjcf_model.worldbody.add('light', pos=(0, 0, 4))
self._creature.observables.joint_positions.enabled = True
self._creature.observables.joint_velocities.enabled = True
self.control_timestep = NUM_SUBSTEPS * self.physics_timestep
@property
def root_entity(self):
return self._arena
def initialize_episode_mjcf(self, random_state):
pass
def initialize_episode(self, physics, random_state):
pass
def get_reward(self, physics):
return 0
def get_task():
creature = Creature()
task = BasicTask(creature)
env = composer.Environment(task, random_state=np.random.RandomState(42))
return env Some observations:
|
To try to debug further I got the arena xml at runtime: <mujoco model="floor">
<compiler boundmass="1e-05" boundinertia="1e-11" coordinate="local" angle="radian" eulerseq="xyz"/>
<option timestep="0.002" integrator="RK4" cone="elliptic" noslip_iterations="5" noslip_tolerance="0.0"/>
<visual>
<headlight ambient="0.40000000000000002 0.40000000000000002 0.40000000000000002" diffuse="0.80000000000000004 0.80000000000000004 0.80000000000000004" specular="0.10000000000000001 0.10000000000000001 0.10000000000000001"/>
<map znear="0.01"/>
<scale forcewidth="0.01" contactwidth="0.06" contactheight="0.01" jointwidth="0.01" framelength="0.3" framewidth="0.01"/>
</visual>
<default>
<default class="/"/>
<default class="unnamed_model/"/>
</default>
<asset>
<texture name="groundplane" type="2d" builtin="checker" rgb1="0.20000000000000001 0.29999999999999999 0.40000000000000002" rgb2="0.10000000000000001 0.20000000000000001 0.29999999999999999" mark="edge" markrgb="0.80000000000000004 0.80000000000000004 0.80000000000000004" width="200" height="200"/>
<material name="groundplane" class="/" texture="groundplane" texrepeat="2 2" texuniform="true" reflectance="0.2"/>
</asset>
<worldbody>
<geom name="groundplane" class="/" type="plane" size="8 8 0.25" material="groundplane"/>
<camera name="top_camera" class="/" fovy="10.058147163570894" pos="0 0 100" quat="1 0 0 0"/>
<body name="unnamed_model/">
<freejoint name="unnamed_model/"/>
<body name="unnamed_model//unnamed_body_0" pos="0.050000000000000003 0.050000000000000003 0.050000000000000003">
<geom name="unnamed_model/torso" class="unnamed_model/" type="box" size="0.050000000000000003 0.050000000000000003 0.050000000000000003" rgba="0.15601864044243652 0.15599452033620265 0.058083612168199461 1" mass="1.0"/>
<joint name="unnamed_model//unnamed_joint_0" class="unnamed_model/" type="slide" pos="0 0 0" axis="1 0 0"/>
<joint name="unnamed_model/my" class="unnamed_model/" type="slide" pos="0 0 0" axis="0 1 0"/>
</body>
</body>
<light name="//unnamed_light_0" class="/" pos="0 0 4"/>
</worldbody>
<actuator>
<motor name="unnamed_model//unnamed_actuator_0" class="unnamed_model/" gear="100" joint="unnamed_model//unnamed_joint_0"/>
<motor name="unnamed_model//unnamed_actuator_1" class="unnamed_model/" gear="100" joint="unnamed_model/my"/>
</actuator>
</mujoco> Some things I tried: changing the integrator to RK4; reducing the timestep; changing solver params. |
This is a very strange model, not clear to me what you are trying to do. Maybe if I understood your goal I could help you. You have a free body with no mass that only compiles because of the |
@yuvaltassa Sorry, that XML is the compiled one at runtime, maybe the code in the comment before that makes more sense. |
So you want the cube to have 4 DoFs? How could it rotate if it can't move up? The corners will collide with the floor. |
By "rotate on the xy plane", I just meant that the cube should be able to spin as you might spin a top — don't need to move up. Does that make sense? |
XML: <mujoco model="ice">
<compiler angle="radian"/>
<default class="root">
<joint pos='0 0 0' limited='false' armature='0' damping='0' stiffness='0'/>
</default>
<worldbody>
<body name="agent" pos="0.05 0.05 0.05">
<camera name="fake_egocentric" pos="5 0 5" xyaxes="0 -1 0 0 0 1" fovy="90" />
<joint class="root" axis="1 0 0" name="tx" pos="0 0 0" type="slide"></joint>
<joint class="root" axis="0 1 0" name="ty" pos="0 0 0" type="slide"></joint>
<geom mass="1" pos="0 0 0" rgba="0.52734375 0.8046875 0.9765625 1" size="0.05 0.05 0.05" type="box" euler="1.57 0 0"></geom>
</body>
</worldbody>
<actuator>
<motor name="motortx" gear="100" joint="tx" ></motor>
<motor name="motorty" gear="100" joint="ty"></motor>
</actuator>
</mujoco> Code: from dm_control import composer
from dm_control.composer.observation import observable
import numpy as np
from dm_control.locomotion.soccer.pitch import Pitch
from dm_control import mjcf
import os
_XML_DIRNAME = os.path.join(os.path.dirname(__file__), '../ice/')
_XML_FILENAME = 'ice.xml'
random_state = np.random.RandomState(42)
class Creature(composer.Entity):
"""A multi-legged creature derived from `composer.Entity`."""
def _build(self):
self._model = mjcf.from_path(os.path.join(_XML_DIRNAME, _XML_FILENAME))
def _build_observables(self):
return CreatureObservables(self)
@property
def mjcf_model(self):
return self._model
@property
def actuators(self):
return tuple(self._model.find_all('actuator'))
def create_root_joints(self, attachment_frame):
root_class = self._model.find('default', 'root')
root_x = attachment_frame.add(
'joint', name='root_x', type='slide', axis=[1, 0, 0], dclass=root_class)
root_y = attachment_frame.add(
'joint', name='root_y', type='slide', axis=[0, 1, 0], dclass=root_class)
# Add simple observable features for joint angles and velocities.
class CreatureObservables(composer.Observables):
@composer.observable
def joint_positions(self):
all_joints = self._entity.mjcf_model.find_all('joint')
return observable.MJCFFeature('qpos', all_joints)
@composer.observable
def joint_velocities(self):
all_joints = self._entity.mjcf_model.find_all('joint')
return observable.MJCFFeature('qvel', all_joints)
from dm_control.locomotion.arenas import floors
NUM_SUBSTEPS = 25
class BasicTask(composer.Task):
def __init__(self, creature):
self._creature = creature
self._arena = floors.Floor()
self._creature.create_root_joints(self._arena.attach(self._creature))
self._arena.mjcf_model.worldbody.add('light', pos=(0, 0, 20))
self._creature.observables.joint_positions.enabled = True
self._creature.observables.joint_velocities.enabled = True
self.control_timestep = NUM_SUBSTEPS * self.physics_timestep
@property
def root_entity(self):
return self._arena
def initialize_episode_mjcf(self, random_state):
pass
def initialize_episode(self, physics, random_state):
pass
def get_reward(self, physics):
return 0
def get_task():
creature = Creature()
task = BasicTask(creature)
env = composer.Environment(task, random_state=np.random.RandomState(42))
return env Here's what I got working for x/y direction. Admittedly, I pieced this together using the soccer example, and it'd be great to have guidance on the right way to model this. (Some confusions I had anyways: Why does this only work with the cube's geom having euler rotation 1.57 and not 0 in the axis? How exactly is the create_root_joints making things work here?) |
From your description, sounds like you want to add a hinge joint with an axis in the z-direction? Not sure what you mean about |
@yuvaltassa I tried adding such a hinge as so: <mujoco model="ice">
<compiler angle="radian"/>
<worldbody>
<body name="agent" pos="0 0 0.05">
<camera name="fake_egocentric" pos="5 0 5" xyaxes="0 -1 0 0 0 1" fovy="90" />
<joint axis="1 0 0" name="tx" pos="0 0 0" type="slide"></joint>
<joint axis="0 1 0" name="ty" pos="0 0 0" type="slide"></joint>
<joint axis="0 0 1" name="rz" pos="0 0 0" type="hinge"></joint>
<geom mass="1" pos="0 0 0" rgba="0.52734375 0.8046875 0.9765625 1" size="0.05 0.05 0.05" type="box" euler="1.57 0 0"></geom>
</body>
</worldbody>
<actuator>
<motor name="motortx" gear="100" joint="tx" ></motor>
<motor name="motorty" gear="100" joint="ty"></motor>
<motor name="motorrz" gear="10" joint="rz"></motor>
</actuator>
</mujoco> That does what I want it to by itself. But adding the floor & compiling (see code at the end) leads to this one at runtime: <mujoco model="floor">
<compiler boundmass="1e-05" boundinertia="1e-11" coordinate="local" angle="radian" eulerseq="xyz"/>
<option timestep="0.002" cone="elliptic" noslip_iterations="5" noslip_tolerance="0.0"/>
<visual>
<headlight ambient="0.40000000000000002 0.40000000000000002 0.40000000000000002" diffuse="0.80000000000000004 0.80000000000000004 0.80000000000000004" specular="0.10000000000000001 0.10000000000000001 0.10000000000000001"/>
<map znear="0.01"/>
<scale forcewidth="0.01" contactwidth="0.06" contactheight="0.01" jointwidth="0.01" framelength="0.3" framewidth="0.01"/>
</visual>
<default>
<default class="/"/>
<default class="ice/"/>
</default>
<asset>
<texture name="groundplane" type="2d" builtin="checker" rgb1="0.20000000000000001 0.29999999999999999 0.40000000000000002" rgb2="0.10000000000000001 0.20000000000000001 0.29999999999999999" mark="edge" markrgb="0.80000000000000004 0.80000000000000004 0.80000000000000004" width="200" height="200"/>
<material name="groundplane" class="/" texture="groundplane" texrepeat="2 2" texuniform="true" reflectance="0.2"/>
</asset>
<worldbody>
<geom name="groundplane" class="/" type="plane" size="8 8 0.25" material="groundplane"/>
<camera name="top_camera" class="/" fovy="10.058147163570894" pos="0 0 100" quat="1 0 0 0"/>
<body name="ice/">
<body name="ice/agent" pos="0 0 0.050000000000000003">
<camera name="ice/fake_egocentric" class="ice/" fovy="90.0" pos="5 0 5" xyaxes="0 -1 0 0 0 1"/>
<joint name="ice/tx" class="ice/" type="slide" pos="0 0 0" axis="1 0 0"/>
<joint name="ice/ty" class="ice/" type="slide" pos="0 0 0" axis="0 1 0"/>
<joint name="ice/rz" class="ice/" type="hinge" pos="0 0 0" axis="0 0 1"/>
<geom name="ice//unnamed_geom_0" class="ice/" type="box" size="0.050000000000000003 0.050000000000000003 0.050000000000000003" rgba="0.52734375 0.8046875 0.9765625 1" mass="1.0" pos="0 0 0" euler="1.5700000000000001 0 0"/>
</body>
</body>
<light name="//unnamed_light_0" class="/" pos="0 0 20"/>
</worldbody>
<actuator>
<motor name="ice/motortx" class="ice/" gear="100" joint="ice/tx"/>
<motor name="ice/motorty" class="ice/" gear="100" joint="ice/ty"/>
<motor name="ice/motorrz" class="ice/" gear="10" joint="ice/rz"/>
</actuator>
</mujoco> And here's a video when applying [0,0,1] action. I expect it to spin around the center of the cube. recording.movAnd here's a video applying [1,0,0] action. I expect it to just go directly right in this case. slide.movHere's the code I used: class Creature(composer.Entity):
def _build(self):
self._model = mjcf.from_path(os.path.join(_XML_DIRNAME, _XML_FILENAME))
def _build_observables(self):
return CreatureObservables(self)
@property
def mjcf_model(self):
return self._model
@property
def actuators(self):
return tuple(self._model.find_all('actuator'))
# Add simple observable features for joint angles and velocities.
class CreatureObservables(composer.Observables):
@composer.observable
def joint_positions(self):
all_joints = self._entity.mjcf_model.find_all('joint')
return observable.MJCFFeature('qpos', all_joints)
@composer.observable
def joint_velocities(self):
all_joints = self._entity.mjcf_model.find_all('joint')
return observable.MJCFFeature('qvel', all_joints)
from dm_control.locomotion.arenas import floors
NUM_SUBSTEPS = 25
class BasicTask(composer.Task):
def __init__(self, creature):
self._creature = creature
self._arena = floors.Floor()
self._arena.attach(self._creature)
self._arena.mjcf_model.worldbody.add('light', pos=(0, 0, 20))
self._creature.observables.joint_positions.enabled = True
self._creature.observables.joint_velocities.enabled = True
self.control_timestep = NUM_SUBSTEPS * self.physics_timestep
s = self._arena.mjcf_model.to_xml_string()
with open("./creature2.xml", "w") as f:
f.write(s)
print('done')
@property
def root_entity(self):
return self._arena
def initialize_episode_mjcf(self, random_state):
pass
def initialize_episode(self, physics, random_state):
pass
def get_reward(self, physics):
return 0
def get_task():
creature = Creature()
task = BasicTask(creature)
env = composer.Environment(task, random_state=np.random.RandomState(42))
return env |
Ok, I think this was simply due to friction and setting "condim" to 1 for both the floor & the cube gets me the behavior I was looking for! I'll try to tune it a bit. (If this is covering up something wrong, do let me know though :) ) |
I'm getting started with dm_control and am trying to model a bare bones environment: a box sliding around a floor.
To do this, I adapted from mujoco-worldgen just a box with 3 slide joints and corresponding actuators. I also use the floor arena and then edited down locomotion walker/target tasks to be as simple as possible.
XML here. Note that if I don't include joint armature = 1, then it immediately fails w/
Nan, Inf or huge value in QACC at DOF 5
at time t=0.000. When I include it though, the box does not move.Full zip of code is attached.
ice 2.zip
The text was updated successfully, but these errors were encountered: