From 04ba92d663a7a796de600ec1f088d93be84ee0dd Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Thu, 6 Nov 2025 12:09:59 -0800 Subject: [PATCH 01/60] Add sleep related data structures PiperOrigin-RevId: 829055431 Change-Id: I7fd12752421bc3456105ae6849a7274e36acc6a3 --- dm_control/mjcf/schema.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 7f293d5b..bb35a53a 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -95,6 +95,7 @@ + @@ -1340,6 +1341,7 @@ + From 830a3c9e3aefd186422018632e052abf1e650f66 Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" Date: Tue, 11 Nov 2025 03:08:33 -0800 Subject: [PATCH 02/60] Avoid exposing symbols from the timing library to avoid ODR issues. PiperOrigin-RevId: 830831651 Change-Id: I96bb73b9d2c317b21358a1e17abf64a61f583e78 --- dm_control/mujoco/wrapper/mujoco_timer.lds | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 dm_control/mujoco/wrapper/mujoco_timer.lds diff --git a/dm_control/mujoco/wrapper/mujoco_timer.lds b/dm_control/mujoco/wrapper/mujoco_timer.lds new file mode 100644 index 00000000..f64aa856 --- /dev/null +++ b/dm_control/mujoco/wrapper/mujoco_timer.lds @@ -0,0 +1,6 @@ +{ + global: + dm_control_mujoco_get_time; + local: + *; +}; From e3a2483574fb17fae757e48c480cc6de3937b9cb Mon Sep 17 00:00:00 2001 From: Peter Hawkins Date: Thu, 4 Dec 2025 05:59:09 -0800 Subject: [PATCH 03/60] [numpy] Replace uses of np.in1d with np.isin(...).ravel(). np.in1d is removed in NumPy 2.4. PiperOrigin-RevId: 840207834 Change-Id: I27dcc518ed3325515001ec965af12e4c81928acc --- dm_control/composer/initializers/tcp_initializer_test.py | 8 ++++---- dm_control/suite/quadruped.py | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/dm_control/composer/initializers/tcp_initializer_test.py b/dm_control/composer/initializers/tcp_initializer_test.py index 6571b7af..002ac8f6 100644 --- a/dm_control/composer/initializers/tcp_initializer_test.py +++ b/dm_control/composer/initializers/tcp_initializer_test.py @@ -53,10 +53,10 @@ def assertEntitiesInContact(self, physics, first, second): second_geom_ids = physics.bind( second.mjcf_model.find_all('geom')).element_id contact = physics.data.contact - first_to_second = (np.in1d(contact.geom1, first_geom_ids) & - np.in1d(contact.geom2, second_geom_ids)) - second_to_first = (np.in1d(contact.geom1, second_geom_ids) & - np.in1d(contact.geom2, first_geom_ids)) + first_to_second = (np.isin(contact.geom1, first_geom_ids).ravel() & + np.isin(contact.geom2, second_geom_ids).ravel()) + second_to_first = (np.isin(contact.geom1, second_geom_ids).ravel() & + np.isin(contact.geom2, first_geom_ids).ravel()) touching = contact.dist <= 0 valid_contact = touching & (first_to_second | second_to_first) self.assertTrue(np.any(valid_contact), msg='Entities are not in contact.') diff --git a/dm_control/suite/quadruped.py b/dm_control/suite/quadruped.py index f75cacf6..86fb5424 100644 --- a/dm_control/suite/quadruped.py +++ b/dm_control/suite/quadruped.py @@ -155,7 +155,9 @@ def _get_sensor_names(self, *sensor_types): try: sensor_names = self._sensor_types_to_names[sensor_types] except KeyError: - [sensor_ids] = np.where(np.in1d(self.model.sensor_type, sensor_types)) + [sensor_ids] = np.where( + np.isin(self.model.sensor_type, sensor_types).ravel() + ) sensor_names = [self.model.id2name(s_id, 'sensor') for s_id in sensor_ids] self._sensor_types_to_names[sensor_types] = sensor_names return sensor_names From 3a1fec1090989abe5a766238a38b64802708abd8 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Thu, 4 Dec 2025 08:22:05 -0800 Subject: [PATCH 04/60] Allow material default classes to define texture layers. PiperOrigin-RevId: 840254100 Change-Id: I2cbe66a74c3a1727ee57533b17fc59a565e8852e --- dm_control/mjcf/schema.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index bb35a53a..e39812fa 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -250,6 +250,14 @@ + + + + + + + + From 91d74c9f551694c7a789cf6a21da3e173d514956 Mon Sep 17 00:00:00 2001 From: Gabe Oppenheimer Date: Tue, 6 Jan 2026 09:08:49 -0800 Subject: [PATCH 05/60] Update to version 1.0.36 following the MuJoCo 3.4.0 release. PiperOrigin-RevId: 852805679 Change-Id: I78fce409d92b4879285dd030185d671fe88f53fa --- dm_control/mujoco/tutorial.ipynb | 478 +++++++++++++++---------------- requirements.txt | 2 +- setup.py | 4 +- tutorial.ipynb | 128 ++++----- 4 files changed, 306 insertions(+), 306 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index caf73cc6..3e8962f5 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -25,9 +25,9 @@ }, "cell_type": "markdown", "source": [ - "\u003e \u003cp\u003e\u003csmall\u003e\u003csmall\u003eCopyright 2021 The dm_control Authors.\u003c/small\u003e\u003c/p\u003e\n", - "\u003e \u003cp\u003e\u003csmall\u003e\u003csmall\u003eLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at \u003ca href=\"http://www.apache.org/licenses/LICENSE-2.0\"\u003ehttp://www.apache.org/licenses/LICENSE-2.0\u003c/a\u003e.\u003c/small\u003e\u003c/small\u003e\u003c/p\u003e\n", - "\u003e \u003cp\u003e\u003csmall\u003e\u003csmall\u003eUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\u003c/small\u003e\u003c/small\u003e\u003c/p\u003e" + ">

Copyright 2021 The dm_control Authors.

\n", + ">

Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

\n", + ">

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

