|
| 1 | +# dm_control: 1.0.0 update guide |
| 2 | + |
| 3 | +With 1.0.0, we changed the way dm_control uses the MuJoCo physics simulator, and |
| 4 | +migrated to new python bindings. For most users, this will require no code |
| 5 | +changes. However, some more advanced users will need to change their code |
| 6 | +slightly. Below is a list of known changes that need to be made. Please contact |
| 7 | +us if you've had to make any further changes that are not listed below. |
| 8 | + |
| 9 | +## Required changes |
| 10 | + |
| 11 | +`dm_control.mujoco.wrapper.mjbindings.types` should not be used This module was |
| 12 | +specific to the previous implementation of the dm_control python bindings. For |
| 13 | +example, `types.MJRRECT` should be replaced with `mujoco.MjrRect`. |
| 14 | + |
| 15 | +### `MjData.contact` has changed |
| 16 | + |
| 17 | +`MjData.contact` (often accessed as Physics.data.contact) used to offer an |
| 18 | +interface similar to a numpy structured array. For example, `data.contact.geom1` |
| 19 | +used to be a numpy array of geom IDs. |
| 20 | + |
| 21 | +With the recent update, `MjData.contact` will appear as a list of MjContact |
| 22 | +structs. Code that used to operate on the structured array will have to change. |
| 23 | +For example, the following code would get an array containing the contact |
| 24 | +distance for all contacts that involve geom_id: |
| 25 | + |
| 26 | +``` |
| 27 | +contact = physics.data.contact |
| 28 | +involves_geom = (contact.geom1 == geom_id) | (contact.geom2 == geom_id) |
| 29 | +dists = contact[involves_geom].dist |
| 30 | +``` |
| 31 | + |
| 32 | +After the upgrade: |
| 33 | + |
| 34 | +``` |
| 35 | +contacts = physics.data.contact |
| 36 | +dists = [ |
| 37 | + c.dist for c in contacts if c.geom1 == geom_id or c.geom2 == geom_id |
| 38 | +] |
| 39 | +``` |
| 40 | + |
| 41 | +### `.ptr.contents` will not work |
| 42 | + |
| 43 | +Code that accesses `.ptr.contents` on objects such as `MjvScene` will need to be |
| 44 | +updated. In most cases, simply using `scene` instead of `scene.ptr.contents` |
| 45 | +will work. |
| 46 | + |
| 47 | +### Different exceptions will be thrown from MuJoCo |
| 48 | + |
| 49 | +Code (mostly in tests) that expects `dm_control.mujoco.wrapper.core.Error` |
| 50 | +exceptions, will receive different exceptions, thrown by the `mujoco` library. |
| 51 | +These will often be `ValueError` (for errors caused by input parameters), or |
| 52 | +`mujoco.FatalError` (for low level errors in MuJoCo). |
| 53 | + |
| 54 | +### Better error handling |
| 55 | + |
| 56 | +The Python interpreter no longer crashes out when |
| 57 | +[`mju_error`](https://mujoco.readthedocs.io/en/latest/APIreference.html#mju-error) |
| 58 | +is called. Instead, `mju_error` calls are translated into `mujoco.FatalError` |
| 59 | +exceptions in Python. |
| 60 | + |
| 61 | +When Python callables are used as user-defined MuJoCo callbacks, they are now |
| 62 | +permitted to raise exceptions, which will be correctly propagated back down the |
| 63 | +Python call stack. |
| 64 | + |
| 65 | +### Change of signature for `mj_saveModel` |
| 66 | + |
| 67 | +[`mj_saveModel`](https://mujoco.readthedocs.io/en/latest/APIreference.html#mj-savemodel) |
| 68 | +now expects a numpy `uint8` array rather than a ctypes string buffer, and |
| 69 | +doesn't require a "size" parameter (it's inferred from the numpy array size). |
| 70 | + |
| 71 | +Before: |
| 72 | +``` |
| 73 | +model_size = mjlib.mj_sizeModel(model.ptr) |
| 74 | +buf = ctypes.create_string_buffer(model_size) |
| 75 | +mjlib.mj_saveModel(model.ptr, None, buf, model_size) |
| 76 | +``` |
| 77 | + |
| 78 | +After: |
| 79 | +``` |
| 80 | +model_size = mujoco.mj_sizeModel(model) |
| 81 | +buf = np.empty(model_size, np.uint8) |
| 82 | +mjlib.mj_saveModel(model.ptr, None, buf) |
| 83 | +``` |
| 84 | + |
| 85 | +## Optional changes |
| 86 | + |
| 87 | +The following are some changes that can make your code more concise, but are not |
| 88 | +required for it to continue working. |
| 89 | + |
| 90 | +### Use the mujoco module directly, instead of mjlib |
| 91 | + |
| 92 | +Existing code that uses `dm_control.mujoco.wrapper.mjbindings.mjlib` can |
| 93 | +directly replace these modules with mujoco. Code that uses `enums` or |
| 94 | +`constants` from `dm_control.mujoco.wrapper.mjbindings` can also use mujoco, |
| 95 | +with slight type changes. All mujoco functions will accept the old enum values |
| 96 | +or the new ones. |
| 97 | + |
| 98 | +Before: |
| 99 | +``` |
| 100 | +import dm_control.mujoco.wrapper.mjbindings |
| 101 | +mjlib = mjbindings.mjlib |
| 102 | +
|
| 103 | +mjlib.mj_objectVelocity( |
| 104 | + physics.model.ptr, physics.data.ptr, |
| 105 | + enums.mjtObj.mjOBJ_SITE, |
| 106 | + site_id, vel, 0) |
| 107 | +``` |
| 108 | + |
| 109 | +After: |
| 110 | +``` |
| 111 | +import mujoco |
| 112 | +
|
| 113 | +mujoco.mj_objectVelocity( |
| 114 | + physics.model.ptr, physics.data.ptr, |
| 115 | + mujoco.mjtObj.mjOBJ_SITE, |
| 116 | + site_id, vel, 0) |
| 117 | +``` |
| 118 | + |
| 119 | +### Assume structs are correctly initialized and memory is managed |
| 120 | + |
| 121 | +The MuJoCo C API includes functions that manage the memory for certain structs. |
| 122 | +Those include functions that allocate memory (e.g. `mj_makeModel`, |
| 123 | +`mj_makeData`, `mjv_makeScene`), functions that free memory (e.g. |
| 124 | +`mj_deleteModel`, `mj_deleteData`, `mjv_freeScene`), and functions that reset a |
| 125 | +struct to its default value (e.g. `mjv_defaultOption`, `mj_defaultVisual`). |
| 126 | + |
| 127 | +The new Python bindings take care of this. Wrapper classes like |
| 128 | +`mujoco.MjvScene` will automatically allocate memory when they're created, and |
| 129 | +release it when they're deleted, and be created with default values set. |
| 130 | + |
| 131 | +As such, allocating and freeing functions are not available through the mujoco |
| 132 | +Python bindings. The "default" functions are still available, but in most cases |
| 133 | +the calls can simply be removed. |
| 134 | + |
| 135 | +Before: |
| 136 | +``` |
| 137 | +from dm_control.mujoco import wrapper |
| 138 | +from dm_control.mujoco.wrapper import mjbindings |
| 139 | +mjlib = mjbindings.mjlib |
| 140 | +
|
| 141 | +scene_option = wrapper.core.MjvOption() |
| 142 | +mjlib.mjv_defaultOption(scene_option.ptr) |
| 143 | +``` |
| 144 | + |
| 145 | +After: |
| 146 | +``` |
| 147 | +from dm_control.mujoco import wrapper |
| 148 | +
|
| 149 | +scene_option = wrapper.core.MjvOption() |
| 150 | +``` |
0 commit comments