Skip to content

Latest commit

 

History

History
150 lines (114 loc) · 4.93 KB

migration_guide_1.0.md

File metadata and controls

150 lines (114 loc) · 4.93 KB

dm_control: 1.0.0 update guide

With 1.0.0, we changed the way dm_control uses the MuJoCo physics simulator, and migrated to new python bindings. For most users, this will require no code changes. However, some more advanced users will need to change their code slightly. Below is a list of known changes that need to be made. Please contact us if you've had to make any further changes that are not listed below.

Required changes

dm_control.mujoco.wrapper.mjbindings.types should not be used This module was specific to the previous implementation of the dm_control python bindings. For example, types.MJRRECT should be replaced with mujoco.MjrRect.

MjData.contact has changed

MjData.contact (often accessed as Physics.data.contact) used to offer an interface similar to a numpy structured array. For example, data.contact.geom1 used to be a numpy array of geom IDs.

With the recent update, MjData.contact will appear as a list of MjContact structs. Code that used to operate on the structured array will have to change. For example, the following code would get an array containing the contact distance for all contacts that involve geom_id:

contact = physics.data.contact
involves_geom = (contact.geom1 == geom_id) | (contact.geom2 == geom_id)
dists = contact[involves_geom].dist

After the upgrade:

contacts = physics.data.contact
dists = [
    c.dist for c in contacts if c.geom1 == geom_id or c.geom2 == geom_id
]

.ptr.contents will not work

Code that accesses .ptr.contents on objects such as MjvScene will need to be updated. In most cases, simply using scene instead of scene.ptr.contents will work.

Different exceptions will be thrown from MuJoCo

Code (mostly in tests) that expects dm_control.mujoco.wrapper.core.Error exceptions, will receive different exceptions, thrown by the mujoco library. These will often be ValueError (for errors caused by input parameters), or mujoco.FatalError (for low level errors in MuJoCo).

Better error handling

The Python interpreter no longer crashes out when mju_error is called. Instead, mju_error calls are translated into mujoco.FatalError exceptions in Python.

When Python callables are used as user-defined MuJoCo callbacks, they are now permitted to raise exceptions, which will be correctly propagated back down the Python call stack.

Change of signature for mj_saveModel

mj_saveModel now expects a numpy uint8 array rather than a ctypes string buffer, and doesn't require a "size" parameter (it's inferred from the numpy array size).

Before:

model_size = mjlib.mj_sizeModel(model.ptr)
buf = ctypes.create_string_buffer(model_size)
mjlib.mj_saveModel(model.ptr, None, buf, model_size)

After:

model_size = mujoco.mj_sizeModel(model)
buf = np.empty(model_size, np.uint8)
mjlib.mj_saveModel(model.ptr, None, buf)

Optional changes

The following are some changes that can make your code more concise, but are not required for it to continue working.

Use the mujoco module directly, instead of mjlib

Existing code that uses dm_control.mujoco.wrapper.mjbindings.mjlib can directly replace these modules with mujoco. Code that uses enums or constants from dm_control.mujoco.wrapper.mjbindings can also use mujoco, with slight type changes. All mujoco functions will accept the old enum values or the new ones.

Before:

import dm_control.mujoco.wrapper.mjbindings
mjlib = mjbindings.mjlib

mjlib.mj_objectVelocity(
    physics.model.ptr, physics.data.ptr,
    enums.mjtObj.mjOBJ_SITE,
    site_id, vel, 0)

After:

import mujoco

mujoco.mj_objectVelocity(
    physics.model.ptr, physics.data.ptr,
    mujoco.mjtObj.mjOBJ_SITE,
    site_id, vel, 0)

Assume structs are correctly initialized and memory is managed

The MuJoCo C API includes functions that manage the memory for certain structs. Those include functions that allocate memory (e.g. mj_makeModel, mj_makeData, mjv_makeScene), functions that free memory (e.g. mj_deleteModel, mj_deleteData, mjv_freeScene), and functions that reset a struct to its default value (e.g. mjv_defaultOption, mj_defaultVisual).

The new Python bindings take care of this. Wrapper classes like mujoco.MjvScene will automatically allocate memory when they're created, and release it when they're deleted, and be created with default values set.

As such, allocating and freeing functions are not available through the mujoco Python bindings. The "default" functions are still available, but in most cases the calls can simply be removed.

Before:

from dm_control.mujoco import wrapper
from dm_control.mujoco.wrapper import mjbindings
mjlib = mjbindings.mjlib

scene_option = wrapper.core.MjvOption()
mjlib.mjv_defaultOption(scene_option.ptr)

After:

from dm_control.mujoco import wrapper

scene_option = wrapper.core.MjvOption()