" ] }, { @@ -38,7 +38,7 @@ "source": [ "This notebook provides an overview tutorial of the **MuJoCo** physics simulator, using the `dm_control` Python bindings. It is similar to the notebook in `dm_control/tutorial.ipynb`, but focuses on teaching MuJoCo itself, rather than the additional features provided by the Python package. \n", "\n", - "**A Colab runtime with GPU acceleration is required.** If you're using a CPU-only runtime, you can switch using the menu \"Runtime \u003e Change runtime type\"." + "**A Colab runtime with GPU acceleration is required.** If you're using a CPU-only runtime, you can switch using the menu \"Runtime > Change runtime type\"." ] }, { @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control\u003e=1.0.35\n", + "!pip install -q dm_control>=1.0.36\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", @@ -267,13 +267,13 @@ "#@title A static model {vertical-output: true}\n", "\n", "static_model = \"\"\"\n", - "\u003cmujoco\u003e\n", - " \u003cworldbody\u003e\n", - " \u003clight name=\"top\" pos=\"0 0 1\"/\u003e\n", - " \u003cgeom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/\u003e\n", - " \u003cgeom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/\u003e\n", - " \u003c/worldbody\u003e\n", - "\u003c/mujoco\u003e\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", "\"\"\"\n", "physics = mujoco.Physics.from_xml_string(static_model)\n", "pixels = physics.render()\n", @@ -310,16 +310,16 @@ "#@title A child body with a joint { vertical-output: true }\n", "\n", "swinging_body = \"\"\"\n", - "\u003cmujoco\u003e\n", - " \u003cworldbody\u003e\n", - " \u003clight name=\"top\" pos=\"0 0 1\"/\u003e\n", - " \u003cbody name=\"box_and_sphere\" euler=\"0 0 -30\"\u003e\n", - " \u003cjoint name=\"swing\" type=\"hinge\" axis=\"1 -1 0\" pos=\"-.2 -.2 -.2\"/\u003e\n", - " \u003cgeom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/\u003e\n", - " \u003cgeom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/\u003e\n", - " \u003c/body\u003e\n", - " \u003c/worldbody\u003e\n", - "\u003c/mujoco\u003e\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", "\"\"\"\n", "physics = mujoco.Physics.from_xml_string(swinging_body)\n", "# Visualize the joint axis.\n", @@ -362,9 +362,9 @@ "# Simulate and display video.\n", "frames = []\n", "physics.reset() # Reset state and time\n", - "while physics.data.time \u003c duration:\n", + "while physics.data.time < duration:\n", " physics.step()\n", - " if len(frames) \u003c physics.data.time * framerate:\n", + " if len(frames) < physics.data.time * framerate:\n", " pixels = physics.render(scene_option=scene_option)\n", " frames.append(pixels)\n", "display_video(frames, framerate)" @@ -422,7 +422,7 @@ "# Shift nearest values to the origin.\n", "depth -= depth.min()\n", "# Scale by 2 mean distances of near rays.\n", - "depth /= 2*depth[depth \u003c= 1].mean()\n", + "depth /= 2*depth[depth <= 1].mean()\n", "# Scale to [0, 255]\n", "pixels = 255*np.clip(depth, 0, 1)\n", "PIL.Image.fromarray(pixels.astype(np.uint8))" @@ -512,7 +512,7 @@ "\n", "def add_visual_capsule(scene, point1, point2, radius, rgba):\n", " \"\"\"Adds one capsule to an mjvScene.\"\"\"\n", - " if scene.ngeom \u003e= scene.maxgeom:\n", + " if scene.ngeom >= scene.maxgeom:\n", " return\n", " scene.ngeom += 1 # increment ngeom\n", " # initialise a new capsule, add it to the scene using mjv_connector\n", @@ -531,7 +531,7 @@ "\n", "def scene_callback(physics, scn):\n", " \"\"\"Draw position trace, speed modifies width and colours.\"\"\"\n", - " if len(positions) \u003e 1:\n", + " if len(positions) > 1:\n", " for i in range(len(positions)-1):\n", " rgba=np.array((np.clip(speeds[i]/10, 0, 1),\n", " np.clip(1-speeds[i]/10, 0, 1),\n", @@ -547,13 +547,13 @@ "# Simulate and display video.\n", "frames = []\n", "physics.reset() # Reset state and time\n", - "while physics.data.time \u003c duration:\n", + "while physics.data.time < duration:\n", " # append data to the traces\n", " positions.append(physics.named.data.geom_xpos[\"green_sphere\"].copy())\n", " times.append(physics.data.time)\n", " speeds.append(get_geom_speed(physics, \"green_sphere\"))\n", " physics.step()\n", - " if len(frames) \u003c physics.data.time * framerate:\n", + " if len(frames) < physics.data.time * framerate:\n", " camera = mujoco.Camera(physics, max_geom=10000,\n", " scene_callback=scene_callback)\n", " pixels = camera.render()\n", @@ -841,32 +841,32 @@ "#@title The \"tippe-top\" model{vertical-output: true}\n", "\n", "tippe_top = \"\"\"\n", - "\u003cmujoco model=\"tippe top\"\u003e\n", - " \u003coption integrator=\"RK4\"/\u003e\n", - "\n", - " \u003casset\u003e\n", - " \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n", - " rgb2=\".2 .3 .4\" width=\"300\" height=\"300\"/\u003e\n", - " \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"8 8\" reflectance=\".2\"/\u003e\n", - " \u003c/asset\u003e\n", - "\n", - " \u003cworldbody\u003e\n", - " \u003cgeom size=\".2 .2 .01\" type=\"plane\" material=\"grid\"/\u003e\n", - " \u003clight pos=\"0 0 .6\"/\u003e\n", - " \u003ccamera name=\"closeup\" pos=\"0 -.1 .07\" xyaxes=\"1 0 0 0 1 2\"/\u003e\n", - " \u003cbody name=\"top\" pos=\"0 0 .02\"\u003e\n", - " \u003cfreejoint/\u003e\n", - " \u003cgeom name=\"ball\" type=\"sphere\" size=\".02\" /\u003e\n", - " \u003cgeom name=\"stem\" type=\"cylinder\" pos=\"0 0 .02\" size=\"0.004 .008\"/\u003e\n", - " \u003cgeom name=\"ballast\" type=\"box\" size=\".023 .023 0.005\" pos=\"0 0 -.015\"\n", - " contype=\"0\" conaffinity=\"0\" group=\"3\"/\u003e\n", - " \u003c/body\u003e\n", - " \u003c/worldbody\u003e\n", - "\n", - " \u003ckeyframe\u003e\n", - " \u003ckey name=\"spinning\" qpos=\"0 0 0.02 1 0 0 0\" qvel=\"0 0 0 0 1 200\" /\u003e\n", - " \u003c/keyframe\u003e\n", - "\u003c/mujoco\u003e\n", + "\n", + " \n", "\"\"\"\n", "physics = mujoco.Physics.from_xml_string(tippe_top)\n", "PIL.Image.fromarray(physics.render(camera_id='closeup'))" @@ -881,12 +881,12 @@ "cell_type": "markdown", "source": [ "Note several new features of this model definition:\n", - "0. The free joint is added with the `\u003cfreejoint/\u003e` clause, which is similar to `\u003cjoint type=\"free\"/\u003e`, but prohibits unphysical attributes like friction or stiffness.\n", - "1. We use the `\u003coption/\u003e` clause to set the integrator to the more accurate Runge Kutta 4th order.\n", - "2. We define the floor's grid material inside the `\u003casset/\u003e` clause and reference it in the floor geom. \n", + "0. The free joint is added with the `` clause, which is similar to ``, but prohibits unphysical attributes like friction or stiffness.\n", + "1. We use the `
+ + + + + + + + + +
From 4c29bdd8a68c338aad754a015ea7ceeb0cd60676 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Wed, 28 Jan 2026 03:33:41 -0800 Subject: [PATCH 08/60] Update dm_control MJCF schema PiperOrigin-RevId: 862153466 Change-Id: Ie6f56d5417070f18455152ba8c4683827940520a --- dm_control/mjcf/schema.xml | 105 +++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 29 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index b01ad53f..13a75ce2 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -19,7 +19,7 @@ - + @@ -53,8 +53,11 @@ + + + @@ -133,6 +136,9 @@ + + + @@ -188,6 +194,7 @@ + @@ -214,6 +221,9 @@ + + + @@ -248,6 +258,8 @@ + + @@ -339,8 +351,8 @@ + - @@ -362,10 +374,8 @@ - - @@ -403,15 +413,14 @@ - - + @@ -426,8 +435,10 @@ + + @@ -449,9 +460,6 @@ - - - @@ -537,7 +545,6 @@ - @@ -666,7 +673,6 @@ - @@ -688,10 +694,8 @@ - - @@ -769,9 +773,6 @@ - - - @@ -941,6 +942,7 @@ + @@ -951,6 +953,7 @@ + @@ -970,7 +973,7 @@ - + @@ -1025,6 +1028,8 @@ + + @@ -1116,6 +1121,7 @@ + @@ -1163,6 +1169,7 @@ + @@ -1175,14 +1182,13 @@ - - + @@ -1295,6 +1301,8 @@ + + @@ -1311,14 +1319,11 @@ - - - @@ -1331,6 +1336,7 @@ + @@ -1494,6 +1500,7 @@ + @@ -1541,6 +1548,7 @@ + @@ -1553,14 +1561,13 @@ - - + @@ -1689,14 +1696,11 @@ - - - @@ -1915,7 +1919,9 @@ + + @@ -1956,7 +1962,9 @@ + + @@ -2179,7 +2187,6 @@ - @@ -2190,6 +2197,7 @@ + @@ -2315,7 +2323,9 @@ - + + + @@ -2635,6 +2645,8 @@ + + @@ -2706,6 +2718,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 78add89f160206381b321cf202ceaec8bda232a8 Mon Sep 17 00:00:00 2001 From: Saran Tunyasuvunakool Date: Fri, 6 Feb 2026 05:14:28 -0800 Subject: [PATCH 09/60] Make bindings generator ignore X macros except for mj{Model,Data}. PiperOrigin-RevId: 866412775 Change-Id: Idee7d56db469a06af3e1688bb2c4ba6362b4f727 --- dm_control/autowrap/binding_generator.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dm_control/autowrap/binding_generator.py b/dm_control/autowrap/binding_generator.py index 370a543e..38c81459 100644 --- a/dm_control/autowrap/binding_generator.py +++ b/dm_control/autowrap/binding_generator.py @@ -159,6 +159,11 @@ def parse_hints(self, xmacro_src): parser = header_parsing.XMACRO for tokens, _, _ in parser.scanString(xmacro_src): for xmacro in tokens: + if not ( + xmacro.name.startswith("MJMODEL") + or xmacro.name.startswith("MJDATA") + ): + continue for member in xmacro.members: if not hasattr(member, "name") or not member.name: continue From 3e48d13386cd225d647f0241300e8a224805adbb Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Fri, 6 Feb 2026 08:46:45 -0800 Subject: [PATCH 10/60] Add actuator and sensor delays. Fixes #1004 PiperOrigin-RevId: 866478839 Change-Id: I11fde3b1d5a2e1f85e6265e4d99a20233cf144f0 --- dm_control/mjcf/schema.xml | 214 +++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 13a75ce2..cec95c50 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1995,6 +1995,9 @@ + + + @@ -2028,6 +2031,9 @@ + + + @@ -2050,6 +2056,9 @@ + + + @@ -2077,6 +2086,9 @@ + + + @@ -2100,6 +2112,9 @@ + + + @@ -2127,6 +2142,9 @@ + + + @@ -2149,6 +2167,9 @@ + + + @@ -2175,6 +2196,9 @@ + + + @@ -2205,6 +2229,9 @@ + + + @@ -2220,6 +2247,9 @@ + + + @@ -2259,6 +2289,10 @@ + + + + @@ -2268,6 +2302,10 @@ + + + + @@ -2277,6 +2315,10 @@ + + + + @@ -2286,6 +2328,10 @@ + + + + @@ -2295,6 +2341,10 @@ + + + + @@ -2304,6 +2354,10 @@ + + + + @@ -2313,6 +2367,10 @@ + + + + @@ -2322,6 +2380,10 @@ + + + + @@ -2333,6 +2395,10 @@ + + + + @@ -2343,6 +2409,10 @@ + + + + @@ -2352,6 +2422,10 @@ + + + + @@ -2361,6 +2435,10 @@ + + + + @@ -2370,6 +2448,10 @@ + + + + @@ -2379,6 +2461,10 @@ + + + + @@ -2388,6 +2474,10 @@ + + + + @@ -2397,6 +2487,10 @@ + + + + @@ -2406,6 +2500,10 @@ + + + + @@ -2415,6 +2513,10 @@ + + + + @@ -2424,6 +2526,10 @@ + + + + @@ -2433,6 +2539,10 @@ + + + + @@ -2442,6 +2552,10 @@ + + + + @@ -2451,6 +2565,10 @@ + + + + @@ -2460,6 +2578,10 @@ + + + + @@ -2469,6 +2591,10 @@ + + + + @@ -2478,6 +2604,10 @@ + + + + @@ -2487,6 +2617,10 @@ + + + + @@ -2499,6 +2633,10 @@ + + + + @@ -2511,6 +2649,10 @@ + + + + @@ -2523,6 +2665,10 @@ + + + + @@ -2535,6 +2681,10 @@ + + + + @@ -2547,6 +2697,10 @@ + + + + @@ -2559,6 +2713,10 @@ + + + + @@ -2571,6 +2729,10 @@ + + + + @@ -2581,6 +2743,10 @@ + + + + @@ -2591,6 +2757,10 @@ + + + + @@ -2600,6 +2770,10 @@ + + + + @@ -2609,6 +2783,10 @@ + + + + @@ -2618,6 +2796,10 @@ + + + + @@ -2664,6 +2846,10 @@ + + + + @@ -2676,6 +2862,10 @@ + + + + @@ -2688,6 +2878,10 @@ + + + + @@ -2700,6 +2894,10 @@ + + + + @@ -2708,6 +2906,10 @@ + + + + @@ -2716,6 +2918,10 @@ + + + + @@ -2723,6 +2929,10 @@ + + + + @@ -2749,6 +2959,10 @@ + + + + From 53c54d83ce634efb41836f1b504c76eeb0796d62 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 10 Feb 2026 11:49:12 -0800 Subject: [PATCH 11/60] correct attribute values in flexcomp/edge/equality PiperOrigin-RevId: 868250572 Change-Id: I17e488c925eb859d465c62383f11f79dbef91f1c --- dm_control/mjcf/schema.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index cec95c50..f52db0b8 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1212,7 +1212,7 @@ - + @@ -1591,7 +1591,7 @@ - + From 80ac24d84e7aa5bfd264948416765cb79f2c6f58 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Fri, 13 Feb 2026 01:42:39 -0800 Subject: [PATCH 12/60] Update to version 1.0.37 following the MuJoCo 3.5.0 release. PiperOrigin-RevId: 869613103 Change-Id: I88675929f857b8919097ede8bdb99fd60386f93f --- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 3e8962f5..276f786f 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.36\n", + "!pip install -q dm_control>=1.0.37\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index de445e3b..34e941a2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.4.0 +mujoco==3.5.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index 615b5f26..ddaee192 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.36', + version='1.0.37', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.4.0', + 'mujoco >= 3.5.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 9d3f73c3..65370100 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.36\n", + "!pip install -q dm_control>=1.0.37\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From 87c78550f1440753f2a5ca4dabf7ce7f2409304b Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Tue, 10 Mar 2026 04:25:19 -0700 Subject: [PATCH 13/60] Introduces a new "strain" equality mode (flex_edgeequality = 3) for flexcomps with trilinear interpolation. This mode enforces constraints on the three invariants of the Green-Lagrange strain tensor at 8 Gauss quadrature points within each flex element, resulting in 24 equality constraints per flexcomp. Also fixes a bug when attaching a flex with constraints. PiperOrigin-RevId: 881349765 Change-Id: I0561aa4f62442a8ba53c96b8328110c8a27cc8a0 --- dm_control/mjcf/schema.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index f52db0b8..e715fdb9 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1909,6 +1909,16 @@ + + + + + + + + + + From 88415f23316bd1288a022cfdb5a3f356676f9f2e Mon Sep 17 00:00:00 2001 From: DeepMind Date: Tue, 10 Mar 2026 22:24:30 -0700 Subject: [PATCH 14/60] Update to version 1.0.38 following the MuJoCo 3.6.0 release. PiperOrigin-RevId: 881795567 Change-Id: I80592a40d0012de4ad60ef0757f87ed8d3364c63 --- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 276f786f..f2ec337c 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.37\n", + "!pip install -q dm_control>=1.0.38\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 34e941a2..7c130a12 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.5.0 +mujoco==3.6.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index ddaee192..29c854c1 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.37', + version='1.0.38', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.5.0', + 'mujoco >= 3.6.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 65370100..01d9f048 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.37\n", + "!pip install -q dm_control>=1.0.38\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From 1b37d0a6a2e5445acdbb4b30778f6a988e3acedc Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Mon, 16 Mar 2026 13:24:44 -0700 Subject: [PATCH 15/60] Polynomial stiffness and damping https://youtu.be/aKa3ZlEF9_Y PiperOrigin-RevId: 884607673 Change-Id: Id336e65b65a899d676fe4444d85bf31a9e8b5a6f --- dm_control/mjcf/attribute.py | 2 ++ dm_control/mjcf/schema.xml | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/dm_control/mjcf/attribute.py b/dm_control/mjcf/attribute.py index 1605f639..c2ae0b2e 100644 --- a/dm_control/mjcf/attribute.py +++ b/dm_control/mjcf/attribute.py @@ -231,6 +231,8 @@ def to_xml_string(self, prefix_root=None, return util.to_native_string(out.getvalue())[:-1] # Strip trailing space. def _check_shape(self, array): + if array.ndim == 0: + array = array.reshape(1) actual_length = array.shape[0] if len(array.shape) > 1: raise ValueError('Expect one-dimensional array: got {}'.format(array)) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index e715fdb9..53fe0b26 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -284,14 +284,14 @@ - + - + @@ -424,8 +424,8 @@ - - + + @@ -606,14 +606,14 @@ - + - + @@ -741,8 +741,8 @@ - - + + @@ -1405,7 +1405,7 @@ - + @@ -1942,7 +1942,7 @@ - + @@ -1977,7 +1977,7 @@ - + From 02b3636269aa73777cb5ca3ff9f5fb53a3b4f2ff Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Wed, 18 Mar 2026 07:58:45 -0700 Subject: [PATCH 16/60] Remove `vertcollide` attribute from flex contact. The `vertcollide` attribute in flex and flexcomp contact specifications has been removed since the next mjWarp release will support flex collisions. This attribute was previously used to enable vertex-based collisions by adding sphere geoms at flex vertices. The functionality associated with this attribute has been deprecated and removed from the XML parser, documentation, and internal data structures. Affected example XML files have also been updated. PiperOrigin-RevId: 885595503 Change-Id: Ifbfc359cf8ba174ce10e8425b32ed309a0f0a37e --- dm_control/mjcf/schema.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 53fe0b26..c0038441 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1242,7 +1242,6 @@ - @@ -1621,7 +1620,6 @@ - @@ -1765,7 +1763,6 @@ - From 1226983c2ba0f22c3db8ad11824952592c8c2182 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Fri, 20 Mar 2026 11:40:35 -0700 Subject: [PATCH 17/60] Allow actuators to add damping and armature to joint and tendon transmissions. PiperOrigin-RevId: 886899849 Change-Id: Ifbf721625d25579bb3b4ed796fee164a70f91c4c --- dm_control/mjcf/schema.xml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index c0038441..24971de0 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -440,6 +440,8 @@ + + @@ -459,6 +461,8 @@ + + @@ -471,6 +475,8 @@ + + @@ -488,6 +494,8 @@ + + @@ -502,6 +510,8 @@ + + @@ -517,6 +527,8 @@ + + @@ -530,6 +542,8 @@ + + @@ -546,6 +560,8 @@ + + @@ -753,6 +769,8 @@ + + @@ -772,6 +790,8 @@ + + @@ -783,6 +803,8 @@ + + @@ -799,6 +821,8 @@ + + @@ -812,6 +836,8 @@ + + @@ -826,6 +852,8 @@ + + @@ -838,6 +866,8 @@ + + From dace40506e5e987ad7db652d622469be6d93495c Mon Sep 17 00:00:00 2001 From: DeepMind Date: Tue, 14 Apr 2026 07:18:24 -0700 Subject: [PATCH 18/60] Update to version 1.0.39 following the MuJoCo 3.7.0 release. PiperOrigin-RevId: 899572533 Change-Id: I6553def744314a789a761156174ca01fa162d00f --- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index f2ec337c..00fa41ee 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.38\n", + "!pip install -q dm_control>=1.0.39\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 7c130a12..679cab9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.6.0 +mujoco==3.7.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index 29c854c1..9c1776bf 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.38', + version='1.0.39', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.6.0', + 'mujoco >= 3.7.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 01d9f048..bb589654 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.38\n", + "!pip install -q dm_control>=1.0.39\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From 203f4989acd50692a0a150e431c4c0d75423123f Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Fri, 17 Apr 2026 04:10:54 -0700 Subject: [PATCH 19/60] Implement multi-cell finite element method for interpolated flexes. This change introduces a `flex_cellcount` field to `mjModel` to specify the number of cells in each dimension for interpolated flexes. The stiffness computation, passive force calculation, and Jacobian derivatives are updated to operate on a per-cell basis, significantly improving performance by localizing computations to the nodes within each cell. PiperOrigin-RevId: 901216393 Change-Id: I219ff09197ba8ecb5cbf1ebfc0b00539718a33fd --- dm_control/mjcf/schema.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 24971de0..2af7658b 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1202,6 +1202,7 @@ + @@ -1771,6 +1772,8 @@ + + From 3af128b4c76a80af3c0ce3f35a80df0dcdd4d729 Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Sun, 19 Apr 2026 07:20:49 -0700 Subject: [PATCH 20/60] Refactor flex strain constraints to be per-cell. Each mjEQ_FLEXSTRAIN equality now represents a single cell within a flex. This allows for more efficient sparse Jacobian computation by only considering the degrees of freedom of the nodes within each specific cell. This change gives a speedup of about 10x on a 3x3x3 model. PiperOrigin-RevId: 902164069 Change-Id: I3fefdaceedeac1e1232672f2b76e954f2d027b2f --- dm_control/mjcf/schema.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 2af7658b..1d6e6fbe 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1947,6 +1947,8 @@ + + From 8ebe930ae04656b91ee7de41c6d1152c31f4a95e Mon Sep 17 00:00:00 2001 From: Kyle Bayes Date: Mon, 20 Apr 2026 11:59:24 -0700 Subject: [PATCH 21/60] Enable multiccd by default. PiperOrigin-RevId: 902752921 Change-Id: I491d550da92ed6768495e1a960ef91f4e9507c54 --- dm_control/entities/props/duplo/duplo2x4.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dm_control/entities/props/duplo/duplo2x4.xml b/dm_control/entities/props/duplo/duplo2x4.xml index 324502bc..77f5811e 100644 --- a/dm_control/entities/props/duplo/duplo2x4.xml +++ b/dm_control/entities/props/duplo/duplo2x4.xml @@ -1,6 +1,6 @@ From 31ae71770176115acfa3b2c4fef412abc1ee1486 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Sat, 25 Apr 2026 14:35:15 -0700 Subject: [PATCH 22/60] Update dm_control to version 1.0.40 and require MuJoCo 3.8.0 PiperOrigin-RevId: 905658580 Change-Id: Ib06b25079034226f0ad0f215294a2b1464eccf08 --- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 00fa41ee..287c4972 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.39\n", + "!pip install -q dm_control>=1.0.40\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 679cab9a..17e51a3e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.7.0 +mujoco==3.8.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index 9c1776bf..a4deab02 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.39', + version='1.0.40', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.7.0', + 'mujoco >= 3.8.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index bb589654..340e9654 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.39\n", + "!pip install -q dm_control>=1.0.40\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From a3aff57fc0052d9b6cc5f8219cdfb1d7b6e993fc Mon Sep 17 00:00:00 2001 From: Amer Elsheikh Date: Sat, 2 May 2026 09:27:47 -0700 Subject: [PATCH 23/60] Automated Code Change PiperOrigin-RevId: 909239434 Change-Id: I40cadcc67cec0841d5535b8ac9b91b656c3139be --- dm_control/blender/mujoco_exporter/testing.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dm_control/blender/mujoco_exporter/testing.py b/dm_control/blender/mujoco_exporter/testing.py index c325c38a..7df4014f 100644 --- a/dm_control/blender/mujoco_exporter/testing.py +++ b/dm_control/blender/mujoco_exporter/testing.py @@ -70,7 +70,7 @@ def build_armature( parent: Optional[Any] = None, parent_bone: Optional[str] = None, bones: Optional[Any] = None, -) -> ...: +): """TBD.""" obj = mock.MagicMock(spec=bpy.types.Object, type='ARMATURE') obj.name = name @@ -154,7 +154,8 @@ def build_mesh_object( name: str, mesh: Optional[Any] = None, parent: Optional[Any] = None, - parent_bone: Optional[str] = None) -> ...: + parent_bone: Optional[str] = None, +): """Builds a mock object with a mesh assigned to it.""" obj = mock.MagicMock(spec=bpy.types.Object, type='MESH') obj.name = name From 4314ae9fd019da7ce90bbbb225786be73ca1d3eb Mon Sep 17 00:00:00 2001 From: DeepMind Date: Mon, 11 May 2026 09:14:46 -0700 Subject: [PATCH 24/60] Update dm_control to version 1.0.41 and require MuJoCo 3.8.1 PiperOrigin-RevId: 913732675 Change-Id: I027cc7fb5a6d2623bdba7cff60d87197a184e9b2 --- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 287c4972..70918e61 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.40\n", + "!pip install -q dm_control>=1.0.41\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 17e51a3e..caa997d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.8.0 +mujoco==3.8.1 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index a4deab02..61b75f97 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.40', + version='1.0.41', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.8.0', + 'mujoco >= 3.8.1', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 340e9654..eca59673 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.40\n", + "!pip install -q dm_control>=1.0.41\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From ed295c50be5cb4648c16f3917bcf06319400ad0d Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 12 May 2026 09:43:07 -0700 Subject: [PATCH 25/60] Margin and gap redesign (breaking change) PiperOrigin-RevId: 914329812 Change-Id: I3eb2aed30f387e064656eca4506320b57727e504 --- dm_control/locomotion/props/target_sphere.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dm_control/locomotion/props/target_sphere.py b/dm_control/locomotion/props/target_sphere.py index 85ace41a..c42715ca 100644 --- a/dm_control/locomotion/props/target_sphere.py +++ b/dm_control/locomotion/props/target_sphere.py @@ -58,7 +58,7 @@ def _build(self, self._material = self._mjcf_root.asset.add( 'material', name='target_sphere', texture=self._texture) self._geom = self._mjcf_root.worldbody.add( - 'geom', type='sphere', name='geom', gap=2*radius, + 'geom', type='sphere', name='geom', margin=-2*radius, gap=2*radius, pos=[0, 0, height_above_ground], size=[radius], material=self._material) self._geom_id = -1 self._activated = False @@ -157,7 +157,7 @@ def _build(self, self._material = self._mjcf_root.asset.add( 'material', name='target_sphere_init', texture=self._texture_initial) self._geom = self._mjcf_root.worldbody.add( - 'geom', type='sphere', name='geom', gap=2*radius, + 'geom', type='sphere', name='geom', margin=-2*radius, gap=2*radius, pos=[0, 0, height_above_ground], size=[radius], material=self._material) self._geom_id = -1 From 72789ffeef50da92a13316564815167cff553f36 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Sun, 17 May 2026 16:47:20 -0700 Subject: [PATCH 26/60] Add mjENBL_DIAGEXACT for exact constraint diagonal. Fixes #2472 PiperOrigin-RevId: 916932908 Change-Id: I1328f64699a6cb0608fc39a1a2450c891701fc85 --- dm_control/mjcf/schema.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 1d6e6fbe..a70530e3 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -99,6 +99,7 @@ + From 61f9fa25403d1be713cf77b8d598d3d998db9d8c Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Thu, 21 May 2026 06:42:56 -0700 Subject: [PATCH 27/60] Rename `mjtnum.h` to `mjtype.h`, move enum types to `mjtype.h` PiperOrigin-RevId: 919020039 Change-Id: Ia8a31949f141a16c49d0e1b79134ed9df9397229 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 61b75f97..65935758 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ 'mjdata.h', 'mjmodel.h', 'mjrender.h', - 'mjtnum.h', + 'mjtype.h', 'mjui.h', 'mjvisualize.h', 'mjxmacro.h', From 3467a8f0a841a2b060f512327ea747a5b8b425fb Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 26 May 2026 05:35:15 -0700 Subject: [PATCH 28/60] Migrate `mjtByte` to `mjtBool` for boolean-valued fields. PiperOrigin-RevId: 921408093 Change-Id: Ibd9727018d23ea0b953a905c0ac80badd5915152 --- dm_control/mujoco/wrapper/core_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dm_control/mujoco/wrapper/core_test.py b/dm_control/mujoco/wrapper/core_test.py index a5251dab..3489f126 100644 --- a/dm_control/mujoco/wrapper/core_test.py +++ b/dm_control/mujoco/wrapper/core_test.py @@ -550,7 +550,8 @@ def _write_unique_values(self, attr_name, target_array): # Don't write to integer arrays since these might contain pointers. Also # don't write directly into the stack. elif (attr_name != "stack" - and not np.issubdtype(target_array.dtype, np.integer)): + and not np.issubdtype(target_array.dtype, np.integer) + and not np.issubdtype(target_array.dtype, np.bool_)): new_contents = np.arange(target_array.size, dtype=target_array.dtype) new_contents.shape = target_array.shape target_array[:] = new_contents From dd437535f83441c99533ebf1d9a05346d62dfdd3 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Wed, 27 May 2026 08:12:11 -0700 Subject: [PATCH 29/60] Update dm_control to version 1.0.42 and require MuJoCo 3.9.0 PiperOrigin-RevId: 922139632 Change-Id: Ied5d3656be84a8c5aa925a77b61e5b4ffee2ed05 --- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 70918e61..44565cbd 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.41\n", + "!pip install -q dm_control>=1.0.42\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index caa997d3..07c752b2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.8.1 +mujoco==3.9.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index 65935758..3a64bf4c 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.41', + version='1.0.42', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.8.1', + 'mujoco >= 3.9.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index eca59673..e80b1d1a 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.41\n", + "!pip install -q dm_control>=1.0.42\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From 6bd692f3d4cce77ccaf546efd6ba73c47f8fddc5 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 2 Jun 2026 17:22:15 -0700 Subject: [PATCH 30/60] Refactor `mj_fullM`. This change is part of the deprecation of `mjData.qM`. PiperOrigin-RevId: 925669464 Change-Id: I0d1eecc333bdf03de5ca7b4fa8c944c398b2bd6a --- dm_control/suite/lqr_solver.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dm_control/suite/lqr_solver.py b/dm_control/suite/lqr_solver.py index e27738cc..fe2a95bc 100644 --- a/dm_control/suite/lqr_solver.py +++ b/dm_control/suite/lqr_solver.py @@ -46,8 +46,9 @@ def solve(env): # Compute the mass matrix. mass = np.zeros((n, n)) - wrapper.mjbindings.mjlib.mj_fullM(env.physics.model.ptr, mass, - env.physics.data.qM) + wrapper.mjbindings.mjlib.mju_sym2dense( + mass, env.physics.data.ptr.M, env.physics.model.ptr.M_rownnz, + env.physics.model.ptr.M_rowadr, env.physics.model.ptr.M_colind) # Compute input matrices a, b, q and r to the DARE solvers. # State transition matrix a. From 8029d278788d7dfe76853b1085bb7b58a1677d25 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Mon, 22 Jun 2026 11:00:11 -0700 Subject: [PATCH 31/60] Update dm_control to version 1.0.43 and require MuJoCo 3.10.0 PiperOrigin-RevId: 936145029 Change-Id: Id040b4bbdf7bb9142727f2aa265c5212e8ccbed6 --- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 44565cbd..cac8c3c7 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.42\n", + "!pip install -q dm_control>=1.0.43\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 07c752b2..b05fa5ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.9.0 +mujoco==3.10.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index 3a64bf4c..92f9ee07 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.42', + version='1.0.43', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.9.0', + 'mujoco >= 3.10.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index e80b1d1a..223277d4 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.42\n", + "!pip install -q dm_control>=1.0.43\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From 61931fe34bf0a7201addfc02fa328e2a10eff406 Mon Sep 17 00:00:00 2001 From: Amer Elsheikh Date: Sun, 28 Jun 2026 05:52:48 -0700 Subject: [PATCH 32/60] Support dynamic attributes for Pyrefly in classes using HAS_DYNAMIC_ATTRIBUTES PiperOrigin-RevId: 939377284 Change-Id: I2d957e5313ce546c60ab6c1f63a688bd819217b9 --- dm_control/mujoco/wrapper/core.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dm_control/mujoco/wrapper/core.py b/dm_control/mujoco/wrapper/core.py index b73cc0d8..95fa150a 100644 --- a/dm_control/mujoco/wrapper/core.py +++ b/dm_control/mujoco/wrapper/core.py @@ -13,16 +13,16 @@ # limitations under the License. # ============================================================================ + """Main user-facing classes and utility functions for loading MuJoCo models.""" import contextlib import copy import ctypes -from typing import Union +from typing import Any, TYPE_CHECKING, Union import weakref from absl import logging - from dm_control.mujoco.wrapper import util # Some clients explicitly import core.mjlib. from dm_control.mujoco.wrapper.mjbindings import mjlib # pylint: disable=unused-import @@ -31,6 +31,7 @@ # Unused internal import: resources. + _FAKE_BINARY_FILENAME = "model.mjb" _CONTACT_ID_OUT_OF_RANGE = ( @@ -257,6 +258,13 @@ class MjModel(metaclass=_MjModelMeta): changed occasionally, although this is done explicitly by the user. """ _HAS_DYNAMIC_ATTRIBUTES = True + if TYPE_CHECKING: + + def __getattr__(self, name: str) -> Any: + ... + + def __setattr__(self, name: str, value: Any) -> None: + ... def __init__(self, model_ptr): """Creates a new MjModel instance from a mujoco.MjModel.""" @@ -447,6 +455,13 @@ class MjData(metaclass=_MjDataMeta): """ _HAS_DYNAMIC_ATTRIBUTES = True + if TYPE_CHECKING: + + def __getattr__(self, name: str) -> Any: + ... + + def __setattr__(self, name: str, value: Any) -> None: + ... def __init__(self, model_or_data: Union[MjModel, mujoco.MjData]): """Constructs a new MjData instance. From 5503e190f5b6162f8bb50e158940828e1a8b1f1b Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Fri, 3 Jul 2026 09:08:42 -0700 Subject: [PATCH 33/60] Add `body/simple` attribute to control simple body optimization. PiperOrigin-RevId: 942164766 Change-Id: I231455a7f7eeeac0aa795a33fc9f1b06aafc1494 --- dm_control/mjcf/schema.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index a70530e3..b2228c82 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1390,6 +1390,7 @@ + From 071677f2768fbd600ff850351ab67aba636fd398 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Sat, 4 Jul 2026 09:38:07 -0700 Subject: [PATCH 34/60] Remove `mjData.qM` PiperOrigin-RevId: 942520660 Change-Id: I3519696ca70bd8f18fc5fa4186b4256cba6b70b1 --- dm_control/mujoco/index_test.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/dm_control/mujoco/index_test.py b/dm_control/mujoco/index_test.py index a5d1176d..3eaeae53 100644 --- a/dm_control/mujoco/index_test.py +++ b/dm_control/mujoco/index_test.py @@ -13,8 +13,6 @@ # limitations under the License. # ============================================================================ -"""Tests for index.""" - import collections from absl.testing import absltest @@ -34,10 +32,10 @@ FIELD_REPR = { 'act': ('FieldIndexer(act):\n' '(empty)'), - 'qM': ('FieldIndexer(qM):\n' - '0 [ 0 ]\n' - '1 [ 1 ]\n' - '2 [ 2 ]'), + 'qLD': ('FieldIndexer(qLD):\n' + '0 [ 0 ]\n' + '1 [ 1 ]\n' + '2 [ 2 ]'), 'sensordata': ('FieldIndexer(sensordata):\n' '0 accelerometer [ 0 ]\n' '1 accelerometer [ 1 ]\n' @@ -270,7 +268,7 @@ def testBadIndexItems(self, bad_index_item, exception_regexp): with self.assertRaisesRegex(IndexError, exception_regexp): _ = indexer[expression] - @parameterized.parameters('act', 'qM', 'sensordata', 'xpos') # field name + @parameterized.parameters('act', 'qLD', 'sensordata', 'xpos') # field name def testFieldIndexerRepr(self, field_name): indexer = getattr(self._data_indexers, field_name) From 876635532c738c5bcd10979d8c7a61ecc55c9d3c Mon Sep 17 00:00:00 2001 From: Hana Joo Date: Wed, 8 Jul 2026 18:17:35 -0700 Subject: [PATCH 35/60] Automated Code Change PiperOrigin-RevId: 944810664 Change-Id: I8d2758378fc7827f5dff37e893dfb57f39ed3c7f --- dm_control/blender/fake_core/bpy.py | 4 +-- dm_control/blender/fake_core/mathutils.py | 2 +- .../blender/mujoco_exporter/blender_scene.py | 14 ++++---- .../blender/mujoco_exporter/mujoco_assets.py | 2 +- dm_control/locomotion/mocap/trajectory.py | 4 +-- dm_control/locomotion/mocap/walkers.py | 2 +- dm_control/locomotion/soccer/camera.py | 6 ++-- dm_control/locomotion/soccer/humanoid.py | 4 +-- .../tasks/reference_pose/tracking.py | 34 +++++++++---------- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/dm_control/blender/fake_core/bpy.py b/dm_control/blender/fake_core/bpy.py index 5ea814e3..46ddac6e 100644 --- a/dm_control/blender/fake_core/bpy.py +++ b/dm_control/blender/fake_core/bpy.py @@ -99,7 +99,7 @@ def select_set(self, _): def to_mesh(self): pass - def evaluated_get(self, _) -> types.Object: + def evaluated_get(self, _) -> types.Object: # pyrefly: ignore[bad-return] pass @property @@ -137,7 +137,7 @@ class bpy_struct: class Context: @property - def scene(self) -> types.Scene: + def scene(self) -> types.Scene: # pyrefly: ignore[bad-return] pass class Light: diff --git a/dm_control/blender/fake_core/mathutils.py b/dm_control/blender/fake_core/mathutils.py index a48c21e9..16f0c51b 100644 --- a/dm_control/blender/fake_core/mathutils.py +++ b/dm_control/blender/fake_core/mathutils.py @@ -67,7 +67,7 @@ def w(self) -> float: def __eq__(self, rhs) -> bool: if not isinstance(rhs, Vector): return False - return np.linalg.norm(self._coords - rhs._coords) < 1e-6 + return np.linalg.norm(self._coords - rhs._coords) < 1e-6 # pyrefly: ignore[bad-return] def __str__(self) -> str: return 'Vector({:.2f}, {:.2f}, {:.2f})'.format(self.x, self.y, self.z) diff --git a/dm_control/blender/mujoco_exporter/blender_scene.py b/dm_control/blender/mujoco_exporter/blender_scene.py index 3004fdfe..690bfa00 100644 --- a/dm_control/blender/mujoco_exporter/blender_scene.py +++ b/dm_control/blender/mujoco_exporter/blender_scene.py @@ -123,7 +123,7 @@ def is_none(self) -> bool: @property def is_armature(self) -> bool: return ( # pytype: disable=bad-return-type - self.native_obj + self.native_obj # pyrefly: ignore[bad-return] and self.native_obj.type == _ARMATURE and not self.native_bone ) @@ -171,7 +171,7 @@ def get_bone_local_mtx(bone: bpy.types.Bone) -> mathutils.Matrix: """Derives a local matrix of an armature bone.""" assert isinstance(bone, bpy.types.Bone) if bone.parent: - return bone.parent.matrix_local.inverted() @ bone.matrix_local + return bone.parent.matrix_local.inverted() @ bone.matrix_local # pyrefly: ignore[missing-attribute] else: return bone.matrix_local @@ -179,7 +179,7 @@ def get_object_local_mtx(obj: bpy.types.Object) -> mathutils.Matrix: """Derives a local matrix of an object, such as a mesh or armature.""" assert isinstance(obj, bpy.types.Object) if obj.parent: - local_mtx = obj.parent.matrix_world.inverted() @ obj.matrix_world + local_mtx = obj.parent.matrix_world.inverted() @ obj.matrix_world # pyrefly: ignore[missing-attribute] if obj.parent_bone: assert obj.parent.type == _ARMATURE armature = obj.parent @@ -191,9 +191,9 @@ def get_object_local_mtx(obj: bpy.types.Object) -> mathutils.Matrix: return obj.matrix_world if self.is_bone: - local_mtx = get_bone_local_mtx(self.native_bone) + local_mtx = get_bone_local_mtx(self.native_bone) # pyrefly: ignore[bad-argument-type] else: - local_mtx = get_object_local_mtx(self.native_obj) + local_mtx = get_object_local_mtx(self.native_obj) # pyrefly: ignore[bad-argument-type] rot_quat = local_mtx.to_quaternion() pos = local_mtx.translation @@ -373,8 +373,8 @@ def map_blender_tree( """Returns a list of scene objects in the breadth-first order.""" # Collect all nodes to explore - objects and bones alike assert context.scene is not None - to_explore = [ObjectRef.new_object(o) for o in context.scene.objects] - armatures = [o for o in context.scene.objects if o.type == 'ARMATURE'] + to_explore = [ObjectRef.new_object(o) for o in context.scene.objects] # pyrefly: ignore[missing-attribute] + armatures = [o for o in context.scene.objects if o.type == 'ARMATURE'] # pyrefly: ignore[missing-attribute] for armature in armatures: for bone in armature.data.bones: to_explore.append(ObjectRef.new_bone(armature, bone)) diff --git a/dm_control/blender/mujoco_exporter/mujoco_assets.py b/dm_control/blender/mujoco_exporter/mujoco_assets.py index 86b45d20..6c96453a 100644 --- a/dm_control/blender/mujoco_exporter/mujoco_assets.py +++ b/dm_control/blender/mujoco_exporter/mujoco_assets.py @@ -102,7 +102,7 @@ def mesh_asset_builder( """Exports a mesh associated with the object and creates an 'asset' node.""" mat_names = blender_scene.map_materials(lambda m: m.name, materials) twosidedness = blender_scene.map_materials( - lambda m: not m.use_backface_culling, materials + lambda m: not m.use_backface_culling, materials # pyrefly: ignore[missing-attribute] ) mat_names = mat_names or [''] twosidedness = twosidedness or [False] diff --git a/dm_control/locomotion/mocap/trajectory.py b/dm_control/locomotion/mocap/trajectory.py index 6d070acd..f28c4d1b 100644 --- a/dm_control/locomotion/mocap/trajectory.py +++ b/dm_control/locomotion/mocap/trajectory.py @@ -130,8 +130,8 @@ def _create_single_item(self, get_field_in_timestep): values = get_field_in_timestep(timestep) if i == 0: array = np.empty((len(self._proto.timesteps),) + values.shape) - array[i, :] = values - return array + array[i, :] = values # pyrefly: ignore[unbound-name] + return array # pyrefly: ignore[unbound-name] def _create_all_items(self, dictionary): for key, value in dictionary.items(): diff --git a/dm_control/locomotion/mocap/walkers.py b/dm_control/locomotion/mocap/walkers.py index a5fdbab9..afa29bd2 100644 --- a/dm_control/locomotion/mocap/walkers.py +++ b/dm_control/locomotion/mocap/walkers.py @@ -92,6 +92,6 @@ def add_marker_sites(self, walker, size=0.01, rgba=(0., 0., 1., .3), pos = np.zeros(3) sites.append( body.add( - 'site', name=str(marker_info.name), pos=pos, dclass=mocap_class)) + 'site', name=str(marker_info.name), pos=pos, dclass=mocap_class)) # pyrefly: ignore[unbound-name] walker.list_of_site_names = [site.name for site in sites] return sites diff --git a/dm_control/locomotion/soccer/camera.py b/dm_control/locomotion/soccer/camera.py index 6a3f1f85..4e6932a4 100644 --- a/dm_control/locomotion/soccer/camera.py +++ b/dm_control/locomotion/soccer/camera.py @@ -104,16 +104,16 @@ def _get_target_camera_pose(self, entity_positions): def initialize_episode(self, entity_positions): """Begin the episode with the camera set to its target pose.""" target_pose = self._get_target_camera_pose(entity_positions) - self._camera.set_pose(*target_pose) + self._camera.set_pose(*target_pose) # pyrefly: ignore[missing-attribute] def after_step(self, entity_positions): """Move camera toward its target poses.""" target_pose = self._get_target_camera_pose(entity_positions) - cur_pose = self._camera.get_pose() + cur_pose = self._camera.get_pose() # pyrefly: ignore[missing-attribute] smoothing_update_speed = self._smoothing_update_speed filtered_pose = [ target_val * smoothing_update_speed + \ current_val * (1 - smoothing_update_speed) for target_val, current_val in zip(target_pose, cur_pose) ] - self._camera.set_pose(*filtered_pose) + self._camera.set_pose(*filtered_pose) # pyrefly: ignore[missing-attribute] diff --git a/dm_control/locomotion/soccer/humanoid.py b/dm_control/locomotion/soccer/humanoid.py index e066b5b4..e1349b0a 100644 --- a/dm_control/locomotion/soccer/humanoid.py +++ b/dm_control/locomotion/soccer/humanoid.py @@ -167,12 +167,12 @@ def _build(self, # pytype: disable=signature-mismatch # overriding-parameter-c tracking_light.remove() if visual == Humanoid.Visual.JERSEY: - shirt_number = walker_id + 1 + shirt_number = walker_id + 1 # pyrefly: ignore[unsupported-operation] self._mjcf_root.asset.add( 'texture', name='skin', type='2d', - file=os.path.join(_ASSETS_PATH, f'{team}_{walker_id + 1:02d}.png')) + file=os.path.join(_ASSETS_PATH, f'{team}_{walker_id + 1:02d}.png')) # pyrefly: ignore[unbound-name, unsupported-operation] self._mjcf_root.asset.add('material', name='skin', texture='skin') self._mjcf_root.asset.add( 'skin', diff --git a/dm_control/locomotion/tasks/reference_pose/tracking.py b/dm_control/locomotion/tasks/reference_pose/tracking.py index 3c28287b..9ce8cdab 100644 --- a/dm_control/locomotion/tasks/reference_pose/tracking.py +++ b/dm_control/locomotion/tasks/reference_pose/tracking.py @@ -81,7 +81,7 @@ def _strip_reference_prefix(dictionary: Mapping[Text, Any], The dictionary with the modified keys and original values (and unchanged keys specified by keep_prefixes). """ - keep_prefixes = keep_prefixes or [] + keep_prefixes = keep_prefixes or [] # pyrefly: ignore[bad-assignment] new_dictionary = dict() for key in dictionary: if key.startswith(prefix): @@ -89,7 +89,7 @@ def _strip_reference_prefix(dictionary: Mapping[Text, Any], # note that this will not copy the underlying array. new_dictionary[key_without_prefix] = dictionary[key] else: - for keep_prefix in keep_prefixes: + for keep_prefix in keep_prefixes: # pyrefly: ignore[not-iterable] if key.startswith(keep_prefix): new_dictionary[key] = dictionary[key] @@ -269,7 +269,7 @@ def _strip_reference_prefix(self): self._clip_reference_features = _strip_reference_prefix( # pytype: disable=wrong-arg-types self._clip_reference_features, 'walker/', - keep_prefixes=self._prop_prefixes) + keep_prefixes=self._prop_prefixes) # pyrefly: ignore[bad-argument-type] positions = [] quaternions = [] @@ -315,7 +315,7 @@ def _load_reference_data(self, ref_path, proto_modifier, clip_id, start_step=clip_start_step, end_step=_MAX_END_STEP) for clip_id, clip_start_step in zip( - self._dataset.ids, self._dataset.start_steps) + self._dataset.ids, self._dataset.start_steps) # pyrefly: ignore[bad-argument-type] ] # infer clip end steps to set sampling distribution self._dataset.end_steps = tuple(clip.end_step for clip in self._all_clips) @@ -395,7 +395,7 @@ def _get_possible_starts(self): self._start_probabilities = [] dataset = self._dataset for clip_number, (start, end, weight) in enumerate( - zip(dataset.start_steps, dataset.end_steps, dataset.weights)): + zip(dataset.start_steps, dataset.end_steps, dataset.weights)): # pyrefly: ignore[bad-argument-type] # length - required lookahead - minimum number of steps last_possible_start = end - self._max_ref_step - self._min_steps @@ -458,8 +458,8 @@ def _get_clip_to_track(self, random_state: np.random.RandomState): logging.info('Loading clip %s', clip_id) self._all_clips[self._current_clip_index] = self._loader.get_trajectory( clip_id, - start_step=self._dataset.start_steps[self._current_clip_index], - end_step=self._dataset.end_steps[self._current_clip_index], + start_step=self._dataset.start_steps[self._current_clip_index], # pyrefly: ignore[unsupported-operation] + end_step=self._dataset.end_steps[self._current_clip_index], # pyrefly: ignore[unsupported-operation] zero_out_velocities=False) self._current_clip = self._all_clips[self._current_clip_index] self._clip_reference_features = self._current_clip.as_dict() @@ -469,9 +469,9 @@ def _get_clip_to_track(self, random_state: np.random.RandomState): # clip_start_step:clip_end_step. However start_step is in # [clip_start_step:clip_end_step]. Hence we subtract clip_start_step to # obtain a valid index for the reference features. - self._time_step = start_step - self._dataset.start_steps[ + self._time_step = start_step - self._dataset.start_steps[ # pyrefly: ignore[unsupported-operation] self._current_clip_index] - self._current_start_time = (start_step - self._dataset.start_steps[ + self._current_start_time = (start_step - self._dataset.start_steps[ # pyrefly: ignore[unsupported-operation] self._current_clip_index]) * self._current_clip.dt self._last_step = len( self._clip_reference_features['joints']) - self._max_ref_step - 1 @@ -879,7 +879,7 @@ def __init__( termination_error_threshold=termination_error_threshold, prop_termination_error_threshold=prop_termination_error_threshold, min_steps=min_steps, - dataset=dataset, + dataset=dataset, # pyrefly: ignore[bad-argument-type] reward_type=reward_type, physics_timestep=physics_timestep, always_init_at_clip_start=always_init_at_clip_start, @@ -956,7 +956,7 @@ def __init__(self, def _get_clip_to_track(self, random_state: np.random.RandomState): self._current_clip_index = (self._current_clip_index + 1) % self._num_clips - start_step = self._dataset.start_steps[self._current_clip_index] + start_step = self._dataset.start_steps[self._current_clip_index] # pyrefly: ignore[unsupported-operation] clip_id = self._dataset.ids[self._current_clip_index] logging.info('Showing clip %d of %d, clip id %s', self._current_clip_index+1, self._num_clips, clip_id) @@ -966,21 +966,21 @@ def _get_clip_to_track(self, random_state: np.random.RandomState): logging.info('Loading clip %s', clip_id) self._all_clips[self._current_clip_index] = self._loader.get_trajectory( clip_id, - start_step=self._dataset.start_steps[self._current_clip_index], - end_step=self._dataset.end_steps[self._current_clip_index], + start_step=self._dataset.start_steps[self._current_clip_index], # pyrefly: ignore[unsupported-operation] + end_step=self._dataset.end_steps[self._current_clip_index], # pyrefly: ignore[unsupported-operation] zero_out_velocities=False) self._current_clip = self._all_clips[self._current_clip_index] - self._clip_reference_features = self._current_clip.as_dict() + self._clip_reference_features = self._current_clip.as_dict() # pyrefly: ignore[missing-attribute] self._clip_reference_features = _strip_reference_prefix( self._clip_reference_features, 'walker/') # The reference features are already restricted to # clip_start_step:clip_end_step. However start_step is in # [clip_start_step:clip_end_step]. Hence we subtract clip_start_step to # obtain a valid index for the reference features. - self._time_step = start_step - self._dataset.start_steps[ + self._time_step = start_step - self._dataset.start_steps[ # pyrefly: ignore[unsupported-operation] self._current_clip_index] - self._current_start_time = (start_step - self._dataset.start_steps[ - self._current_clip_index]) * self._current_clip.dt + self._current_start_time = (start_step - self._dataset.start_steps[ # pyrefly: ignore[unsupported-operation] + self._current_clip_index]) * self._current_clip.dt # pyrefly: ignore[missing-attribute] self._last_step = len( self._clip_reference_features['joints']) - self._max_ref_step - 1 logging.info('Mocap %s at step %d with remaining length %d.', clip_id, From 9c72a5e02d9cb350259f1244a324ace42339648d Mon Sep 17 00:00:00 2001 From: DeepMind Date: Wed, 15 Jul 2026 02:25:31 -0700 Subject: [PATCH 36/60] Remove unneeded mjvScene argument from mjv_moveCamera. PiperOrigin-RevId: 948204736 Change-Id: I86e20c906bc13e37cca9691f11d70bf3ef5af7df --- dm_control/viewer/renderer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dm_control/viewer/renderer.py b/dm_control/viewer/renderer.py index e5d938e7..7d4a803f 100644 --- a/dm_control/viewer/renderer.py +++ b/dm_control/viewer/renderer.py @@ -481,7 +481,7 @@ def move(self, action, viewport_offset): # to be called very often, so in order to avoid the overhead, all arguments # are assumed to be valid. mujoco.mjv_moveCamera(self._model.ptr, action, viewport_offset[0], - viewport_offset[1], self._scene.ptr, self._camera.ptr) + viewport_offset[1], self._camera.ptr) def new_perturbation(self, body_id): """Creates a proxy that allows to manipulate the specified object.""" From efb896e2698c0e3d2f2016d63ff4a80cab1ed03c Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Wed, 15 Jul 2026 08:29:38 -0700 Subject: [PATCH 37/60] Preparation for MIMO actuators: split actuator counts: nu (inputs), nactuator (objects), nout (outputs). An actuator now owns a block of consecutive controls (actuator_ctrladr/ctrlnum, width defined by the actuator type) and a block of consecutive force outputs (actuator_outadr/outnum, width defined by the transmission type). Force outputs are the scalars of actuation space: one force, length, velocity and moment row each. nout = dim(actuator_force) is derived from transmission types; all current types have width 1, so all three counts coincide for every existing model and behavior is bit-exact. Array re-keying: ctrlrange/ctrllimited by nu; forcerange/forcelimited/gear/ acc0/length0/lengthrange and the moment row structure by nout; everything else per actuator. The mjModel actuator block is re-sorted by size key. Layout-breaking, not behavior-breaking: saved .mjb files are invalidated (size list changed) and recompilation is required. PiperOrigin-RevId: 948351772 Change-Id: Ib0f019e530790ac13a890abbdf5929e9d5b5e536 --- dm_control/mjcf/physics.py | 3 ++- dm_control/mujoco/index.py | 10 ++++++++-- dm_control/mujoco/wrapper/mjbindings_test.py | 4 +--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/dm_control/mjcf/physics.py b/dm_control/mjcf/physics.py index ef6a9402..8922bbf3 100644 --- a/dm_control/mjcf/physics.py +++ b/dm_control/mjcf/physics.py @@ -92,7 +92,8 @@ def _get_attributes(size_names, strip_prefixes): _ATTRIBUTES = { - 'actuator': _get_attributes(['na', 'nu'], strip_prefixes=['actuator']), + 'actuator': _get_attributes(['na', 'nu', 'nactuator', 'nout'], + strip_prefixes=['actuator']), 'body': _get_attributes(['nbody'], strip_prefixes=['body']), 'mocap_body': _get_attributes(['nbody', 'nmocap'], strip_prefixes=['body']), 'camera': _get_attributes(['ncam'], strip_prefixes=['cam']), diff --git a/dm_control/mujoco/index.py b/dm_control/mujoco/index.py index 112e4a78..76e534cc 100644 --- a/dm_control/mujoco/index.py +++ b/dm_control/mujoco/index.py @@ -219,11 +219,17 @@ def _get_size_name_to_element_names(model): # For example, the element names for "nv" axis come from "njnt". for size_name, address_field_name in _RAGGED_ADDRS.items(): donor = 'n' + address_field_name.split('_')[0] - if donor == 'nactuator': - donor = 'nu' if donor in size_name_to_element_names: size_name_to_element_names[size_name] = size_name_to_element_names[donor] + # nu (controls) and nout (force outputs) inherit actuator names from + # nactuator. For SISO models nu == nactuator == nout; for MIMO models this + # gives each control/output the name of its owning actuator. + if 'nactuator' in size_name_to_element_names: + for alias in ('nu', 'nout'): + size_name_to_element_names[alias] = ( + size_name_to_element_names['nactuator']) + # Mocap bodies are a special subset of bodies. mocap_body_names = [None] * model.nmocap for body_id, body_name in enumerate(size_name_to_element_names['nbody']): diff --git a/dm_control/mujoco/wrapper/mjbindings_test.py b/dm_control/mujoco/wrapper/mjbindings_test.py index 9dae5803..41518d3c 100644 --- a/dm_control/mujoco/wrapper/mjbindings_test.py +++ b/dm_control/mujoco/wrapper/mjbindings_test.py @@ -13,8 +13,6 @@ # limitations under the License. # ============================================================================ -"""Tests for mjbindings.""" - from absl.testing import absltest from absl.testing import parameterized from dm_control.mujoco.wrapper.mjbindings import constants @@ -27,7 +25,7 @@ class MjbindingsTest(parameterized.TestCase): ('mjdata', 'xpos', ('nbody', 3)), ('mjmodel', 'geom_type', ('ngeom',)), # Fields with identifiers in mjxmacro that are resolved at compile-time. - ('mjmodel', 'actuator_dynprm', ('nu', constants.mjNDYN)), + ('mjmodel', 'actuator_dynprm', ('nactuator', constants.mjNDYN)), # Fields with multiple named indices. ('mjmodel', 'key_qpos', ('nkey', 'nq')), ) From cb36d7d834adc070427eeb450794fac8e02bc8ee Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Wed, 15 Jul 2026 17:57:28 -0700 Subject: [PATCH 38/60] Add geom surfacevel: zero-dof conveyors, treadmills and turntables. https://www.youtube.com/watch?v=PdSdrqhSiZA The new geom attribute surfacevel (6 numbers: linear and angular velocity in the geom's local frame, angular about the geom frame origin) specifies the velocity of the geom's surface material relative to the geom frame. The relative surface velocity of the two geoms is added to the tangential contact rows of efc_vel in mj_referenceConstraint, so friction drives touching bodies toward the motion of the surface: objects on a conveyor are transported at belt speed, turntables impart omega x r with torsional spin-up for condim >= 4, and surface velocities compose with each other and with body motion. The component along the contact normal is projected out: probe experiments showed that velocity-space emission chatters mass-independently and ingestion merely deepens penetration; normal-direction effects belong to force-space features. surfacevel is interpreted in the geom frame as authored: for mesh geoms, whose compiled frame absorbs the mesh centering and principal-axes transform, the compiler re-expresses the authored value in the compiled frame. No special interaction with sleeping: objects being transported do not fall asleep because they are moving; objects at rest on an active surface may sleep like any other resting object. Includes showcase models (model/surfacevel/): a luggage carousel whose ring is a spinning square-profile supertorus fed by a cascade of belts with matched spinning end rollers, bags dropping in and circulating indefinitely; and a treadmill with a passive humanoid. PiperOrigin-RevId: 948647785 Change-Id: I313f66949811e9e0e9d96f494f6f0a8f83d07f81 --- dm_control/mjcf/schema.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index b2228c82..2179398d 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -318,6 +318,7 @@ + @@ -656,6 +657,7 @@ + @@ -1098,6 +1100,7 @@ + @@ -1355,6 +1358,7 @@ + @@ -1478,6 +1482,7 @@ + @@ -1732,6 +1737,7 @@ + From 734471648b85a3f1e075f67a9b2cd865f28b57e6 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Fri, 17 Jul 2026 07:48:46 -0700 Subject: [PATCH 39/60] Interpret position and intvelocity setpoints on 3D rotational transmissions (ball joints, site+refsite) on the circle. The force uses the setpoint representative nearest the current length for smooth tracking beyond pi. - Wrapping in force path is local; act is re-anchored at integration time. - Remove hardcoded `actrange` for intvelocity actuators. PiperOrigin-RevId: 949566477 Change-Id: I6d8e17455ed6095833261209cf95dc677605e41d --- dm_control/mjcf/schema.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 2179398d..dbda9798 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -508,6 +508,7 @@ + @@ -835,6 +836,7 @@ + @@ -2167,6 +2169,7 @@ + From 1c4ab79a3cb0d322e5a25154f4a3c96fbaa4a3e2 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Mon, 20 Jul 2026 08:35:17 -0700 Subject: [PATCH 40/60] Add geom adhesion: contacts that pull, via translated friction cones. https://youtu.be/GioWwB36XHI The new geom attribute adhesion (units of force, signed; pair-level override) translates the contact friction cone along its normal so that the force origin lies strictly inside it. Consequences: each contact can pull with up to the given force before breaking, and the tangential friction budget becomes mu*(f_N + adhesion) -- the Mohr-Coulomb yield condition with cohesion c = mu*adhesion -- so lightly-squeezed grasps retain a guaranteed friction floor. A translated cone factors exactly into {constant attractive force} + {original cone}, so no solver kernels change. The implementation is this factorization: a constant attraction along contact normals accumulated into the new mjData.qfrc_adhesion (summed into qfrc_passive), plus a bias of adhesive contact rows' reference acceleration (aref += R*adhesion), which makes resting penetration exactly independent of adhesion. Contacts of adhesive pairs remain active throughout the gap zone, producing rows with positive violation whose reference acceleration pulls: a tether that resists pull-off smoothly, captures objects released within the band into steady contact, and detaches at the specified force. Adhesion values of the two geoms combine by sum; explicit pairs override. mj_contactForce reports the net interface force (cone force minus the adhesive pull), whose normal component can now be negative. Negative adhesion is allowed and produces a repulsive offset (air hockey). PiperOrigin-RevId: 950858148 Change-Id: Ifb7349d0db64a856206e4bca68044eac8f7c40c8 --- dm_control/mjcf/schema.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index dbda9798..8cb08ac7 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -319,6 +319,7 @@ + @@ -402,6 +403,7 @@ + @@ -659,6 +661,7 @@ + @@ -739,6 +742,7 @@ + @@ -1103,6 +1107,7 @@ + @@ -1361,6 +1366,7 @@ + @@ -1485,6 +1491,7 @@ + @@ -1740,6 +1747,7 @@ + @@ -1862,6 +1870,7 @@ + From 206323b1b2f2c379e1f115136ee90d0b6f886283 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 21 Jul 2026 11:35:28 -0700 Subject: [PATCH 41/60] Add SO3 transmission and native orientation actuator. https://youtu.be/17XpwnqyCXs New transmission type mjTRN_SO3: a relative orientation, targeting a ball joint or a site+refsite pair. It is the first transmission with more than one force output: its length is the norm of the expmap vector of the relative rotation and its moment axes are the 3 rows of the relative rotational Jacobian, without projecting onto per-actuator gears. New force law mjGAIN_SO3/mjBIAS_SO3: a geodesic PD servo, force = kp * log(q_current^-1 * q_target) - kv * velocity, exact for arbitrary axis combinations with a unique equilibrium at every commanded orientation. Error, moment rows and velocity all live in the child frame (joint or site): the right-difference error is the gradient of the geodesic potential in that frame. The parent-frame (left) error is not: driving child-frame torques with it pumps energy at large angles, settling into steady-spinning limit cycles (the SO3LargeAngleConvergence test). The integrator variant stores the 3D orientation setpoint in act (actnum = 3, re-anchored to a bounded representative at integration time). Exposed in MJCF as , or via . The setpoint input has two charts: an expmap target (3 controls, default) or a quaternion target (4 controls) -- , the first actuator with different input and output widths. The signature is recorded in a new per-actuator field actuator_ctrlspec (mjtCtrlChart), whose meaning is scoped by the gain type the way gain/bias parameters are; ctrlnum is derived from it at compile time and remains the layout authority. An explicit field rather than width inference or a prm slot: width-as-chart cannot express same-width signatures (upcoming servo input subsets), and prm slots are the input_mode pattern this stack retires. The force law normalizes the commanded quaternion, making it scale- and antipodally-invariant. The all-zero ctrl still maps to the identity via mju_normalize4, but it is a degenerate point (a nudge of any component commands a half-turn), so quat inputs reset to the identity quaternion: new mj_resetCtrl sets neutral ctrl values (zero, except qw = 1), called by mj_resetData and the viewers' Clear All. The quat chart is restricted to dyntype 'none': integrating a quaternion setpoint linearly is not meaningful on the manifold. New mjsActuator.ctrlspec field carries the signature through the spec and XML round-trip. Actuator sensors (actuatorpos/vel/frc) now report one value per force output; dim = 3 on an SO3 actuator. As the first actuator with nu != nactuator, this commit also makes the viewers multi-input aware: the control sliders in simulate and studio, which indexed per-actuator arrays by control index (out of bounds on this model class), are generated per control and labeled with the actuator name plus an input suffix ("orient/qw"), via the new introspection helper mj_actuatorInputName -- the single source of truth for input names, extended by each new multi-input type (quaternion components are w-first: qw, qx, qy, qz). Slider ranges now honor a defined ctrlrange even when ctrllimited is false: range is the UI hint, limited is the clamp -- wrapped and expmap setpoints are unbounded but still want finite sliders, while quat components are truly bounded. The rotational demo model is orientation.xml under test/engine/testdata/actuation/, upgraded to a three-way contrast: per-axis wrapped servos vs an expmap-commanded vs a quat-commanded orientation actuator, on identical checker-textured boxes. It is loaded by the mixed-axis contrast and input-name tests, and doubles as the viewer test model (slider groups of 3 independent, 3 grouped, 4 grouped). PiperOrigin-RevId: 951607063 Change-Id: If116b2e2ff29f22759d189ea644ee6d59419b1ce --- dm_control/mjcf/schema.xml | 62 ++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 8cb08ac7..3f960851 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -448,9 +448,11 @@ + + - - + + @@ -525,6 +527,19 @@ + + + + + + + + + + + + + @@ -782,9 +797,10 @@ + - - + + @@ -855,6 +871,18 @@ + + + + + + + + + + + + @@ -2060,6 +2088,7 @@ + @@ -2079,8 +2108,8 @@ - - + + @@ -2199,6 +2228,27 @@ + + + + + + + + + + + + + + + + + + + + + From 49254987f5c839b1281260e84d4f3e227b1acc1b Mon Sep 17 00:00:00 2001 From: DeepMind Date: Mon, 27 Jul 2026 18:45:49 -0700 Subject: [PATCH 42/60] Update dm_control to version 1.0.44 and require MuJoCo 3.11.0 PiperOrigin-RevId: 954952537 Change-Id: I9e5a7ef5adb3a0eec553cde9deb715ddeb5a6194 --- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index cac8c3c7..b2a0fc08 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.43\n", + "!pip install -q dm_control>=1.0.44\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index b05fa5ca..08ed1d67 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.10.0 +mujoco==3.11.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index 92f9ee07..08b9246d 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.43', + version='1.0.44', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.10.0', + 'mujoco >= 3.11.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 223277d4..20f09ac4 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.43\n", + "!pip install -q dm_control>=1.0.44\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From a45215282b6290a660a9f2518cc518689b27277f Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 4 Aug 2026 08:03:25 -0700 Subject: [PATCH 43/60] Save flex node coordinates in the new nodecoord attribute. Interpolated flexes with pinned nodes could not be reloaded after saving: pinned nodes share their parent body, and their positions within it lived only in mjsFlex.node, which had no MJCF attribute. On reload the pinned nodes collapsed onto the parent body origin, degenerating the trilinear interpolation grid ("flex grid rotation R0 is not orthonormal"). This made model/flex/strain.xml and gripper_trilinear.xml fail to round-trip. Add flex/nodecoord, real(3*nnode), the node analog of flex/vertex: local node coordinates within the corresponding body frames. The reader picks it up from the regenerated schema tables; the writer emits it with the precision-aware WriteVector, since VectorToString ignores the XML precision setting and truncating node coordinates to 6 digits while body positions carry 17 fails the R0 orthonormality check at full precision. Add a WritesPinnedFlexNodes round-trip regression test, and remove the two write-read sweep exclusions documenting this bug. The removed substring filter "strain" was also matching core_constraint, silently excluding that entire testdata directory from the sweep; its ~40 models are now covered and pass. PiperOrigin-RevId: 959025281 Change-Id: I9edbe6328740fe63c3adfa3b6a69546c141e575f --- dm_control/mjcf/schema.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 3f960851..30d68ee6 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1818,6 +1818,7 @@ + From 9401ef296b425eb2d26d7b9dc218e03ae68587d2 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Tue, 4 Aug 2026 18:11:03 -0700 Subject: [PATCH 44/60] Add light softness: spotlight edge softness for physically-based rendering. The new spotlight attribute softness (real in [0, 1], default 0) is the fraction of the cone, measured inward from the cutoff, over which intensity falls to zero. It is used by physically-based lighting models; the Phong model's corresponding knob remains exponent. The filament renderer previously hardcoded the inner cone angle to 0, making the entire beam penumbra: the shader attenuates by the squared smoothstep ((cos(theta) - cos(outer)) / (cos(inner) - cos(outer)))^2, so a cutoff-25 spot delivered its rated candela only exactly on-axis and about a third of it averaged over the light pool, with the deficit shrinking as the cutoff widens. The inner angle is now (1 - softness) * cutoff, so at the default the light delivers its full intensity everywhere inside the cone and illuminance follows E = I/d^2 independent of the cutoff. Setting softness to 1 reproduces the previous appearance exactly (verified bit-identical), which is the migration path for models tuned against the old behavior. The filament light type also changes from FOCUSED_SPOT to SPOT. With intensity given in candela and the cone set at build time the two types produce identical output (FOCUSED_SPOT's power-conserving rescale only applies when the cone changes after the intensity is set), but SPOT guarantees that candela never rescales with cone angle should the cone ever become runtime-editable. Verified with headless renders under a linear tone mapper against an equal-candela point light at cutoffs 25/45/80: softness 0 gives spot/point luminance ratio 1.000 at all sampled angles inside the cone; softness 0.2 is flat over the inner 80% of the cone; softness 1 matches the previous renderer with zero linear-pixel difference. XML round-trip and the [0, 1] compile-time check verified. Introspect and wasm bindings regenerated. PiperOrigin-RevId: 959334706 Change-Id: I617b6c4942f98233f7af5d64e9182cc2752fda2b --- dm_control/mjcf/schema.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 30d68ee6..029ceb88 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -385,6 +385,7 @@ + @@ -740,6 +741,7 @@ + @@ -1226,6 +1228,7 @@ + @@ -1610,6 +1613,7 @@ + From 985d09401ea8824cec489e56cd631b24d9e32891 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Wed, 5 Aug 2026 17:13:18 -0700 Subject: [PATCH 45/60] Update dm_control's schema.xml from generated schema and add schema_test. Replaces the hand-maintained schema.xml in dm_control with the generated schema from MuJoCo's mjcf.schema. Adds schema_test.py to dm_control/mjcf/ to validate the schema against dm_control itself (structural checks, namespace completeness, singleton/repeated trees, PyMJCF exercise, and default validation). PiperOrigin-RevId: 959953820 Change-Id: I1184d211519a26e640cb0a77b3e8b7bfc3d43864 --- dm_control/mjcf/schema.xml | 3765 ++++++++++++++++---------------- dm_control/mjcf/schema_test.py | 191 ++ 2 files changed, 2134 insertions(+), 1822 deletions(-) create mode 100644 dm_control/mjcf/schema_test.py diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 029ceb88..e6b33241 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1,3 +1,7 @@ + @@ -5,103 +9,104 @@ - + - + - + - - + - - + + + + - - + + - + - - - - - + + + + + - - - - + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -109,543 +114,191 @@ - - - + + + - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - + + + + + - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - + + - - + + - + + + + + + + + + + + + - - + - - - - - - + + + + + + + @@ -653,75 +306,76 @@ - - - - - + + + + - - - + + - + - - - + + + - - + + - - - + + + + - + - + - - - - - + + + + + + - - - - - + + + + + + + - - + @@ -732,33 +386,34 @@ - - - - - - - - - - - - - + + + + + - + + + + + + + + + - + - - - - - + + + + + + @@ -771,282 +426,673 @@ - + + - + - - + + + - + - - + + + + + + + + - + + - - + - - - - - + + + + + + + - + - - + + + + + + + - + - - + - - + + + + + + + + - + - - - + - - + + + + + + + - + - - + - - - + + + + + + + + - + + - - - + - + + + + - + + - + - + + + + + + - + - - + - - + + + + + + + - + - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + - + + + + + + + + + + + + + + + + + - + - + + - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - + + + + + + - + - + @@ -1054,7 +1100,7 @@ - + @@ -1062,382 +1108,287 @@ + + + + + + + + + + + + + + - - - - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - + + + - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + + + + + + + + - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - + + + - + - - - + + + + + + + - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - + + + + + + + + + + - + - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + + + + + + + + + + + + + + + + + + + - + - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + @@ -1445,100 +1396,88 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1546,7 +1485,7 @@ - + @@ -1554,179 +1493,82 @@ - + - - - + + - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - + - + - + - + - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - - - - - - - - - - - - - + @@ -1734,69 +1576,316 @@ - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + @@ -1810,120 +1899,197 @@ - - - - - - - - - + + + + + + + + + - - + + - - + + - + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - + + + + + + + - + - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + @@ -1935,9 +2101,9 @@ - - - + + + @@ -1951,10 +2117,10 @@ - - - - + + + + @@ -1963,10 +2129,10 @@ - - - - + + + + @@ -1975,110 +2141,32 @@ - - - - + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - @@ -2092,31 +2180,35 @@ - - - - - + + + + - + + + - - - - - - - + + + - - - - - - + + + + + + + + + + + + + @@ -2129,21 +2221,23 @@ - - + + + - + + + - - - - + + + - + + - @@ -2154,26 +2248,28 @@ - - + + + + - + + + - - - - + + + - + + - - @@ -2184,21 +2280,23 @@ - - + + + - + + + - - - - + + + - + + - @@ -2210,27 +2308,29 @@ - - - + + + + + - + + + - - - - + + + - + + - - @@ -2241,13 +2341,13 @@ - + + - - + + - @@ -2262,20 +2362,22 @@ - + + - + + + - - - - + + + - + + - @@ -2287,21 +2389,23 @@ - - + + + - + + + - - - - + + + - + + - @@ -2316,20 +2420,23 @@ - - + + + - + + + - - - - + + + - + + @@ -2338,7 +2445,6 @@ - @@ -2349,11 +2455,11 @@ - - - + + + @@ -2361,37 +2467,39 @@ - - - - - + + + + + + - - - - + + + - - - - + + + + + + + - - + @@ -2404,569 +2512,548 @@ - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - + - - + + - - - + + - + - - + + - - + + + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - + + + + + + + + + + + + + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - + - - + + - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - + - - - + + + @@ -2976,29 +3063,29 @@ - - - + + + - + - - - + + + @@ -3008,81 +3095,115 @@ - - - + + + - - - + + + - - - + + + - + - - + + - - - - - - - - - - - + - - + + + + + + + - + - + + - - - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3095,9 +3216,9 @@ - + diff --git a/dm_control/mjcf/schema_test.py b/dm_control/mjcf/schema_test.py new file mode 100644 index 00000000..1eda0e8c --- /dev/null +++ b/dm_control/mjcf/schema_test.py @@ -0,0 +1,191 @@ +# Copyright 2026 The dm_control Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================ +"""Validates dm_control's schema.xml against dm_control itself.""" + +import os +import xml.etree.ElementTree as ET + +from absl.testing import absltest +from dm_control import mjcf +from dm_control.mjcf import schema + +_SCHEMA_PATH = os.path.join(os.path.dirname(__file__), 'schema.xml') + +# attributes whose defaults are not settable through PyMJCF descriptors +# (multi-token strings PyMJCF types more strictly than the runtime) +_DEFAULT_SWEEP_SKIP = set() + + +class SchemaTest(absltest.TestCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.spec = schema.parse_schema(_SCHEMA_PATH) + + def test_namespace_universe_is_closed(self): + """Every reference namespace is populated by some identified element.""" + namespaces = schema.collect_namespaces(self.spec) + dangling = [] + + def visit(spec, seen): + if id(spec) in seen: + return + seen.add(id(spec)) + for attr_spec in spec.attributes.values(): + kwargs = getattr(attr_spec, 'other_kwargs', {}) or {} + ns = kwargs.get('reference_namespace') + if ns and not ns.startswith('attrib:') and ns not in namespaces: + dangling.append(f'{spec.name}.{attr_spec.name} -> {ns}') + for child in spec.children.values(): + visit(child, seen) + + visit(self.spec, set()) + self.assertEqual(dangling, []) + + def test_singleton_api_surface(self): + """The attribute-vs-list-view surface PyMJCF users rely on.""" + root = mjcf.RootElement(model='m') + # singletons are elements, directly usable + root.option.timestep = 0.001 + root.compiler.angle = 'radian' + root.visual.map.znear = 0.01 + self.assertTrue(hasattr(root.worldbody, 'add')) + # the top-level default is a singleton... + root.default.geom.margin = 0.001 + # ...whose nested defaults are repeated + root.default.add('default', dclass='a') + root.default.add('default', dclass='b') + # repeated elements are list views + root.worldbody.add('body', name='b1') + root.worldbody.add('body', name='b2') + self.assertLen(root.worldbody.body, 2) + + def test_full_pymjcf_exercise(self): + """Build, class, attach twice, bind, compile, round-trip.""" + arm = mjcf.RootElement(model='arm') + arm.default.joint.damping = 2.0 + strong = arm.default.add('default', dclass='strong') + strong.joint.damping = 5.0 + upper = arm.worldbody.add('body', name='upper') + upper.add('joint', name='shoulder', type='ball') + upper.add('geom', name='upper_geom', type='capsule', size=[.05], + fromto=[0, 0, 0, 0, 0, -.3]) + lower = upper.add('body', name='lower', pos=[0, 0, -.3]) + elbow = lower.add('joint', name='elbow', type='hinge', axis=[0, 1, 0], + dclass='strong') + lower.add('geom', name='lower_geom', type='capsule', size=[.04], + fromto=[0, 0, 0, 0, 0, -.25]) + tip = lower.add('site', name='tip', pos=[0, 0, -.25]) + arm.actuator.add('position', name='act', joint=elbow, kp=10) + arm.sensor.add('jointpos', name='sense', joint=elbow) + arm.contact.add('exclude', name='ex', body1='upper', body2='lower') + + hand = mjcf.RootElement(model='hand') + hand.worldbody.add('geom', name='palm', type='box', + size=[.02, .02, .02]) + tip.attach(hand) + + scene = mjcf.RootElement(model='scene') + scene.worldbody.add('geom', name='floor', type='plane', size=[1, 1, .1]) + scene.worldbody.add('light', pos=[0, 0, 3]) + scene.attach(arm) + + physics = mjcf.Physics.from_mjcf_model(scene) + self.assertEqual(physics.model.nu, 1) + self.assertGreater(physics.model.nq, 4) + # binding resolves through two attachment levels + self.assertEqual( + scene.find_all('sensor')[0].joint.full_identifier, 'arm/elbow') + bound = physics.bind(scene.find_all('joint')) + self.assertEqual(bound.qpos.shape[0], physics.model.nq) + # serialization is deterministic; PyMJCF output is not re-parseable by + # design (the '/' scope markers reject), so the parser direction is + # exercised on ordinary MJCF instead + self.assertEqual(scene.to_xml_string(), scene.to_xml_string()) + plain = mjcf.from_xml_string(""" + + + + + + + + + + + + """) + self.assertEqual(plain.find('geom', 'g').dclass.dclass, 'soft') + plain_physics = mjcf.Physics.from_mjcf_model(plain) + self.assertEqual(plain_physics.model.nu, 1) + + def test_every_declared_default_validates(self): + """Setting each attribute to its declared default passes validation. + + The schema file carries default= metadata; PyMJCF's descriptors + validate on assignment, so this sweeps every keyword set, arity and + numeric type through dm_control's own machinery. + """ + tree = ET.parse(_SCHEMA_PATH) + + def constructible(spec_node, path): + """Depth-first: yield (path, element node) below construction roots.""" + for child in spec_node.findall('./children/element'): + name = child.get('name') + yield path + (name,), child + yield from constructible(child, path + (name,)) + + root = mjcf.RootElement(model='sweep') + checked, failures = 0, [] + for path, node in constructible(tree.getroot(), ()): + for attr in node.findall('./attributes/attribute'): + default = attr.get('default') + if default is None: + continue + if (path[-1], attr.get('name')) in _DEFAULT_SWEEP_SKIP: + continue + # walk to the element, constructing along the way where possible + parent = root + ok = True + for tag in path: + existing = getattr(parent, tag, None) + if isinstance(existing, mjcf.Element) or ( + existing is not None + and type(existing).__name__ == '_ElementImpl'): + parent = existing + continue + try: + parent = parent.add(tag) + except Exception: # pylint: disable=broad-exception-caught + ok = False + break + if not ok: + continue + try: + setattr(parent, attr.get('name'), default) + checked += 1 + except Exception as e: # pylint: disable=broad-exception-caught + failures.append(f'{"/".join(path)}@{attr.get("name")}=' + f'{default!r}: {e}') + self.assertGreater(checked, 200) + if failures: + self.fail(f'{len(failures)} defaults rejected by PyMJCF:\n' + + '\n'.join(failures[:20])) + + +if __name__ == '__main__': + absltest.main() From 6b3298d4a4962948992ae9c8ff0ad15681068270 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Thu, 20 Aug 2026 06:54:07 -0700 Subject: [PATCH 46/60] Update dm_control to version 1.0.45 and require MuJoCo 3.12.0 PiperOrigin-RevId: 967795246 Change-Id: I81e5e57857e5fc4af03c59709aacbfd345e3babe --- dm_control/mjcf/schema.xml | 10 +++++----- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index e6b33241..cf376fa8 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -154,7 +154,7 @@ - + @@ -397,7 +397,7 @@ - + @@ -793,7 +793,7 @@ - + @@ -1378,7 +1378,7 @@ - + @@ -1700,7 +1700,7 @@ - + diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index b2a0fc08..08979735 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.44\n", + "!pip install -q dm_control>=1.0.45\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 08ed1d67..2ff34130 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.11.0 +mujoco==3.12.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index 08b9246d..da4df650 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.44', + version='1.0.45', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.11.0', + 'mujoco >= 3.12.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 20f09ac4..022ab738 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.44\n", + "!pip install -q dm_control>=1.0.45\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From d2cf3a3d3ad47a9ea4153710fca852375adb4dff Mon Sep 17 00:00:00 2001 From: Taylor Howell Date: Sat, 29 Aug 2026 05:21:28 -0700 Subject: [PATCH 47/60] Update schema.xml from generated schema to include tactile cutoff attribute. PiperOrigin-RevId: 973076751 Change-Id: I7c78859e2a1a1b1a8dcd111dbdb66f15681b693e --- dm_control/mjcf/schema.xml | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index cf376fa8..dbeacccb 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -2193,7 +2193,7 @@ - + @@ -2232,7 +2232,7 @@ - + @@ -2260,7 +2260,7 @@ - + @@ -2291,7 +2291,7 @@ - + @@ -2322,7 +2322,7 @@ - + @@ -2372,7 +2372,7 @@ - + @@ -2400,7 +2400,7 @@ - + @@ -2431,7 +2431,7 @@ - + @@ -2486,7 +2486,7 @@ - + @@ -3092,6 +3092,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -3137,6 +3159,7 @@ + @@ -3182,13 +3205,13 @@ - + - + From 3e9cd0bf3ec5141f3c6225e77f3ef99b42df2426 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Wed, 9 Sep 2026 10:12:25 -0700 Subject: [PATCH 48/60] Update dm_control to version 1.0.46 and require MuJoCo 3.13.0 PiperOrigin-RevId: 978612909 Change-Id: If462d0fc5be998969009ffe99ab02cf0231c73cb --- dm_control/mjcf/schema.xml | 8 +++++++- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index dbeacccb..ff5fe54d 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -66,7 +66,7 @@ - + @@ -356,6 +356,7 @@ + @@ -752,6 +753,7 @@ + @@ -1332,6 +1334,7 @@ + @@ -1475,6 +1478,7 @@ + @@ -1654,6 +1658,7 @@ + @@ -1783,6 +1788,7 @@ + diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 08979735..da9a6b71 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.45\n", + "!pip install -q dm_control>=1.0.46\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 2ff34130..218abf26 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.12.0 +mujoco==3.13.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index da4df650..a3430d1b 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.45', + version='1.0.46', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.12.0', + 'mujoco >= 3.13.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 022ab738..24744ae4 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.45\n", + "!pip install -q dm_control>=1.0.46\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From a04e3e4cf56c12117d2294bb090f9acec21e5c67 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Tue, 22 Sep 2026 14:11:49 -0700 Subject: [PATCH 49/60] Update dm_control to version 1.0.47 and require MuJoCo 3.14.0 PiperOrigin-RevId: 986225725 Change-Id: I6925c0fa3f236de926ec4a2d3c0e1d2f66a580df --- dm_control/mjcf/schema.xml | 9 +++++---- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index ff5fe54d..9b89d0c1 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -107,6 +107,7 @@ + @@ -1412,7 +1413,7 @@ - + @@ -1722,7 +1723,7 @@ - + @@ -2018,7 +2019,7 @@ - + @@ -2061,7 +2062,7 @@ - + diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index da9a6b71..5c893143 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.46\n", + "!pip install -q dm_control>=1.0.47\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 218abf26..916311df 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.13.0 +mujoco==3.14.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index a3430d1b..01016233 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.46', + version='1.0.47', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.13.0', + 'mujoco >= 3.14.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 24744ae4..b821c2c9 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.46\n", + "!pip install -q dm_control>=1.0.47\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From 3c2f212bd11abf235b91d9314ba3ca759abe8985 Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Mon, 5 Oct 2026 06:54:08 -0700 Subject: [PATCH 50/60] Replace `# pytype: disable` suppressions with `# pyrefly: ignore` PiperOrigin-RevId: 993657114 Change-Id: Iec75a7d9049e6743eabe0a8135ec5eb3e7803360 --- dm_control/blender/fake_core/mathutils.py | 2 +- .../blender/mujoco_exporter/blender_scene.py | 10 +++++----- dm_control/blender/mujoco_exporter/mujoco_scene.py | 2 +- dm_control/locomotion/mocap/trajectory.py | 2 +- dm_control/locomotion/soccer/humanoid.py | 2 +- .../locomotion/tasks/reference_pose/tracking.py | 14 +++++++------- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dm_control/blender/fake_core/mathutils.py b/dm_control/blender/fake_core/mathutils.py index 16f0c51b..a48c21e9 100644 --- a/dm_control/blender/fake_core/mathutils.py +++ b/dm_control/blender/fake_core/mathutils.py @@ -67,7 +67,7 @@ def w(self) -> float: def __eq__(self, rhs) -> bool: if not isinstance(rhs, Vector): return False - return np.linalg.norm(self._coords - rhs._coords) < 1e-6 # pyrefly: ignore[bad-return] + return np.linalg.norm(self._coords - rhs._coords) < 1e-6 def __str__(self) -> str: return 'Vector({:.2f}, {:.2f}, {:.2f})'.format(self.x, self.y, self.z) diff --git a/dm_control/blender/mujoco_exporter/blender_scene.py b/dm_control/blender/mujoco_exporter/blender_scene.py index 690bfa00..ca50a537 100644 --- a/dm_control/blender/mujoco_exporter/blender_scene.py +++ b/dm_control/blender/mujoco_exporter/blender_scene.py @@ -122,7 +122,7 @@ def is_none(self) -> bool: @property def is_armature(self) -> bool: - return ( # pytype: disable=bad-return-type + return ( self.native_obj # pyrefly: ignore[bad-return] and self.native_obj.type == _ARMATURE and not self.native_bone @@ -138,19 +138,19 @@ def is_bone(self) -> bool: @property def is_mesh(self) -> bool: - return self.native_obj and self.native_obj.type == _MESH # pytype: disable=bad-return-type + return self.native_obj and self.native_obj.type == _MESH # pyrefly: ignore[bad-return] @property def is_light(self) -> bool: - return self.native_obj and self.native_obj.type == _LIGHT # pytype: disable=bad-return-type + return self.native_obj and self.native_obj.type == _LIGHT # pyrefly: ignore[bad-return] @property def is_camera(self) -> bool: - return self.native_obj and self.native_obj.type == _CAMERA # pytype: disable=bad-return-type + return self.native_obj and self.native_obj.type == _CAMERA # pyrefly: ignore[bad-return] @property def is_empty(self) -> bool: - return self.native_obj and self.native_obj.type == _EMPTY # pytype: disable=bad-return-type + return self.native_obj and self.native_obj.type == _EMPTY # pyrefly: ignore[bad-return] @property def name(self) -> str: diff --git a/dm_control/blender/mujoco_exporter/mujoco_scene.py b/dm_control/blender/mujoco_exporter/mujoco_scene.py index c2d75549..e633492c 100644 --- a/dm_control/blender/mujoco_exporter/mujoco_scene.py +++ b/dm_control/blender/mujoco_exporter/mujoco_scene.py @@ -74,7 +74,7 @@ def light_builder( el.setAttribute('pos', vec_to_mjcf(transform.pos)) el.setAttribute('dir', vec_to_mjcf(transform.rot @ _OZ)) el.setAttribute('directional', directional) - el.setAttribute('castshadow', bool_to_mjcf(light.use_shadow)) # pytype: disable=wrong-arg-types + el.setAttribute('castshadow', bool_to_mjcf(light.use_shadow)) el.setAttribute('diffuse', color_to_mjcf(light.color)) el.setAttribute('attenuation', attenuation) return el diff --git a/dm_control/locomotion/mocap/trajectory.py b/dm_control/locomotion/mocap/trajectory.py index f28c4d1b..c09739e1 100644 --- a/dm_control/locomotion/mocap/trajectory.py +++ b/dm_control/locomotion/mocap/trajectory.py @@ -118,7 +118,7 @@ def prop_field(timestep, i=i, field_name=field_name): self._create_all_items(self._dict) for k in self._dict: # make trajectory immutable by default - self._dict[k].flags.writeable = False # pytype: disable=attribute-error + self._dict[k].flags.writeable = False return {k: v[self._start_step:self._end_step] for k, v in self._dict.items()} diff --git a/dm_control/locomotion/soccer/humanoid.py b/dm_control/locomotion/soccer/humanoid.py index e1349b0a..6ad70da1 100644 --- a/dm_control/locomotion/soccer/humanoid.py +++ b/dm_control/locomotion/soccer/humanoid.py @@ -108,7 +108,7 @@ class Visual(enum.Enum): GEOM = 1 JERSEY = 2 - def _build(self, # pytype: disable=signature-mismatch # overriding-parameter-count-checks + def _build(self, # pyrefly: ignore[bad-override] visual, marker_rgba, walker_id=None, diff --git a/dm_control/locomotion/tasks/reference_pose/tracking.py b/dm_control/locomotion/tasks/reference_pose/tracking.py index 9ce8cdab..f6fd4eb9 100644 --- a/dm_control/locomotion/tasks/reference_pose/tracking.py +++ b/dm_control/locomotion/tasks/reference_pose/tracking.py @@ -266,7 +266,7 @@ def __init__( self._reset_reward_channels() def _strip_reference_prefix(self): - self._clip_reference_features = _strip_reference_prefix( # pytype: disable=wrong-arg-types + self._clip_reference_features = _strip_reference_prefix( self._clip_reference_features, 'walker/', keep_prefixes=self._prop_prefixes) # pyrefly: ignore[bad-argument-type] @@ -488,7 +488,7 @@ def initialize_episode(self, physics: 'mjcf.Physics', physics, self._walker, props=self._props) self._walker_features_prev = self._walker_features.copy() - self._walker_joints = np.array(physics.bind(self._walker.mocap_joints).qpos) # pytype: disable=attribute-error + self._walker_joints = np.array(physics.bind(self._walker.mocap_joints).qpos) # compute initial error self._compute_termination_error() @@ -779,14 +779,14 @@ def _update_ghost(self, physics: 'mjcf.Physics'): def action_spec(self, physics: 'mjcf.Physics'): """Action spec of the walker only.""" - ctrl = physics.bind(self._walker.actuators).ctrl # pytype: disable=attribute-error + ctrl = physics.bind(self._walker.actuators).ctrl shape = ctrl.shape dtype = ctrl.dtype minimum = [] maximum = [] for actuator in self._walker.actuators: - if physics.bind(actuator).ctrllimited: # pytype: disable=attribute-error - ctrlrange = physics.bind(actuator).ctrlrange # pytype: disable=attribute-error + if physics.bind(actuator).ctrllimited: + ctrlrange = physics.bind(actuator).ctrlrange minimum.append(ctrlrange[0]) maximum.append(ctrlrange[1]) else: @@ -797,7 +797,7 @@ def action_spec(self, physics: 'mjcf.Physics'): dtype=dtype, minimum=np.asarray(minimum, dtype=dtype), maximum=np.asarray(maximum, dtype=dtype), - name='\t'.join(actuator.full_identifier # pytype: disable=attribute-error + name='\t'.join(actuator.full_identifier for actuator in self._walker.actuators)) @property @@ -903,7 +903,7 @@ def after_step(self, physics: 'mjcf.Physics', random_state): self._walker_features = utils.get_features( physics, self._walker, props=self._props) # features for default error - self._walker_joints = np.array(physics.bind(self._walker.mocap_joints).qpos) # pytype: disable=attribute-error + self._walker_joints = np.array(physics.bind(self._walker.mocap_joints).qpos) self._current_reference_features = { k: v[self._time_step].copy() From c22ec28159c541c8c6b6546cd56d41dcaf7fb33b Mon Sep 17 00:00:00 2001 From: DeepMind Date: Mon, 5 Oct 2026 11:37:27 -0700 Subject: [PATCH 51/60] Update dm_control to version 1.0.48 and require MuJoCo 3.15.0 PiperOrigin-RevId: 993811117 Change-Id: I441cb83b308fe40e8d4a719fbc88ab8f51509886 --- dm_control/mjcf/schema.xml | 4 +--- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 9b89d0c1..68d8158e 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -1559,7 +1559,6 @@ - @@ -1869,7 +1868,6 @@ - @@ -1935,7 +1933,6 @@ - @@ -3049,6 +3046,7 @@ + diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 5c893143..fbc16efc 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.47\n", + "!pip install -q dm_control>=1.0.48\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 916311df..cd10bfde 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.14.0 +mujoco==3.15.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index 01016233..cdb2b7c7 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.47', + version='1.0.48', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.14.0', + 'mujoco >= 3.15.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index b821c2c9..924ac0f1 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.47\n", + "!pip install -q dm_control>=1.0.48\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From 773d5b5d94d8f58943cf56a66b9b9755818fe5b4 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Wed, 14 Oct 2026 03:58:48 -0700 Subject: [PATCH 52/60] Update dm_control to version 1.0.49 and require MuJoCo 3.16.0 PiperOrigin-RevId: 999267869 Change-Id: I81bd1ad4388126b858b9b78e934047b04f87b7cf --- dm_control/mjcf/schema.xml | 16 ++++++++++++---- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 68d8158e..e384cb34 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -27,6 +27,8 @@ + + @@ -464,9 +466,10 @@ - + + @@ -861,9 +864,10 @@ - + + @@ -1090,7 +1094,7 @@ - + @@ -1216,6 +1220,7 @@ + @@ -1514,6 +1519,7 @@ + @@ -1823,6 +1829,7 @@ + @@ -2205,9 +2212,10 @@ - + + diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index fbc16efc..a5dc26f4 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.48\n", + "!pip install -q dm_control>=1.0.49\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index cd10bfde..6fcb7945 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.15.0 +mujoco==3.16.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index cdb2b7c7..ac936187 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.48', + version='1.0.49', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.15.0', + 'mujoco >= 3.16.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 924ac0f1..9a3ea687 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.48\n", + "!pip install -q dm_control>=1.0.49\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From 437b7a6a416715d9ed9e419cb40060c862de3ab0 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Sun, 18 Oct 2026 10:21:59 -0700 Subject: [PATCH 53/60] dm_control: load exported MJCF relative to output dir in export_with_assets_test PiperOrigin-RevId: 1001873634 Change-Id: I1d4bcc52d19d78edd3980c3ea46595a3016dde85 --- dm_control/mjcf/export_with_assets_test.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dm_control/mjcf/export_with_assets_test.py b/dm_control/mjcf/export_with_assets_test.py index a23e7b47..1cc6b31e 100644 --- a/dm_control/mjcf/export_with_assets_test.py +++ b/dm_control/mjcf/export_with_assets_test.py @@ -13,8 +13,6 @@ # limitations under the License. # ============================================================================ -"""Tests for `dm_control.mjcf.export_with_assets`.""" - import os from absl import flags from absl.testing import absltest @@ -74,9 +72,15 @@ def test_export_model(self, xml_path, out_xml_name): self.assertDictEqual(out_dir_contents, assets) # Check that we can construct an MjModel instance using the path to the - # output file. - from_exported = wrapper.MjModel.from_xml_path( - os.path.join(out_dir, out_xml_name)) + # output file. Load relative to `out_dir` so `modelfiledir` is empty, + # matching `from_xml_string` below when resolved paths are stored in + # `mjModel.paths`. + old_cwd = os.getcwd() + try: + os.chdir(out_dir) + from_exported = wrapper.MjModel.from_xml_path(out_xml_name) + finally: + os.chdir(old_cwd) # Check that this model is identical to one constructed directly from # `mjcf_model`. From 1806ac9f3da0b1a8e628506232ea4234fcfbc9b9 Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Tue, 20 Oct 2026 04:04:31 -0700 Subject: [PATCH 54/60] Suppress new Pyrefly findings before upgrading to v1.4.0 PiperOrigin-RevId: 1002991834 Change-Id: Ib5be32459c384de38defa034aa2836be8c48f940 --- dm_control/blender/fake_core/mathutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dm_control/blender/fake_core/mathutils.py b/dm_control/blender/fake_core/mathutils.py index a48c21e9..16f0c51b 100644 --- a/dm_control/blender/fake_core/mathutils.py +++ b/dm_control/blender/fake_core/mathutils.py @@ -67,7 +67,7 @@ def w(self) -> float: def __eq__(self, rhs) -> bool: if not isinstance(rhs, Vector): return False - return np.linalg.norm(self._coords - rhs._coords) < 1e-6 + return np.linalg.norm(self._coords - rhs._coords) < 1e-6 # pyrefly: ignore[bad-return] def __str__(self) -> str: return 'Vector({:.2f}, {:.2f}, {:.2f})'.format(self.x, self.y, self.z) From 3948bd0ab4a857dbb5989a1b8d20bac920551136 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Thu, 22 Oct 2026 17:16:26 -0700 Subject: [PATCH 55/60] Update dm_control to version 1.0.50 and require MuJoCo 3.17.0 PiperOrigin-RevId: 1005169649 Change-Id: Ib1ac8358d8fd7aa56bb8a1d4e6c51ed126e8a57f --- dm_control/mjcf/schema.xml | 49 ++++++++++++++++++++++++++++++++ dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 +-- tutorial.ipynb | 2 +- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index e384cb34..cce8e57d 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -32,6 +32,7 @@ + @@ -263,6 +264,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -661,6 +682,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -1153,6 +1194,7 @@ + @@ -1176,6 +1218,7 @@ + @@ -1551,6 +1594,8 @@ + + @@ -1861,6 +1906,8 @@ + + @@ -1958,6 +2005,8 @@ + + diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index a5dc26f4..0db0b38b 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.49\n", + "!pip install -q dm_control>=1.0.50\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 6fcb7945..82ef52ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.16.0 +mujoco==3.17.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index ac936187..b28c3601 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.49', + version='1.0.50', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.16.0', + 'mujoco >= 3.17.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 9a3ea687..3742876b 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.49\n", + "!pip install -q dm_control>=1.0.50\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", From d7a88f9533f6113853f38791f926d24c7d05e9fd Mon Sep 17 00:00:00 2001 From: DeepMind Date: Thu, 29 Oct 2026 06:07:25 -0700 Subject: [PATCH 56/60] Add an mjRND_POST_PROCESSING flag. PiperOrigin-RevId: 1009632523 Change-Id: Id09b49b8b17fac1e5204cf4b6bc004d8aa897163 --- dm_control/viewer/renderer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dm_control/viewer/renderer.py b/dm_control/viewer/renderer.py index 7d4a803f..be055b49 100644 --- a/dm_control/viewer/renderer.py +++ b/dm_control/viewer/renderer.py @@ -45,6 +45,8 @@ _DEFAULT_RENDER_FLAGS[mujoco.mjtRndFlag.mjRND_REFLECTION.value] = 1 _DEFAULT_RENDER_FLAGS[mujoco.mjtRndFlag.mjRND_SKYBOX.value] = 1 _DEFAULT_RENDER_FLAGS[mujoco.mjtRndFlag.mjRND_CULL_FACE.value] = 1 +if hasattr(mujoco.mjtRndFlag, 'mjRND_POST_PROCESSING'): + _DEFAULT_RENDER_FLAGS[mujoco.mjtRndFlag.mjRND_POST_PROCESSING.value] = 1 # Font scale values. _DEFAULT_FONT_SCALE = mujoco.mjtFontScale.mjFONTSCALE_100 From ec0deccab7c6ad6d06f54c9d784ff7ec516172f2 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Thu, 29 Oct 2026 07:14:52 -0700 Subject: [PATCH 57/60] Add `castshadow` attribute to `` for per-geom shadow control. Point lights placed inside detailed light-fixture meshes are occluded by the enclosing geometry in shadow-mapped renderers like Filament. Adding a boolean `castshadow` attribute on `` (default `true`) allows disabling shadow casting on individual geoms while still lighting them normally, including when `mjModel.geom_castshadow` is toggled at runtime. - Add `castshadow` to `` in MJCF (`mjsGeom.castshadow`, `mjModel.geom_castshadow`, `mjvGeom.castshadow`). - Add `mjrf_setRenderableCastShadow` (`mjrf.Renderable.set_cast_shadow` in Python) and update per-geom shadow state in `ModelRenderables::Update`. - Respect `geom->castshadow` in the classic OpenGL renderer, Filament `ModelRenderables` / `compat` bridge, Studio `gui_spec`, Python bindings, and `dm_control`. PiperOrigin-RevId: 1009665752 Change-Id: I6e8708c6d299caafd41354d7ba0a15d746563d9c --- dm_control/mjcf/schema.xml | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index cce8e57d..8afc7917 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -364,6 +364,7 @@ + @@ -782,6 +783,7 @@ + @@ -1349,6 +1351,7 @@ + @@ -1580,7 +1583,7 @@ - + @@ -1675,6 +1678,7 @@ + @@ -1892,7 +1896,7 @@ - + @@ -2207,16 +2211,6 @@ - - - - - - - - - - From e94f1e998bba39bc27875771f5156acfdd630755 Mon Sep 17 00:00:00 2001 From: Kyle Bayes Date: Thu, 29 Oct 2026 11:22:14 -0700 Subject: [PATCH 58/60] Add speculative enable flag along with corresponding documentation. PiperOrigin-RevId: 1009829611 Change-Id: I2ae50138c351ad0df1e0dabf5ce594935c1b7dcd --- dm_control/mjcf/schema.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 8afc7917..02413267 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -111,6 +111,7 @@ + From f1f91e0309e5df81bf7a3ee83849ebcee86779d8 Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Sun, 1 Nov 2026 23:17:15 -0800 Subject: [PATCH 59/60] MuJoCo: port cable DER torsion to 1D flexcomp and remove legacy cable plugin and composite. Native 1D flex rods now implement discrete elastic rods (DER) with bending and torsion, replacing the `mujoco.elasticity.cable` plugin and ``. **Rod model** - Each open elastic 1D flexcomp whose first edge is pinned gets one `_twist` hinge joint that holds the material frame of the last edge (unpinned rods do not create a twist joint and are SO(3)-invariant). The interior material frames are quasistatic: - `section="circle"`: closed-form twist energy over a Bishop frame (`mj_rodChain`). - `section="box"`: O(M) tridiagonal Newton solve for the edge angles, with a Gauss-Newton fallback when the Hessian is indefinite and steps capped at 0.5 rad. - The rod's total twist (holonomy) is measured against a reference director carried forward in time by parallel transport (Bergou et al. 2010), so the energy stays continuous when a twisted rod coils. The state (7 values per rod) is stored in `d->plastic` and saved and restored with `mjSTATE_PLASTIC` and `key_plastic`. - The twist hinge has the rod's polar mass moment as inertia, Rayleigh damping (flex `damping` x torsional stiffness), and its stiffness is included in the discrete integrator's implicit metric. - New `` overrides the shear modulus G = E / (2 (1 + nu)) used for rod torsion. - `flex_bending` stores one record per hinge: `[v0, v1, v2, v3, k1, k2-k1, kb0, twist_jnt, kt, psi0]`. - Curved 1D hinge pairs: 3D rest curvature and dihedral torsion with exact gradients and a PSD stiffness matrix. - 1D direct flexcomps without `element` get sequential edges automatically. **Models and removals** - `cable.xml`, `coil.xml` and `belt.xml` move from `model/plugin/elasticity/` to `model/flex/`, using native 1D flexcomps with the old torsional moduli (`shear` = 1e7, 5e8, 1e8; belt `damping=".3"`). - Removed `plugin/elasticity/` (cable and shell plugins) and `user_composite`. **MJWarp** Matches C (passive forces, rod metric product, effective-metric stiffness, twist-state stepping), with C-vs-Warp parity tests for the twist hinge, box sections, indefinite Hessians and twist-state stepping. **Benchmark vs the old cable plugin** `testspeed -c opt`, single thread, best of 3, old and new interleaved. Old: plugin with Euler. New: flex with the discrete integrator. Time per `mj_step` in microseconds. | Segments | Old cable | New cable | Old belt | New belt | |---------:|----------:|----------:|---------:|---------:| | 5 | **25** | 58 | **17** | 46 | | 10 | **59** | 112 | **38** | 86 | | 20 | **164** | 240 | **103** | 179 | | 50 | 1062 | **542** | 756 | **407** | | 100 | 6915 | **596** | 4437 | **804** | | 200 | 30083 | **1143** | 29766 | **1649** | | 500 | 532844 | **2827** | 536544 | **4246** | - The old plugin is a chain of rigid bodies with a dense mass matrix (O(N^3)); the new rod is linear in N. Crossover: about 30 segments (cable) and 40-50 (belt). - The implicit-metric rod stiffness now evaluates the anisotropic chain once per flex (`rodChainWeights`), which made box-section rods linear (they were O(N^2)). Largest stable timestep (default 2 ms): | Model | 10 segments | 50 segments | 200 segments | |----------------------|-------------|-------------|--------------| | Old cable (Euler) | 64 ms | < 32 ms | < 16 ms | | Old belt (Euler) | 128 ms | < 32 ms | < 32 ms | | New cable (discrete) | >= 128 ms | >= 128 ms | >= 128 ms | | New belt (discrete) | >= 128 ms | >= 128 ms | >= 128 ms | Shipped scenes, time per step in microseconds: | Scene | Old | New | |--------------------|------|---------| | cable | 709 | **236** | | coil | 1164 | **622** | | belt (20 segments) | **119** | 154 | PiperOrigin-RevId: 1011913598 Change-Id: I20863ce8c5c3524992202c49939fe9f05529d910 --- dm_control/mjcf/physics_test.py | 31 +---- dm_control/mjcf/schema.xml | 198 +++---------------------------- dm_control/mujoco/engine_test.py | 44 ++++--- 3 files changed, 35 insertions(+), 238 deletions(-) diff --git a/dm_control/mjcf/physics_test.py b/dm_control/mjcf/physics_test.py index b10f42bb..e2c4a608 100644 --- a/dm_control/mjcf/physics_test.py +++ b/dm_control/mjcf/physics_test.py @@ -13,8 +13,6 @@ # limitations under the License. # ============================================================================ -"""Tests for `dm_control.mjcf.physics`.""" - import copy import os import pickle @@ -579,33 +577,6 @@ def test_error_when_pickling_synchronizing_array_wrapper(self): mjcf_physics._PICKLING_NOT_SUPPORTED.format(type=type(xpos_view))): pickle.dumps(xpos_view) - def test_plugins_elasticity(self): - root = mjcf.RootElement() - root.extension.add('plugin', plugin='mujoco.elasticity.cable') - - # Replicate example in mujoco/model/plugin/elasticity/cable.xml - composite = root.worldbody.add( - 'composite', - type='cable', - curve='s', - count=[41, 1, 1], - size=[1, 0, 0], - offset=[-0.3, 0, 0.6], - initial='none', - ) - plugin = composite.add('plugin', plugin='mujoco.elasticity.cable') - plugin.add('config', key='twist', value='1e7') - plugin.add('config', key='bend', value='4e6') - plugin.add('config', key='vmax', value='0.05') - composite.add('joint', kind='main', damping=0.015) - composite.geom.type = 'capsule' - composite.geom.size = [0.005, 0, 0] - composite.geom.rgba = [0.8, 0.2, 0.1, 1] - composite.geom.condim = 1 - - physics = mjcf.Physics.from_mjcf_model(root) - physics.step() - def test_plugins_sdf(self): root = mjcf.RootElement() root.option.sdf_iterations = 10 @@ -616,7 +587,7 @@ def test_plugins_sdf(self): instance.add('config', key='radius1', value='0.35') instance.add('config', key='radius2', value='0.15') - # Replicate example in mujoco/model/plugin/elasticity/torus.xml + # Replicate example in mujoco/model/plugin/sdf/torus.xml mesh = root.asset.add('mesh', name='torus') mesh.add('plugin', instance='torus') diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index 02413267..e9847b6f 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -327,6 +327,7 @@ + @@ -462,6 +463,7 @@ + @@ -746,6 +748,7 @@ + @@ -881,6 +884,7 @@ + @@ -1305,6 +1309,7 @@ + @@ -1458,98 +1463,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1594,9 +1507,11 @@ + + @@ -1771,98 +1686,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1907,9 +1730,11 @@ + + @@ -2006,9 +1831,11 @@ + + @@ -2086,6 +1913,7 @@ + @@ -2129,6 +1957,7 @@ + @@ -3299,6 +3128,7 @@ + diff --git a/dm_control/mujoco/engine_test.py b/dm_control/mujoco/engine_test.py index c4197a83..5471eee0 100644 --- a/dm_control/mujoco/engine_test.py +++ b/dm_control/mujoco/engine_test.py @@ -406,37 +406,27 @@ def testSetGetPhysicsState(self): ) def testSetGetPhysicsStateWithPlugin(self): - # Model copied from mujoco/test/plugin/elasticity/elasticity_test.cc - model_with_cable_plugin = """ + model_with_pid_plugin = """ - """ - physics = engine.Physics.from_xml_string(model_with_cable_plugin) + physics = engine.Physics.from_xml_string(model_with_pid_plugin) physics_state = physics.get_state() # qpos, qvel, act, plugin_state @@ -549,7 +539,10 @@ def assert_warning(): @parameterized.named_parameters( ('_copy', lambda x: x.copy()), ('_deepcopy', copy.deepcopy), - ('_pickle_and_unpickle', lambda x: pickle.loads(pickle.dumps(x))), + ( + '_pickle_and_unpickle', + lambda x: pickle.loads(pickle.dumps(x)), # pylint: disable=g-unsafe-pickle-load + ), ) def testCopyOrPicklePhysics(self, func): for _ in range(10): @@ -573,7 +566,10 @@ def testCopyOrPicklePhysics(self, func): @parameterized.named_parameters( ('_copy', lambda x: x.copy()), - ('_pickle_and_unpickle', lambda x: pickle.loads(pickle.dumps(x))), + ( + '_pickle_and_unpickle', + lambda x: pickle.loads(pickle.dumps(x)), # pylint: disable=g-unsafe-pickle-load + ), ) def testSuppressErrorsAfterCopyOrPicklePhysics(self, func): # Regression test for a problem that used to exist where From f9b2e9c304d3a07eb47dd82ade5b59735a368ff9 Mon Sep 17 00:00:00 2001 From: DeepMind Date: Fri, 6 Nov 2026 08:48:23 -0800 Subject: [PATCH 60/60] Update dm_control to version 1.0.51 and require MuJoCo 4.0.0 PiperOrigin-RevId: 1015588155 Change-Id: I5d02c240482271e7b28d9e75045afe61fba2cf67 --- dm_control/mjcf/schema.xml | 20 +++++++++++++------- dm_control/mujoco/tutorial.ipynb | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- tutorial.ipynb | 2 +- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/dm_control/mjcf/schema.xml b/dm_control/mjcf/schema.xml index e9847b6f..11aea4eb 100644 --- a/dm_control/mjcf/schema.xml +++ b/dm_control/mjcf/schema.xml @@ -176,7 +176,7 @@ - + @@ -456,7 +456,9 @@ + + @@ -469,6 +471,7 @@ + @@ -877,7 +880,9 @@ + + @@ -890,6 +895,7 @@ + @@ -1507,11 +1513,11 @@ - + - + @@ -1730,11 +1736,11 @@ - + - + @@ -1831,11 +1837,11 @@ - + - + diff --git a/dm_control/mujoco/tutorial.ipynb b/dm_control/mujoco/tutorial.ipynb index 0db0b38b..e577e4c2 100644 --- a/dm_control/mujoco/tutorial.ipynb +++ b/dm_control/mujoco/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.50\n", + "!pip install -q dm_control>=1.0.51\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n", diff --git a/requirements.txt b/requirements.txt index 82ef52ef..1f84f220 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ h5py==3.14.0 labmaze==1.0.6 lxml==6.0.1 mock==5.2.0 -mujoco==3.17.0 +mujoco==4.0.0 numpy==2.3.2; python_version >= '3.11' numpy==2.2.6; python_version == '3.10' numpy==2.0.2; python_version == '3.9' diff --git a/setup.py b/setup.py index b28c3601..3a6b4b91 100644 --- a/setup.py +++ b/setup.py @@ -166,7 +166,7 @@ def is_excluded(s): setup( name='dm_control', - version='1.0.50', + version='1.0.51', description='Continuous control environments and MuJoCo Python bindings.', long_description=""" # `dm_control`: DeepMind Infrastructure for Physics-Based Simulation. @@ -191,7 +191,7 @@ def is_excluded(s): 'glfw', 'labmaze', 'lxml', - 'mujoco >= 3.17.0', + 'mujoco >= 4.0.0', 'numpy >= 1.9.0', 'protobuf >= 3.19.4', 'pyopengl >= 3.1.4', diff --git a/tutorial.ipynb b/tutorial.ipynb index 3742876b..af7a48b1 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -91,7 +91,7 @@ "\"\"\")\n", "\n", "print('Installing dm_control...')\n", - "!pip install -q dm_control>=1.0.50\n", + "!pip install -q dm_control>=1.0.51\n", "\n", "# Configure dm_control to use the EGL rendering backend (requires GPU)\n", "%env MUJOCO_GL=egl\n",