Revert "fix mj_forward link typo"

This reverts commit 9f006dccdb.
This commit is contained in:
Alexis
2024-02-01 23:25:56 -04:00
parent 9f006dccdb
commit bfa359cb2e
+294 -307
View File
@@ -8,11 +8,11 @@
"source": [ "source": [
"![MuJoCo banner](https://raw.githubusercontent.com/google-deepmind/mujoco/main/banner.png)\n", "![MuJoCo banner](https://raw.githubusercontent.com/google-deepmind/mujoco/main/banner.png)\n",
"\n", "\n",
"# <h1><center>Tutorial <a href=\"https://colab.research.google.com/github/google-deepmind/mujoco/blob/main/python/tutorial.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" width=\"140\" align=\"center\"/></a></center></h1>\n", "# \u003ch1\u003e\u003ccenter\u003eTutorial \u003ca href=\"https://colab.research.google.com/github/google-deepmind/mujoco/blob/main/python/tutorial.ipynb\"\u003e\u003cimg src=\"https://colab.research.google.com/assets/colab-badge.svg\" width=\"140\" align=\"center\"/\u003e\u003c/a\u003e\u003c/center\u003e\u003c/h1\u003e\n",
"\n", "\n",
"This notebook provides an introductory tutorial for [**MuJoCo** physics](https://github.com/google-deepmind/mujoco#readme), using the native Python bindings.\n", "This notebook provides an introductory tutorial for [**MuJoCo** physics](https://github.com/google-deepmind/mujoco#readme), using the native Python bindings.\n",
"\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 > Change runtime type\".\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\".\n",
"\n", "\n",
"\n", "\n",
"\n", "\n",
@@ -38,9 +38,9 @@
"id": "_UbO9uhtBSX5" "id": "_UbO9uhtBSX5"
}, },
"source": [ "source": [
"> <p><small><small>Copyright 2022 DeepMind Technologies Limited.</small></p>\n", "\u003e \u003cp\u003e\u003csmall\u003e\u003csmall\u003eCopyright 2022 DeepMind Technologies Limited.\u003c/small\u003e\u003c/p\u003e\n",
"> <p><small><small>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 <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</a>.</small></small></p>\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",
"> <p><small><small>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.</small></small></p>" "\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"
] ]
}, },
{ {
@@ -107,7 +107,7 @@
"try:\n", "try:\n",
" print('Checking that the installation succeeded:')\n", " print('Checking that the installation succeeded:')\n",
" import mujoco\n", " import mujoco\n",
" mujoco.MjModel.from_xml_string('<mujoco/>')\n", " mujoco.MjModel.from_xml_string('\u003cmujoco/\u003e')\n",
"except Exception as e:\n", "except Exception as e:\n",
" raise e from RuntimeError(\n", " raise e from RuntimeError(\n",
" 'Something went wrong during installation. Check the shell output above '\n", " 'Something went wrong during installation. Check the shell output above '\n",
@@ -135,7 +135,7 @@
"\n", "\n",
"# Graphics and plotting.\n", "# Graphics and plotting.\n",
"print('Installing mediapy:')\n", "print('Installing mediapy:')\n",
"!command -v ffmpeg >/dev/null || (apt update && apt install -y ffmpeg)\n", "!command -v ffmpeg \u003e/dev/null || (apt update \u0026\u0026 apt install -y ffmpeg)\n",
"!pip install -q mediapy\n", "!pip install -q mediapy\n",
"import mediapy as media\n", "import mediapy as media\n",
"import matplotlib.pyplot as plt\n", "import matplotlib.pyplot as plt\n",
@@ -164,12 +164,12 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"xml = \"\"\"\n", "xml = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n", " \u003cgeom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/\u003e\n",
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n", " \u003cgeom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(xml)" "model = mujoco.MjModel.from_xml_string(xml)"
] ]
@@ -181,8 +181,8 @@
}, },
"source": [ "source": [
"The `xml` string is written in MuJoCo's [MJCF](http://www.mujoco.org/book/modeling.html), which is an [XML](https://en.wikipedia.org/wiki/XML#Key_terminology)-based modeling language.\n", "The `xml` string is written in MuJoCo's [MJCF](http://www.mujoco.org/book/modeling.html), which is an [XML](https://en.wikipedia.org/wiki/XML#Key_terminology)-based modeling language.\n",
" - The only required element is `<mujoco>`. The smallest valid MJCF model is `<mujoco/>` which is a completely empty model.\n", " - The only required element is `\u003cmujoco\u003e`. The smallest valid MJCF model is `\u003cmujoco/\u003e` which is a completely empty model.\n",
" - All physical elements live inside the `<worldbody>` which is always the top-level body and constitutes the global origin in Cartesian coordinates.\n", " - All physical elements live inside the `\u003cworldbody\u003e` which is always the top-level body and constitutes the global origin in Cartesian coordinates.\n",
" - We define two geoms in the world named `red_box` and `green_sphere`.\n", " - We define two geoms in the world named `red_box` and `green_sphere`.\n",
" - **Question:** The `red_box` has no position, the `green_sphere` has no type, why is that?\n", " - **Question:** The `red_box` has no position, the `green_sphere` has no type, why is that?\n",
" - **Answer:** MJCF attributes have *default values*. The default position is `0 0 0`, the default geom type is `sphere`. The MJCF language is described in the documentation's [XML Reference chapter](https://mujoco.readthedocs.io/en/latest/XMLreference.html).\n", " - **Answer:** MJCF attributes have *default values*. The default position is `0 0 0`, the default geom type is `sphere`. The MJCF language is described in the documentation's [XML Reference chapter](https://mujoco.readthedocs.io/en/latest/XMLreference.html).\n",
@@ -442,12 +442,12 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"xml = \"\"\"\n", "xml = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n", " \u003cgeom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/\u003e\n",
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n", " \u003cgeom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"# Make model and data\n", "# Make model and data\n",
"model = mujoco.MjModel.from_xml_string(xml)\n", "model = mujoco.MjModel.from_xml_string(xml)\n",
@@ -466,7 +466,7 @@
"source": [ "source": [
"Hmmm, why the black pixels?\n", "Hmmm, why the black pixels?\n",
"\n", "\n",
"**Answer:** For the same reason as above, we first need to propagate the values in `mjData`. This time we'll call [`mj_forward`](https://mujoco.readthedocs.io/en/latest/APIreference/APIfunctions.html#mj-forward), which invokes the entire pipeline up to the computation of accelerations i.e., it computes $\\dot x = f(x)$, where $x$ is the state. This function does more than we actually need, but unless we care about saving computation time, it's good practice to call `mj_forward` since then we know we are not missing anything.\n", "**Answer:** For the same reason as above, we first need to propagate the values in `mjData`. This time we'll call [`mj_forward`](https://mujoco.readthedocs.io/en/latest/APIreference.html#mj-forward), which invokes the entire pipeline up to the computation of accelerations i.e., it computes $\\dot x = f(x)$, where $x$ is the state. This function does more than we actually need, but unless we care about saving computation time, it's good practice to call `mj_forward` since then we know we are not missing anything.\n",
"\n", "\n",
"We also need to update the `mjvScene` which is an object held by the renderer describing the visual scene. We'll later see that the scene can include visual objects which are not part of the physical model." "We also need to update the `mjvScene` which is an object held by the renderer describing the visual scene. We'll later see that the scene can include visual objects which are not part of the physical model."
] ]
@@ -503,13 +503,13 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"xml = \"\"\"\n", "xml = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <light name=\"top\" pos=\"0 0 1\"/>\n", " \u003clight name=\"top\" pos=\"0 0 1\"/\u003e\n",
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n", " \u003cgeom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/\u003e\n",
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n", " \u003cgeom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(xml)\n", "model = mujoco.MjModel.from_xml_string(xml)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
@@ -573,9 +573,9 @@
"# Simulate and display video.\n", "# Simulate and display video.\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetData(model, data) # Reset state and time.\n", "mujoco.mj_resetData(model, data) # Reset state and time.\n",
"while data.time < duration:\n", "while data.time \u003c duration:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" if len(frames) < data.time * framerate:\n", " if len(frames) \u003c data.time * framerate:\n",
" renderer.update_scene(data)\n", " renderer.update_scene(data)\n",
" pixels = renderer.render()\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n", " frames.append(pixels)\n",
@@ -590,7 +590,7 @@
"source": [ "source": [
"Hmmm, the video is playing, but nothing is moving, why is that?\n", "Hmmm, the video is playing, but nothing is moving, why is that?\n",
"\n", "\n",
"This is because this model has no [degrees of freedom](https://www.google.com/url?sa=D&q=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FDegrees_of_freedom_(mechanics)) (DoFs). The things that move (and which have inertia) are called *bodies*. We add DoFs by adding *joints* to bodies, specifying how they can move with respect to their parents. Let's make a new body that contains our geoms, add a hinge joint and re-render, while visualizing the joint axis using the visualization option object `MjvOption`." "This is because this model has no [degrees of freedom](https://www.google.com/url?sa=D\u0026q=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FDegrees_of_freedom_(mechanics)) (DoFs). The things that move (and which have inertia) are called *bodies*. We add DoFs by adding *joints* to bodies, specifying how they can move with respect to their parents. Let's make a new body that contains our geoms, add a hinge joint and re-render, while visualizing the joint axis using the visualization option object `MjvOption`."
] ]
}, },
{ {
@@ -602,16 +602,16 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"xml = \"\"\"\n", "xml = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <light name=\"top\" pos=\"0 0 1\"/>\n", " \u003clight name=\"top\" pos=\"0 0 1\"/\u003e\n",
" <body name=\"box_and_sphere\" euler=\"0 0 -30\">\n", " \u003cbody name=\"box_and_sphere\" euler=\"0 0 -30\"\u003e\n",
" <joint name=\"swing\" type=\"hinge\" axis=\"1 -1 0\" pos=\"-.2 -.2 -.2\"/>\n", " \u003cjoint name=\"swing\" type=\"hinge\" axis=\"1 -1 0\" pos=\"-.2 -.2 -.2\"/\u003e\n",
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n", " \u003cgeom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/\u003e\n",
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n", " \u003cgeom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(xml)\n", "model = mujoco.MjModel.from_xml_string(xml)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
@@ -626,9 +626,9 @@
"\n", "\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"while data.time < duration:\n", "while data.time \u003c duration:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" if len(frames) < data.time * framerate:\n", " if len(frames) \u003c data.time * framerate:\n",
" renderer.update_scene(data, scene_option=scene_option)\n", " renderer.update_scene(data, scene_option=scene_option)\n",
" pixels = renderer.render()\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n", " frames.append(pixels)\n",
@@ -643,7 +643,7 @@
"id": "Ymv-tvWCpl6V" "id": "Ymv-tvWCpl6V"
}, },
"source": [ "source": [
"Note that we rotated the `box_and_sphere` body by 30° around the Z (vertical) axis, with the directive `euler=\"0 0 -30\"`. This was made to emphasize that the poses of elements in the [kinematic tree](https://www.google.com/url?sa=D&q=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FKinematic_chain) are always with respect to their *parent body*, so our two geoms were also rotated by this transformation.\n", "Note that we rotated the `box_and_sphere` body by 30° around the Z (vertical) axis, with the directive `euler=\"0 0 -30\"`. This was made to emphasize that the poses of elements in the [kinematic tree](https://www.google.com/url?sa=D\u0026q=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FKinematic_chain) are always with respect to their *parent body*, so our two geoms were also rotated by this transformation.\n",
"\n", "\n",
"Physics options live in `mjModel.opt`, for example the timestep:" "Physics options live in `mjModel.opt`, for example the timestep:"
] ]
@@ -682,9 +682,9 @@
"\n", "\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"while data.time < duration:\n", "while data.time \u003c duration:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" if len(frames) < data.time * framerate:\n", " if len(frames) \u003c data.time * framerate:\n",
" renderer.update_scene(data, scene_option=scene_option)\n", " renderer.update_scene(data, scene_option=scene_option)\n",
" pixels = renderer.render()\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n", " frames.append(pixels)\n",
@@ -698,12 +698,12 @@
"id": "FsxDDgXBqg_J" "id": "FsxDDgXBqg_J"
}, },
"source": [ "source": [
"We could also have done this in XML using the top-level `<option>` element:\n", "We could also have done this in XML using the top-level `\u003coption\u003e` element:\n",
"```xml\n", "```xml\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <option gravity=\"0 0 10\"/>\n", " \u003coption gravity=\"0 0 10\"/\u003e\n",
" ...\n", " ...\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"```" "```"
] ]
}, },
@@ -750,7 +750,7 @@
"source": [ "source": [
"# Example: Simulating free bodies with the self-inverting \"tippe-top\"\n", "# Example: Simulating free bodies with the self-inverting \"tippe-top\"\n",
"\n", "\n",
"A free body is a body with a [free joint](https://www.google.com/url?sa=D&q=https%3A%2F%2Fmujoco.readthedocs.io%2Fen%2Flatest%2FXMLreference.html%3Fhighlight%3Dfreejoint%23body-freejoint) having 6 DoFs, i.e., 3 translations and 3 rotations. We could give our `box_and_sphere` body a free joint and watch it fall, but let's look at something more interesting. A \"tippe top\" is a spinning toy which flips itself ([video](https://www.youtube.com/watch?v=kbYpVrdcszQ), [Wikipedia](https://en.wikipedia.org/wiki/Tippe_top)). We model it as follows:" "A free body is a body with a [free joint](https://www.google.com/url?sa=D\u0026q=https%3A%2F%2Fmujoco.readthedocs.io%2Fen%2Flatest%2FXMLreference.html%3Fhighlight%3Dfreejoint%23body-freejoint) having 6 DoFs, i.e., 3 translations and 3 rotations. We could give our `box_and_sphere` body a free joint and watch it fall, but let's look at something more interesting. A \"tippe top\" is a spinning toy which flips itself ([video](https://www.youtube.com/watch?v=kbYpVrdcszQ), [Wikipedia](https://en.wikipedia.org/wiki/Tippe_top)). We model it as follows:"
] ]
}, },
{ {
@@ -762,32 +762,32 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"tippe_top = \"\"\"\n", "tippe_top = \"\"\"\n",
"<mujoco model=\"tippe top\">\n", "\u003cmujoco model=\"tippe top\"\u003e\n",
" <option integrator=\"RK4\"/>\n", " \u003coption integrator=\"RK4\"/\u003e\n",
"\n", "\n",
" <asset>\n", " \u003casset\u003e\n",
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n", " \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\"/>\n", " rgb2=\".2 .3 .4\" width=\"300\" height=\"300\"/\u003e\n",
" <material name=\"grid\" texture=\"grid\" texrepeat=\"8 8\" reflectance=\".2\"/>\n", " \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"8 8\" reflectance=\".2\"/\u003e\n",
" </asset>\n", " \u003c/asset\u003e\n",
"\n", "\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <geom size=\".2 .2 .01\" type=\"plane\" material=\"grid\"/>\n", " \u003cgeom size=\".2 .2 .01\" type=\"plane\" material=\"grid\"/\u003e\n",
" <light pos=\"0 0 .6\"/>\n", " \u003clight pos=\"0 0 .6\"/\u003e\n",
" <camera name=\"closeup\" pos=\"0 -.1 .07\" xyaxes=\"1 0 0 0 1 2\"/>\n", " \u003ccamera name=\"closeup\" pos=\"0 -.1 .07\" xyaxes=\"1 0 0 0 1 2\"/\u003e\n",
" <body name=\"top\" pos=\"0 0 .02\">\n", " \u003cbody name=\"top\" pos=\"0 0 .02\"\u003e\n",
" <freejoint/>\n", " \u003cfreejoint/\u003e\n",
" <geom name=\"ball\" type=\"sphere\" size=\".02\" />\n", " \u003cgeom name=\"ball\" type=\"sphere\" size=\".02\" /\u003e\n",
" <geom name=\"stem\" type=\"cylinder\" pos=\"0 0 .02\" size=\"0.004 .008\"/>\n", " \u003cgeom name=\"stem\" type=\"cylinder\" pos=\"0 0 .02\" size=\"0.004 .008\"/\u003e\n",
" <geom name=\"ballast\" type=\"box\" size=\".023 .023 0.005\" pos=\"0 0 -.015\"\n", " \u003cgeom name=\"ballast\" type=\"box\" size=\".023 .023 0.005\" pos=\"0 0 -.015\"\n",
" contype=\"0\" conaffinity=\"0\" group=\"3\"/>\n", " contype=\"0\" conaffinity=\"0\" group=\"3\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"\n", "\n",
" <keyframe>\n", " \u003ckeyframe\u003e\n",
" <key name=\"spinning\" qpos=\"0 0 0.02 1 0 0 0\" qvel=\"0 0 0 0 1 200\" />\n", " \u003ckey name=\"spinning\" qpos=\"0 0 0.02 1 0 0 0\" qvel=\"0 0 0 0 1 200\" /\u003e\n",
" </keyframe>\n", " \u003c/keyframe\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(tippe_top)\n", "model = mujoco.MjModel.from_xml_string(tippe_top)\n",
"renderer = mujoco.Renderer(model)\n", "renderer = mujoco.Renderer(model)\n",
@@ -804,12 +804,12 @@
}, },
"source": [ "source": [
"Note several new features of this model definition:\n", "Note several new features of this model definition:\n",
"1. A 6-DoF free joint is added with the `<freejoint/>` clause.\n", "1. A 6-DoF free joint is added with the `\u003cfreejoint/\u003e` clause.\n",
"2. We use the `<option/>` clause to set the integrator to the 4th order [Runge Kutta](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods). Runge-Kutta has a higher rate of convergence than the default Euler integrator, which in many cases increases the accuracy at a given timestep size.\n", "2. We use the `\u003coption/\u003e` clause to set the integrator to the 4th order [Runge Kutta](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods). Runge-Kutta has a higher rate of convergence than the default Euler integrator, which in many cases increases the accuracy at a given timestep size.\n",
"3. We define the floor's grid material inside the `<asset/>` clause and reference it in the `\"floor\"` geom.\n", "3. We define the floor's grid material inside the `\u003casset/\u003e` clause and reference it in the `\"floor\"` geom.\n",
"4. We use an invisible and non-colliding box geom called `ballast` to move the top's center-of-mass lower. Having a low center of mass is (counter-intuitively) required for the flipping behavior to occur.\n", "4. We use an invisible and non-colliding box geom called `ballast` to move the top's center-of-mass lower. Having a low center of mass is (counter-intuitively) required for the flipping behavior to occur.\n",
"5. We save our initial spinning state as a *keyframe*. It has a high rotational velocity around the Z-axis, but is not perfectly oriented with the world, which introduces the symmetry-breaking required for the flipping.\n", "5. We save our initial spinning state as a *keyframe*. It has a high rotational velocity around the Z-axis, but is not perfectly oriented with the world, which introduces the symmetry-breaking required for the flipping.\n",
"6. We define a `<camera>` in our model, and then render from it using the `camera` argument to `update_scene()`.\n", "6. We define a `\u003ccamera\u003e` in our model, and then render from it using the `camera` argument to `update_scene()`.\n",
"Let us examine the state:\n" "Let us examine the state:\n"
] ]
}, },
@@ -850,9 +850,9 @@
"# Simulate and display video.\n", "# Simulate and display video.\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetDataKeyframe(model, data, 0) # Reset the state to keyframe 0\n", "mujoco.mj_resetDataKeyframe(model, data, 0) # Reset the state to keyframe 0\n",
"while data.time < duration:\n", "while data.time \u003c duration:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" if len(frames) < data.time * framerate:\n", " if len(frames) \u003c data.time * framerate:\n",
" renderer.update_scene(data, \"closeup\")\n", " renderer.update_scene(data, \"closeup\")\n",
" pixels = renderer.render()\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n", " frames.append(pixels)\n",
@@ -884,7 +884,7 @@
"\n", "\n",
"# Simulate and save data\n", "# Simulate and save data\n",
"mujoco.mj_resetDataKeyframe(model, data, 0)\n", "mujoco.mj_resetDataKeyframe(model, data, 0)\n",
"while data.time < duration:\n", "while data.time \u003c duration:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" timevals.append(data.time)\n", " timevals.append(data.time)\n",
" angular_velocity.append(data.qvel[3:6].copy())\n", " angular_velocity.append(data.qvel[3:6].copy())\n",
@@ -933,38 +933,38 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"chaotic_pendulum = \"\"\"\n", "chaotic_pendulum = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <option timestep=\".001\">\n", " \u003coption timestep=\".001\"\u003e\n",
" <flag energy=\"enable\" contact=\"disable\"/>\n", " \u003cflag energy=\"enable\" contact=\"disable\"/\u003e\n",
" </option>\n", " \u003c/option\u003e\n",
"\n", "\n",
" <default>\n", " \u003cdefault\u003e\n",
" <joint type=\"hinge\" axis=\"0 -1 0\"/>\n", " \u003cjoint type=\"hinge\" axis=\"0 -1 0\"/\u003e\n",
" <geom type=\"capsule\" size=\".02\"/>\n", " \u003cgeom type=\"capsule\" size=\".02\"/\u003e\n",
" </default>\n", " \u003c/default\u003e\n",
"\n", "\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <light pos=\"0 -.4 1\"/>\n", " \u003clight pos=\"0 -.4 1\"/\u003e\n",
" <camera name=\"fixed\" pos=\"0 -1 0\" xyaxes=\"1 0 0 0 0 1\"/>\n", " \u003ccamera name=\"fixed\" pos=\"0 -1 0\" xyaxes=\"1 0 0 0 0 1\"/\u003e\n",
" <body name=\"0\" pos=\"0 0 .2\">\n", " \u003cbody name=\"0\" pos=\"0 0 .2\"\u003e\n",
" <joint name=\"root\"/>\n", " \u003cjoint name=\"root\"/\u003e\n",
" <geom fromto=\"-.2 0 0 .2 0 0\" rgba=\"1 1 0 1\"/>\n", " \u003cgeom fromto=\"-.2 0 0 .2 0 0\" rgba=\"1 1 0 1\"/\u003e\n",
" <geom fromto=\"0 0 0 0 0 -.25\" rgba=\"1 1 0 1\"/>\n", " \u003cgeom fromto=\"0 0 0 0 0 -.25\" rgba=\"1 1 0 1\"/\u003e\n",
" <body name=\"1\" pos=\"-.2 0 0\">\n", " \u003cbody name=\"1\" pos=\"-.2 0 0\"\u003e\n",
" <joint/>\n", " \u003cjoint/\u003e\n",
" <geom fromto=\"0 0 0 0 0 -.2\" rgba=\"1 0 0 1\"/>\n", " \u003cgeom fromto=\"0 0 0 0 0 -.2\" rgba=\"1 0 0 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" <body name=\"2\" pos=\".2 0 0\">\n", " \u003cbody name=\"2\" pos=\".2 0 0\"\u003e\n",
" <joint/>\n", " \u003cjoint/\u003e\n",
" <geom fromto=\"0 0 0 0 0 -.2\" rgba=\"0 1 0 1\"/>\n", " \u003cgeom fromto=\"0 0 0 0 0 -.2\" rgba=\"0 1 0 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" <body name=\"3\" pos=\"0 0 -.25\">\n", " \u003cbody name=\"3\" pos=\"0 0 -.25\"\u003e\n",
" <joint/>\n", " \u003cjoint/\u003e\n",
" <geom fromto=\"0 0 0 0 0 -.2\" rgba=\"0 0 1 1\"/>\n", " \u003cgeom fromto=\"0 0 0 0 0 -.2\" rgba=\"0 0 1 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(chaotic_pendulum)\n", "model = mujoco.MjModel.from_xml_string(chaotic_pendulum)\n",
"renderer = mujoco.Renderer(model, 480, 640)\n", "renderer = mujoco.Renderer(model, 480, 640)\n",
@@ -1011,7 +1011,7 @@
"render_time = 0\n", "render_time = 0\n",
"n_steps = 0\n", "n_steps = 0\n",
"for i in range(n_frames):\n", "for i in range(n_frames):\n",
" while data.time * framerate < i:\n", " while data.time * framerate \u003c i:\n",
" tic = time.time()\n", " tic = time.time()\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" sim_time += time.time() - tic\n", " sim_time += time.time() - tic\n",
@@ -1240,26 +1240,26 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"free_body_MJCF = \"\"\"\n", "free_body_MJCF = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <asset>\n", " \u003casset\u003e\n",
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n", " \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"edge\" markrgb=\".2 .3 .4\"/>\n", " rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"edge\" markrgb=\".2 .3 .4\"/\u003e\n",
" <material name=\"grid\" texture=\"grid\" texrepeat=\"2 2\" texuniform=\"true\"\n", " \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"2 2\" texuniform=\"true\"\n",
" reflectance=\".2\"/>\n", " reflectance=\".2\"/\u003e\n",
" </asset>\n", " \u003c/asset\u003e\n",
"\n", "\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <light pos=\"0 0 1\" mode=\"trackcom\"/>\n", " \u003clight pos=\"0 0 1\" mode=\"trackcom\"/\u003e\n",
" <geom name=\"ground\" type=\"plane\" pos=\"0 0 -.5\" size=\"2 2 .1\" material=\"grid\" solimp=\".99 .99 .01\" solref=\".001 1\"/>\n", " \u003cgeom name=\"ground\" type=\"plane\" pos=\"0 0 -.5\" size=\"2 2 .1\" material=\"grid\" solimp=\".99 .99 .01\" solref=\".001 1\"/\u003e\n",
" <body name=\"box_and_sphere\" pos=\"0 0 0\">\n", " \u003cbody name=\"box_and_sphere\" pos=\"0 0 0\"\u003e\n",
" <freejoint/>\n", " \u003cfreejoint/\u003e\n",
" <geom name=\"red_box\" type=\"box\" size=\".1 .1 .1\" rgba=\"1 0 0 1\" solimp=\".99 .99 .01\" solref=\".001 1\"/>\n", " \u003cgeom name=\"red_box\" type=\"box\" size=\".1 .1 .1\" rgba=\"1 0 0 1\" solimp=\".99 .99 .01\" solref=\".001 1\"/\u003e\n",
" <geom name=\"green_sphere\" size=\".06\" pos=\".1 .1 .1\" rgba=\"0 1 0 1\"/>\n", " \u003cgeom name=\"green_sphere\" size=\".06\" pos=\".1 .1 .1\" rgba=\"0 1 0 1\"/\u003e\n",
" <camera name=\"fixed\" pos=\"0 -.6 .3\" xyaxes=\"1 0 0 0 1 2\"/>\n", " \u003ccamera name=\"fixed\" pos=\"0 -.6 .3\" xyaxes=\"1 0 0 0 1 2\"/\u003e\n",
" <camera name=\"track\" pos=\"0 -.6 .3\" xyaxes=\"1 0 0 0 1 2\" mode=\"track\"/>\n", " \u003ccamera name=\"track\" pos=\"0 -.6 .3\" xyaxes=\"1 0 0 0 1 2\" mode=\"track\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(free_body_MJCF)\n", "model = mujoco.MjModel.from_xml_string(free_body_MJCF)\n",
"renderer = mujoco.Renderer(model, 400, 600)\n", "renderer = mujoco.Renderer(model, 400, 600)\n",
@@ -1311,7 +1311,7 @@
"\n", "\n",
"# simulate and render\n", "# simulate and render\n",
"for i in range(n_frames):\n", "for i in range(n_frames):\n",
" while data.time < i/120.0: #1/4x real time\n", " while data.time \u003c i/120.0: #1/4x real time\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" renderer.update_scene(data, \"track\", options)\n", " renderer.update_scene(data, \"track\", options)\n",
" frame = renderer.render()\n", " frame = renderer.render()\n",
@@ -1430,36 +1430,36 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"MJCF = \"\"\"\n", "MJCF = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <asset>\n", " \u003casset\u003e\n",
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n", " \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"none\"/>\n", " rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"none\"/\u003e\n",
" <material name=\"grid\" texture=\"grid\" texrepeat=\"6 6\"\n", " \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"6 6\"\n",
" texuniform=\"true\" reflectance=\".2\"/>\n", " texuniform=\"true\" reflectance=\".2\"/\u003e\n",
" <material name=\"wall\" rgba='.5 .5 .5 1'/>\n", " \u003cmaterial name=\"wall\" rgba='.5 .5 .5 1'/\u003e\n",
" </asset>\n", " \u003c/asset\u003e\n",
"\n", "\n",
" <default>\n", " \u003cdefault\u003e\n",
" <geom type=\"box\" size=\".05 .05 .05\" />\n", " \u003cgeom type=\"box\" size=\".05 .05 .05\" /\u003e\n",
" <joint type=\"free\"/>\n", " \u003cjoint type=\"free\"/\u003e\n",
" </default>\n", " \u003c/default\u003e\n",
"\n", "\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <light name=\"light\" pos=\"-.2 0 1\"/>\n", " \u003clight name=\"light\" pos=\"-.2 0 1\"/\u003e\n",
" <geom name=\"ground\" type=\"plane\" size=\".5 .5 10\" material=\"grid\"\n", " \u003cgeom name=\"ground\" type=\"plane\" size=\".5 .5 10\" material=\"grid\"\n",
" zaxis=\"-.3 0 1\" friction=\".1\"/>\n", " zaxis=\"-.3 0 1\" friction=\".1\"/\u003e\n",
" <camera name=\"y\" pos=\"-.1 -.6 .3\" xyaxes=\"1 0 0 0 1 2\"/>\n", " \u003ccamera name=\"y\" pos=\"-.1 -.6 .3\" xyaxes=\"1 0 0 0 1 2\"/\u003e\n",
" <body pos=\"0 0 .1\">\n", " \u003cbody pos=\"0 0 .1\"\u003e\n",
" <joint/>\n", " \u003cjoint/\u003e\n",
" <geom/>\n", " \u003cgeom/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" <body pos=\"0 .2 .1\">\n", " \u003cbody pos=\"0 .2 .1\"\u003e\n",
" <joint/>\n", " \u003cjoint/\u003e\n",
" <geom friction=\".33\"/>\n", " \u003cgeom friction=\".33\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"\n", "\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"n_frames = 60\n", "n_frames = 60\n",
"height = 300\n", "height = 300\n",
@@ -1474,7 +1474,7 @@
"# simulate and render\n", "# simulate and render\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"for i in range(n_frames):\n", "for i in range(n_frames):\n",
" while data.time < i/30.0:\n", " while data.time \u003c i/30.0:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" renderer.update_scene(data, \"y\")\n", " renderer.update_scene(data, \"y\")\n",
" frame = renderer.render()\n", " frame = renderer.render()\n",
@@ -1500,51 +1500,51 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"MJCF = \"\"\"\n", "MJCF = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <asset>\n", " \u003casset\u003e\n",
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n", " \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"none\"/>\n", " rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"none\"/\u003e\n",
" <material name=\"grid\" texture=\"grid\" texrepeat=\"1 1\"\n", " \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"1 1\"\n",
" texuniform=\"true\" reflectance=\".2\"/>\n", " texuniform=\"true\" reflectance=\".2\"/\u003e\n",
" </asset>\n", " \u003c/asset\u003e\n",
"\n", "\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <light name=\"light\" pos=\"0 0 1\"/>\n", " \u003clight name=\"light\" pos=\"0 0 1\"/\u003e\n",
" <geom name=\"floor\" type=\"plane\" pos=\"0 0 -.5\" size=\"2 2 .1\" material=\"grid\"/>\n", " \u003cgeom name=\"floor\" type=\"plane\" pos=\"0 0 -.5\" size=\"2 2 .1\" material=\"grid\"/\u003e\n",
" <site name=\"anchor\" pos=\"0 0 .3\" size=\".01\"/>\n", " \u003csite name=\"anchor\" pos=\"0 0 .3\" size=\".01\"/\u003e\n",
" <camera name=\"fixed\" pos=\"0 -1.3 .5\" xyaxes=\"1 0 0 0 1 2\"/>\n", " \u003ccamera name=\"fixed\" pos=\"0 -1.3 .5\" xyaxes=\"1 0 0 0 1 2\"/\u003e\n",
"\n", "\n",
" <geom name=\"pole\" type=\"cylinder\" fromto=\".3 0 -.5 .3 0 -.1\" size=\".04\"/>\n", " \u003cgeom name=\"pole\" type=\"cylinder\" fromto=\".3 0 -.5 .3 0 -.1\" size=\".04\"/\u003e\n",
" <body name=\"bat\" pos=\".3 0 -.1\">\n", " \u003cbody name=\"bat\" pos=\".3 0 -.1\"\u003e\n",
" <joint name=\"swing\" type=\"hinge\" damping=\"1\" axis=\"0 0 1\"/>\n", " \u003cjoint name=\"swing\" type=\"hinge\" damping=\"1\" axis=\"0 0 1\"/\u003e\n",
" <geom name=\"bat\" type=\"capsule\" fromto=\"0 0 .04 0 -.3 .04\"\n", " \u003cgeom name=\"bat\" type=\"capsule\" fromto=\"0 0 .04 0 -.3 .04\"\n",
" size=\".04\" rgba=\"0 0 1 1\"/>\n", " size=\".04\" rgba=\"0 0 1 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body name=\"box_and_sphere\" pos=\"0 0 0\">\n", " \u003cbody name=\"box_and_sphere\" pos=\"0 0 0\"\u003e\n",
" <joint name=\"free\" type=\"free\"/>\n", " \u003cjoint name=\"free\" type=\"free\"/\u003e\n",
" <geom name=\"red_box\" type=\"box\" size=\".1 .1 .1\" rgba=\"1 0 0 1\"/>\n", " \u003cgeom name=\"red_box\" type=\"box\" size=\".1 .1 .1\" rgba=\"1 0 0 1\"/\u003e\n",
" <geom name=\"green_sphere\" size=\".06\" pos=\".1 .1 .1\" rgba=\"0 1 0 1\"/>\n", " \u003cgeom name=\"green_sphere\" size=\".06\" pos=\".1 .1 .1\" rgba=\"0 1 0 1\"/\u003e\n",
" <site name=\"hook\" pos=\"-.1 -.1 -.1\" size=\".01\"/>\n", " \u003csite name=\"hook\" pos=\"-.1 -.1 -.1\" size=\".01\"/\u003e\n",
" <site name=\"IMU\"/>\n", " \u003csite name=\"IMU\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"\n", "\n",
" <tendon>\n", " \u003ctendon\u003e\n",
" <spatial name=\"wire\" limited=\"true\" range=\"0 0.35\" width=\"0.003\">\n", " \u003cspatial name=\"wire\" limited=\"true\" range=\"0 0.35\" width=\"0.003\"\u003e\n",
" <site site=\"anchor\"/>\n", " \u003csite site=\"anchor\"/\u003e\n",
" <site site=\"hook\"/>\n", " \u003csite site=\"hook\"/\u003e\n",
" </spatial>\n", " \u003c/spatial\u003e\n",
" </tendon>\n", " \u003c/tendon\u003e\n",
"\n", "\n",
" <actuator>\n", " \u003cactuator\u003e\n",
" <motor name=\"my_motor\" joint=\"swing\" gear=\"1\"/>\n", " \u003cmotor name=\"my_motor\" joint=\"swing\" gear=\"1\"/\u003e\n",
" </actuator>\n", " \u003c/actuator\u003e\n",
"\n", "\n",
" <sensor>\n", " \u003csensor\u003e\n",
" <accelerometer name=\"accelerometer\" site=\"IMU\"/>\n", " \u003caccelerometer name=\"accelerometer\" site=\"IMU\"/\u003e\n",
" </sensor>\n", " \u003c/sensor\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(MJCF)\n", "model = mujoco.MjModel.from_xml_string(MJCF)\n",
"renderer = mujoco.Renderer(model, 480, 480)\n", "renderer = mujoco.Renderer(model, 480, 480)\n",
@@ -1587,7 +1587,7 @@
"\n", "\n",
"# simulate and render\n", "# simulate and render\n",
"for i in range(n_frames):\n", "for i in range(n_frames):\n",
" while data.time < i/fps:\n", " while data.time \u003c i/fps:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" times.append(data.time)\n", " times.append(data.time)\n",
" sensordata.append(data.sensor('accelerometer').data.copy())\n", " sensordata.append(data.sensor('accelerometer').data.copy())\n",
@@ -1658,16 +1658,16 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"xml = \"\"\"\n", "xml = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <light name=\"top\" pos=\"0 0 1\"/>\n", " \u003clight name=\"top\" pos=\"0 0 1\"/\u003e\n",
" <body name=\"box_and_sphere\" euler=\"0 0 -30\">\n", " \u003cbody name=\"box_and_sphere\" euler=\"0 0 -30\"\u003e\n",
" <joint name=\"swing\" type=\"hinge\" axis=\"1 -1 0\" pos=\"-.2 -.2 -.2\"/>\n", " \u003cjoint name=\"swing\" type=\"hinge\" axis=\"1 -1 0\" pos=\"-.2 -.2 -.2\"/\u003e\n",
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n", " \u003cgeom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/\u003e\n",
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n", " \u003cgeom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(xml)\n", "model = mujoco.MjModel.from_xml_string(xml)\n",
"renderer = mujoco.Renderer(model)\n", "renderer = mujoco.Renderer(model)\n",
@@ -1717,7 +1717,7 @@
"# Shift nearest values to the origin.\n", "# Shift nearest values to the origin.\n",
"depth -= depth.min()\n", "depth -= depth.min()\n",
"# Scale by 2 mean distances of near rays.\n", "# Scale by 2 mean distances of near rays.\n",
"depth /= 2*depth[depth <= 1].mean()\n", "depth /= 2*depth[depth \u003c= 1].mean()\n",
"# Scale to [0, 255]\n", "# Scale to [0, 255]\n",
"pixels = 255*np.clip(depth, 0, 1)\n", "pixels = 255*np.clip(depth, 0, 1)\n",
"\n", "\n",
@@ -1888,7 +1888,7 @@
"\n", "\n",
"def add_visual_capsule(scene, point1, point2, radius, rgba):\n", "def add_visual_capsule(scene, point1, point2, radius, rgba):\n",
" \"\"\"Adds one capsule to an mjvScene.\"\"\"\n", " \"\"\"Adds one capsule to an mjvScene.\"\"\"\n",
" if scene.ngeom >= scene.maxgeom:\n", " if scene.ngeom \u003e= scene.maxgeom:\n",
" return\n", " return\n",
" scene.ngeom += 1 # increment ngeom\n", " scene.ngeom += 1 # increment ngeom\n",
" # initialise a new capsule, add it to the scene using mjv_makeConnector\n", " # initialise a new capsule, add it to the scene using mjv_makeConnector\n",
@@ -1908,7 +1908,7 @@
"\n", "\n",
"def modify_scene(scn):\n", "def modify_scene(scn):\n",
" \"\"\"Draw position trace, speed modifies width and colors.\"\"\"\n", " \"\"\"Draw position trace, speed modifies width and colors.\"\"\"\n",
" if len(positions) > 1:\n", " if len(positions) \u003e 1:\n",
" for i in range(len(positions)-1):\n", " for i in range(len(positions)-1):\n",
" rgba=np.array((np.clip(speeds[i]/10, 0, 1),\n", " rgba=np.array((np.clip(speeds[i]/10, 0, 1),\n",
" np.clip(1-speeds[i]/10, 0, 1),\n", " np.clip(1-speeds[i]/10, 0, 1),\n",
@@ -1928,13 +1928,13 @@
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"mujoco.mj_forward(model, data)\n", "mujoco.mj_forward(model, data)\n",
"\n", "\n",
"while data.time < duration:\n", "while data.time \u003c duration:\n",
" # append data to the traces\n", " # append data to the traces\n",
" positions.append(data.geom_xpos[data.geom(\"green_sphere\").id].copy())\n", " positions.append(data.geom_xpos[data.geom(\"green_sphere\").id].copy())\n",
" times.append(data.time)\n", " times.append(data.time)\n",
" speeds.append(get_geom_speed(model, data, \"green_sphere\"))\n", " speeds.append(get_geom_speed(model, data, \"green_sphere\"))\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" if len(frames) < data.time * framerate:\n", " if len(frames) \u003c data.time * framerate:\n",
" renderer.update_scene(data)\n", " renderer.update_scene(data)\n",
" modify_scene(renderer.scene)\n", " modify_scene(renderer.scene)\n",
" pixels = renderer.render()\n", " pixels = renderer.render()\n",
@@ -1966,88 +1966,88 @@
"source": [ "source": [
"#@title Load the \"dominos\" model\n", "#@title Load the \"dominos\" model\n",
"dominos_xml = \"\"\"\n", "dominos_xml = \"\"\"\n",
"<mujoco>\n", "\u003cmujoco\u003e\n",
" <asset>\n", " \u003casset\u003e\n",
" <texture type=\"skybox\" builtin=\"gradient\" rgb1=\".3 .5 .7\" rgb2=\"0 0 0\" width=\"32\" height=\"512\"/>\n", " \u003ctexture type=\"skybox\" builtin=\"gradient\" rgb1=\".3 .5 .7\" rgb2=\"0 0 0\" width=\"32\" height=\"512\"/\u003e\n",
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" width=\"512\" height=\"512\" rgb1=\".1 .2 .3\" rgb2=\".2 .3 .4\"/>\n", " \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" width=\"512\" height=\"512\" rgb1=\".1 .2 .3\" rgb2=\".2 .3 .4\"/\u003e\n",
" <material name=\"grid\" texture=\"grid\" texrepeat=\"2 2\" texuniform=\"true\" reflectance=\".2\"/>\n", " \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"2 2\" texuniform=\"true\" reflectance=\".2\"/\u003e\n",
" </asset>\n", " \u003c/asset\u003e\n",
"\n", "\n",
" <statistic meansize=\".01\"/>\n", " \u003cstatistic meansize=\".01\"/\u003e\n",
"\n", "\n",
" <visual>\n", " \u003cvisual\u003e\n",
" <global offheight=\"2160\" offwidth=\"3840\"/>\n", " \u003cglobal offheight=\"2160\" offwidth=\"3840\"/\u003e\n",
" <quality offsamples=\"8\"/>\n", " \u003cquality offsamples=\"8\"/\u003e\n",
" </visual>\n", " \u003c/visual\u003e\n",
"\n", "\n",
" <default>\n", " \u003cdefault\u003e\n",
" <geom type=\"box\" solref=\".005 1\"/>\n", " \u003cgeom type=\"box\" solref=\".005 1\"/\u003e\n",
" <default class=\"static\">\n", " \u003cdefault class=\"static\"\u003e\n",
" <geom rgba=\".3 .5 .7 1\"/>\n", " \u003cgeom rgba=\".3 .5 .7 1\"/\u003e\n",
" </default>\n", " \u003c/default\u003e\n",
" </default>\n", " \u003c/default\u003e\n",
"\n", "\n",
" <option timestep=\"5e-4\"/>\n", " \u003coption timestep=\"5e-4\"/\u003e\n",
"\n", "\n",
" <worldbody>\n", " \u003cworldbody\u003e\n",
" <light pos=\".3 -.3 .8\" mode=\"trackcom\" diffuse=\"1 1 1\" specular=\".3 .3 .3\"/>\n", " \u003clight pos=\".3 -.3 .8\" mode=\"trackcom\" diffuse=\"1 1 1\" specular=\".3 .3 .3\"/\u003e\n",
" <light pos=\"0 -.3 .4\" mode=\"targetbodycom\" target=\"box\" diffuse=\".8 .8 .8\" specular=\".3 .3 .3\"/>\n", " \u003clight pos=\"0 -.3 .4\" mode=\"targetbodycom\" target=\"box\" diffuse=\".8 .8 .8\" specular=\".3 .3 .3\"/\u003e\n",
" <geom name=\"floor\" type=\"plane\" size=\"3 3 .01\" pos=\"-0.025 -0.295 0\" material=\"grid\"/>\n", " \u003cgeom name=\"floor\" type=\"plane\" size=\"3 3 .01\" pos=\"-0.025 -0.295 0\" material=\"grid\"/\u003e\n",
" <geom name=\"ramp\" pos=\".25 -.45 -.03\" size=\".04 .1 .07\" euler=\"-30 0 0\" class=\"static\"/>\n", " \u003cgeom name=\"ramp\" pos=\".25 -.45 -.03\" size=\".04 .1 .07\" euler=\"-30 0 0\" class=\"static\"/\u003e\n",
" <camera name=\"top\" pos=\"-0.37 -0.78 0.49\" xyaxes=\"0.78 -0.63 0 0.27 0.33 0.9\"/>\n", " \u003ccamera name=\"top\" pos=\"-0.37 -0.78 0.49\" xyaxes=\"0.78 -0.63 0 0.27 0.33 0.9\"/\u003e\n",
"\n", "\n",
" <body name=\"ball\" pos=\".25 -.45 .1\">\n", " \u003cbody name=\"ball\" pos=\".25 -.45 .1\"\u003e\n",
" <freejoint name=\"ball\"/>\n", " \u003cfreejoint name=\"ball\"/\u003e\n",
" <geom name=\"ball\" type=\"sphere\" size=\".02\" rgba=\".65 .81 .55 1\"/>\n", " \u003cgeom name=\"ball\" type=\"sphere\" size=\".02\" rgba=\".65 .81 .55 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body pos=\".26 -.3 .03\" euler=\"0 0 -90.0\">\n", " \u003cbody pos=\".26 -.3 .03\" euler=\"0 0 -90.0\"\u003e\n",
" <freejoint/>\n", " \u003cfreejoint/\u003e\n",
" <geom size=\".0015 .015 .03\" rgba=\"1 .5 .5 1\"/>\n", " \u003cgeom size=\".0015 .015 .03\" rgba=\"1 .5 .5 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body pos=\".26 -.27 .04\" euler=\"0 0 -81.0\">\n", " \u003cbody pos=\".26 -.27 .04\" euler=\"0 0 -81.0\"\u003e\n",
" <freejoint/>\n", " \u003cfreejoint/\u003e\n",
" <geom size=\".002 .02 .04\" rgba=\"1 1 .5 1\"/>\n", " \u003cgeom size=\".002 .02 .04\" rgba=\"1 1 .5 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body pos=\".24 -.21 .06\" euler=\"0 0 -63.0\">\n", " \u003cbody pos=\".24 -.21 .06\" euler=\"0 0 -63.0\"\u003e\n",
" <freejoint/>\n", " \u003cfreejoint/\u003e\n",
" <geom size=\".003 .03 .06\" rgba=\".5 1 .5 1\"/>\n", " \u003cgeom size=\".003 .03 .06\" rgba=\".5 1 .5 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body pos=\".2 -.16 .08\" euler=\"0 0 -45.0\">\n", " \u003cbody pos=\".2 -.16 .08\" euler=\"0 0 -45.0\"\u003e\n",
" <freejoint/>\n", " \u003cfreejoint/\u003e\n",
" <geom size=\".004 .04 .08\" rgba=\".5 1 1 1\"/>\n", " \u003cgeom size=\".004 .04 .08\" rgba=\".5 1 1 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body pos=\".15 -.12 .1\" euler=\"0 0 -27.0\">\n", " \u003cbody pos=\".15 -.12 .1\" euler=\"0 0 -27.0\"\u003e\n",
" <freejoint/>\n", " \u003cfreejoint/\u003e\n",
" <geom size=\".005 .05 .1\" rgba=\".5 .5 1 1\"/>\n", " \u003cgeom size=\".005 .05 .1\" rgba=\".5 .5 1 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body pos=\".09 -.1 .12\" euler=\"0 0 -9.0\">\n", " \u003cbody pos=\".09 -.1 .12\" euler=\"0 0 -9.0\"\u003e\n",
" <freejoint/>\n", " \u003cfreejoint/\u003e\n",
" <geom size=\".006 .06 .12\" rgba=\"1 .5 1 1\"/>\n", " \u003cgeom size=\".006 .06 .12\" rgba=\"1 .5 1 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body name=\"seasaw_wrapper\" pos=\"-.23 -.1 0\" euler=\"0 0 30\">\n", " \u003cbody name=\"seasaw_wrapper\" pos=\"-.23 -.1 0\" euler=\"0 0 30\"\u003e\n",
" <geom size=\".01 .01 .015\" pos=\"0 .05 .015\" class=\"static\"/>\n", " \u003cgeom size=\".01 .01 .015\" pos=\"0 .05 .015\" class=\"static\"/\u003e\n",
" <geom size=\".01 .01 .015\" pos=\"0 -.05 .015\" class=\"static\"/>\n", " \u003cgeom size=\".01 .01 .015\" pos=\"0 -.05 .015\" class=\"static\"/\u003e\n",
" <geom type=\"cylinder\" size=\".01 .0175\" pos=\"-.09 0 .0175\" class=\"static\"/>\n", " \u003cgeom type=\"cylinder\" size=\".01 .0175\" pos=\"-.09 0 .0175\" class=\"static\"/\u003e\n",
" <body name=\"seasaw\" pos=\"0 0 .03\">\n", " \u003cbody name=\"seasaw\" pos=\"0 0 .03\"\u003e\n",
" <joint axis=\"0 1 0\"/>\n", " \u003cjoint axis=\"0 1 0\"/\u003e\n",
" <geom type=\"cylinder\" size=\".005 .039\" zaxis=\"0 1 0\" rgba=\".84 .15 .33 1\"/>\n", " \u003cgeom type=\"cylinder\" size=\".005 .039\" zaxis=\"0 1 0\" rgba=\".84 .15 .33 1\"/\u003e\n",
" <geom size=\".1 .02 .005\" pos=\"0 0 .01\" rgba=\".84 .15 .33 1\"/>\n", " \u003cgeom size=\".1 .02 .005\" pos=\"0 0 .01\" rgba=\".84 .15 .33 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
"\n", "\n",
" <body name=\"box\" pos=\"-.3 -.14 .05501\" euler=\"0 0 -30\">\n", " \u003cbody name=\"box\" pos=\"-.3 -.14 .05501\" euler=\"0 0 -30\"\u003e\n",
" <freejoint name=\"box\"/>\n", " \u003cfreejoint name=\"box\"/\u003e\n",
" <geom name=\"box\" size=\".01 .01 .01\" rgba=\".0 .7 .79 1\"/>\n", " \u003cgeom name=\"box\" size=\".01 .01 .01\" rgba=\".0 .7 .79 1\"/\u003e\n",
" </body>\n", " \u003c/body\u003e\n",
" </worldbody>\n", " \u003c/worldbody\u003e\n",
"</mujoco>\n", "\u003c/mujoco\u003e\n",
"\"\"\"\n", "\"\"\"\n",
"model = mujoco.MjModel.from_xml_string(dominos_xml)\n", "model = mujoco.MjModel.from_xml_string(dominos_xml)\n",
"data = mujoco.MjData(model)\n", "data = mujoco.MjData(model)\n",
@@ -2070,9 +2070,9 @@
"# Simulate and display video.\n", "# Simulate and display video.\n",
"frames = []\n", "frames = []\n",
"mujoco.mj_resetData(model, data) # Reset state and time.\n", "mujoco.mj_resetData(model, data) # Reset state and time.\n",
"while data.time < duration:\n", "while data.time \u003c duration:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" if len(frames) < data.time * framerate:\n", " if len(frames) \u003c data.time * framerate:\n",
" renderer.update_scene(data, camera='top')\n", " renderer.update_scene(data, camera='top')\n",
" pixels = renderer.render()\n", " pixels = renderer.render()\n",
" frames.append(pixels)\n", " frames.append(pixels)\n",
@@ -2091,15 +2091,15 @@
"#@title Render from moving camera\n", "#@title Render from moving camera\n",
"duration = 3 # (seconds)\n", "duration = 3 # (seconds)\n",
"\n", "\n",
"# find time when box is thrown (speed > 2cm/s)\n", "# find time when box is thrown (speed \u003e 2cm/s)\n",
"throw_time = 0.0\n", "throw_time = 0.0\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"while data.time < duration and not throw_time:\n", "while data.time \u003c duration and not throw_time:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" box_speed = np.linalg.norm(data.joint('box').qvel[:3])\n", " box_speed = np.linalg.norm(data.joint('box').qvel[:3])\n",
" if box_speed > 0.02:\n", " if box_speed \u003e 0.02:\n",
" throw_time = data.time\n", " throw_time = data.time\n",
"assert throw_time > 0\n", "assert throw_time \u003e 0\n",
"\n", "\n",
"def mix(time, t0=0.0, width=1.0):\n", "def mix(time, t0=0.0, width=1.0):\n",
" \"\"\"Sigmoidal mixing function.\"\"\"\n", " \"\"\"Sigmoidal mixing function.\"\"\"\n",
@@ -2144,9 +2144,9 @@
"slowdown = 4 # 4x slow-down\n", "slowdown = 4 # 4x slow-down\n",
"mujoco.mj_resetData(model, data)\n", "mujoco.mj_resetData(model, data)\n",
"frames = []\n", "frames = []\n",
"while data.time < duration:\n", "while data.time \u003c duration:\n",
" mujoco.mj_step(model, data)\n", " mujoco.mj_step(model, data)\n",
" if len(frames) < data.time * framerate * slowdown:\n", " if len(frames) \u003c data.time * framerate * slowdown:\n",
" cam.distance, cam.azimuth, cam.elevation, cam.lookat = cam_motion()\n", " cam.distance, cam.azimuth, cam.elevation, cam.lookat = cam_motion()\n",
" renderer.update_scene(data, cam)\n", " renderer.update_scene(data, cam)\n",
" pixels = renderer.render()\n", " pixels = renderer.render()\n",
@@ -2167,23 +2167,10 @@
}, },
"gpuClass": "premium", "gpuClass": "premium",
"kernelspec": { "kernelspec": {
"display_name": "Python 3 (ipykernel)", "display_name": "Python 3",
"language": "python",
"name": "python3" "name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
} }
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 4 "nbformat_minor": 0
} }