+294
-307
@@ -8,11 +8,11 @@
|
||||
"source": [
|
||||
"\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",
|
||||
"This notebook provides an introductory tutorial for [**MuJoCo** physics](https://github.com/google-deepmind/mujoco#readme), using the native Python bindings.\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",
|
||||
@@ -38,9 +38,9 @@
|
||||
"id": "_UbO9uhtBSX5"
|
||||
},
|
||||
"source": [
|
||||
"> <p><small><small>Copyright 2022 DeepMind Technologies Limited.</small></p>\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",
|
||||
"> <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\u003eCopyright 2022 DeepMind Technologies Limited.\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"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -107,7 +107,7 @@
|
||||
"try:\n",
|
||||
" print('Checking that the installation succeeded:')\n",
|
||||
" import mujoco\n",
|
||||
" mujoco.MjModel.from_xml_string('<mujoco/>')\n",
|
||||
" mujoco.MjModel.from_xml_string('\u003cmujoco/\u003e')\n",
|
||||
"except Exception as e:\n",
|
||||
" raise e from RuntimeError(\n",
|
||||
" 'Something went wrong during installation. Check the shell output above '\n",
|
||||
@@ -135,7 +135,7 @@
|
||||
"\n",
|
||||
"# Graphics and plotting.\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",
|
||||
"import mediapy as media\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
@@ -164,12 +164,12 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"xml = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <worldbody>\n",
|
||||
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n",
|
||||
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n",
|
||||
" </worldbody>\n",
|
||||
"</mujoco>\n",
|
||||
"\u003cmujoco\u003e\n",
|
||||
" \u003cworldbody\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",
|
||||
"model = mujoco.MjModel.from_xml_string(xml)"
|
||||
]
|
||||
@@ -181,8 +181,8 @@
|
||||
},
|
||||
"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 only required element is `<mujoco>`. The smallest valid MJCF model is `<mujoco/>` 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",
|
||||
" - 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 `\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",
|
||||
" - **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",
|
||||
@@ -442,12 +442,12 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"xml = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <worldbody>\n",
|
||||
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n",
|
||||
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n",
|
||||
" </worldbody>\n",
|
||||
"</mujoco>\n",
|
||||
"\u003cmujoco\u003e\n",
|
||||
" \u003cworldbody\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",
|
||||
"# Make model and data\n",
|
||||
"model = mujoco.MjModel.from_xml_string(xml)\n",
|
||||
@@ -466,7 +466,7 @@
|
||||
"source": [
|
||||
"Hmmm, why the black pixels?\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",
|
||||
"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": [],
|
||||
"source": [
|
||||
"xml = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <worldbody>\n",
|
||||
" <light name=\"top\" pos=\"0 0 1\"/>\n",
|
||||
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n",
|
||||
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n",
|
||||
" </worldbody>\n",
|
||||
"</mujoco>\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",
|
||||
"model = mujoco.MjModel.from_xml_string(xml)\n",
|
||||
"data = mujoco.MjData(model)\n",
|
||||
@@ -573,9 +573,9 @@
|
||||
"# Simulate and display video.\n",
|
||||
"frames = []\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",
|
||||
" if len(frames) < data.time * framerate:\n",
|
||||
" if len(frames) \u003c data.time * framerate:\n",
|
||||
" renderer.update_scene(data)\n",
|
||||
" pixels = renderer.render()\n",
|
||||
" frames.append(pixels)\n",
|
||||
@@ -590,7 +590,7 @@
|
||||
"source": [
|
||||
"Hmmm, the video is playing, but nothing is moving, why is that?\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": [],
|
||||
"source": [
|
||||
"xml = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <worldbody>\n",
|
||||
" <light name=\"top\" pos=\"0 0 1\"/>\n",
|
||||
" <body name=\"box_and_sphere\" euler=\"0 0 -30\">\n",
|
||||
" <joint name=\"swing\" type=\"hinge\" axis=\"1 -1 0\" pos=\"-.2 -.2 -.2\"/>\n",
|
||||
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n",
|
||||
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n",
|
||||
" </body>\n",
|
||||
" </worldbody>\n",
|
||||
"</mujoco>\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",
|
||||
"model = mujoco.MjModel.from_xml_string(xml)\n",
|
||||
"data = mujoco.MjData(model)\n",
|
||||
@@ -626,9 +626,9 @@
|
||||
"\n",
|
||||
"frames = []\n",
|
||||
"mujoco.mj_resetData(model, data)\n",
|
||||
"while data.time < duration:\n",
|
||||
"while data.time \u003c duration:\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",
|
||||
" pixels = renderer.render()\n",
|
||||
" frames.append(pixels)\n",
|
||||
@@ -643,7 +643,7 @@
|
||||
"id": "Ymv-tvWCpl6V"
|
||||
},
|
||||
"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",
|
||||
"Physics options live in `mjModel.opt`, for example the timestep:"
|
||||
]
|
||||
@@ -682,9 +682,9 @@
|
||||
"\n",
|
||||
"frames = []\n",
|
||||
"mujoco.mj_resetData(model, data)\n",
|
||||
"while data.time < duration:\n",
|
||||
"while data.time \u003c duration:\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",
|
||||
" pixels = renderer.render()\n",
|
||||
" frames.append(pixels)\n",
|
||||
@@ -698,12 +698,12 @@
|
||||
"id": "FsxDDgXBqg_J"
|
||||
},
|
||||
"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",
|
||||
"<mujoco>\n",
|
||||
" <option gravity=\"0 0 10\"/>\n",
|
||||
"\u003cmujoco\u003e\n",
|
||||
" \u003coption gravity=\"0 0 10\"/\u003e\n",
|
||||
" ...\n",
|
||||
"</mujoco>\n",
|
||||
"\u003c/mujoco\u003e\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
@@ -750,7 +750,7 @@
|
||||
"source": [
|
||||
"# Example: Simulating free bodies with the self-inverting \"tippe-top\"\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": [],
|
||||
"source": [
|
||||
"tippe_top = \"\"\"\n",
|
||||
"<mujoco model=\"tippe top\">\n",
|
||||
" <option integrator=\"RK4\"/>\n",
|
||||
"\u003cmujoco model=\"tippe top\"\u003e\n",
|
||||
" \u003coption integrator=\"RK4\"/\u003e\n",
|
||||
"\n",
|
||||
" <asset>\n",
|
||||
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
|
||||
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\"/>\n",
|
||||
" <material name=\"grid\" texture=\"grid\" texrepeat=\"8 8\" reflectance=\".2\"/>\n",
|
||||
" </asset>\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",
|
||||
" <worldbody>\n",
|
||||
" <geom size=\".2 .2 .01\" type=\"plane\" material=\"grid\"/>\n",
|
||||
" <light pos=\"0 0 .6\"/>\n",
|
||||
" <camera name=\"closeup\" pos=\"0 -.1 .07\" xyaxes=\"1 0 0 0 1 2\"/>\n",
|
||||
" <body name=\"top\" pos=\"0 0 .02\">\n",
|
||||
" <freejoint/>\n",
|
||||
" <geom name=\"ball\" type=\"sphere\" size=\".02\" />\n",
|
||||
" <geom name=\"stem\" type=\"cylinder\" pos=\"0 0 .02\" size=\"0.004 .008\"/>\n",
|
||||
" <geom name=\"ballast\" type=\"box\" size=\".023 .023 0.005\" pos=\"0 0 -.015\"\n",
|
||||
" contype=\"0\" conaffinity=\"0\" group=\"3\"/>\n",
|
||||
" </body>\n",
|
||||
" </worldbody>\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",
|
||||
" <keyframe>\n",
|
||||
" <key name=\"spinning\" qpos=\"0 0 0.02 1 0 0 0\" qvel=\"0 0 0 0 1 200\" />\n",
|
||||
" </keyframe>\n",
|
||||
"</mujoco>\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",
|
||||
"model = mujoco.MjModel.from_xml_string(tippe_top)\n",
|
||||
"renderer = mujoco.Renderer(model)\n",
|
||||
@@ -804,12 +804,12 @@
|
||||
},
|
||||
"source": [
|
||||
"Note several new features of this model definition:\n",
|
||||
"1. A 6-DoF free joint is added with the `<freejoint/>` 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",
|
||||
"3. We define the floor's grid material inside the `<asset/>` clause and reference it in the `\"floor\"` geom.\n",
|
||||
"1. A 6-DoF free joint is added with the `\u003cfreejoint/\u003e` clause.\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 `\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",
|
||||
"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"
|
||||
]
|
||||
},
|
||||
@@ -850,9 +850,9 @@
|
||||
"# Simulate and display video.\n",
|
||||
"frames = []\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",
|
||||
" if len(frames) < data.time * framerate:\n",
|
||||
" if len(frames) \u003c data.time * framerate:\n",
|
||||
" renderer.update_scene(data, \"closeup\")\n",
|
||||
" pixels = renderer.render()\n",
|
||||
" frames.append(pixels)\n",
|
||||
@@ -884,7 +884,7 @@
|
||||
"\n",
|
||||
"# Simulate and save data\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",
|
||||
" timevals.append(data.time)\n",
|
||||
" angular_velocity.append(data.qvel[3:6].copy())\n",
|
||||
@@ -933,38 +933,38 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chaotic_pendulum = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <option timestep=\".001\">\n",
|
||||
" <flag energy=\"enable\" contact=\"disable\"/>\n",
|
||||
" </option>\n",
|
||||
"\u003cmujoco\u003e\n",
|
||||
" \u003coption timestep=\".001\"\u003e\n",
|
||||
" \u003cflag energy=\"enable\" contact=\"disable\"/\u003e\n",
|
||||
" \u003c/option\u003e\n",
|
||||
"\n",
|
||||
" <default>\n",
|
||||
" <joint type=\"hinge\" axis=\"0 -1 0\"/>\n",
|
||||
" <geom type=\"capsule\" size=\".02\"/>\n",
|
||||
" </default>\n",
|
||||
" \u003cdefault\u003e\n",
|
||||
" \u003cjoint type=\"hinge\" axis=\"0 -1 0\"/\u003e\n",
|
||||
" \u003cgeom type=\"capsule\" size=\".02\"/\u003e\n",
|
||||
" \u003c/default\u003e\n",
|
||||
"\n",
|
||||
" <worldbody>\n",
|
||||
" <light pos=\"0 -.4 1\"/>\n",
|
||||
" <camera name=\"fixed\" pos=\"0 -1 0\" xyaxes=\"1 0 0 0 0 1\"/>\n",
|
||||
" <body name=\"0\" pos=\"0 0 .2\">\n",
|
||||
" <joint name=\"root\"/>\n",
|
||||
" <geom fromto=\"-.2 0 0 .2 0 0\" rgba=\"1 1 0 1\"/>\n",
|
||||
" <geom fromto=\"0 0 0 0 0 -.25\" rgba=\"1 1 0 1\"/>\n",
|
||||
" <body name=\"1\" pos=\"-.2 0 0\">\n",
|
||||
" <joint/>\n",
|
||||
" <geom fromto=\"0 0 0 0 0 -.2\" rgba=\"1 0 0 1\"/>\n",
|
||||
" </body>\n",
|
||||
" <body name=\"2\" pos=\".2 0 0\">\n",
|
||||
" <joint/>\n",
|
||||
" <geom fromto=\"0 0 0 0 0 -.2\" rgba=\"0 1 0 1\"/>\n",
|
||||
" </body>\n",
|
||||
" <body name=\"3\" pos=\"0 0 -.25\">\n",
|
||||
" <joint/>\n",
|
||||
" <geom fromto=\"0 0 0 0 0 -.2\" rgba=\"0 0 1 1\"/>\n",
|
||||
" </body>\n",
|
||||
" </body>\n",
|
||||
" </worldbody>\n",
|
||||
"</mujoco>\n",
|
||||
" \u003cworldbody\u003e\n",
|
||||
" \u003clight pos=\"0 -.4 1\"/\u003e\n",
|
||||
" \u003ccamera name=\"fixed\" pos=\"0 -1 0\" xyaxes=\"1 0 0 0 0 1\"/\u003e\n",
|
||||
" \u003cbody name=\"0\" pos=\"0 0 .2\"\u003e\n",
|
||||
" \u003cjoint name=\"root\"/\u003e\n",
|
||||
" \u003cgeom fromto=\"-.2 0 0 .2 0 0\" rgba=\"1 1 0 1\"/\u003e\n",
|
||||
" \u003cgeom fromto=\"0 0 0 0 0 -.25\" rgba=\"1 1 0 1\"/\u003e\n",
|
||||
" \u003cbody name=\"1\" pos=\"-.2 0 0\"\u003e\n",
|
||||
" \u003cjoint/\u003e\n",
|
||||
" \u003cgeom fromto=\"0 0 0 0 0 -.2\" rgba=\"1 0 0 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003cbody name=\"2\" pos=\".2 0 0\"\u003e\n",
|
||||
" \u003cjoint/\u003e\n",
|
||||
" \u003cgeom fromto=\"0 0 0 0 0 -.2\" rgba=\"0 1 0 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003cbody name=\"3\" pos=\"0 0 -.25\"\u003e\n",
|
||||
" \u003cjoint/\u003e\n",
|
||||
" \u003cgeom fromto=\"0 0 0 0 0 -.2\" rgba=\"0 0 1 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003c/worldbody\u003e\n",
|
||||
"\u003c/mujoco\u003e\n",
|
||||
"\"\"\"\n",
|
||||
"model = mujoco.MjModel.from_xml_string(chaotic_pendulum)\n",
|
||||
"renderer = mujoco.Renderer(model, 480, 640)\n",
|
||||
@@ -1011,7 +1011,7 @@
|
||||
"render_time = 0\n",
|
||||
"n_steps = 0\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",
|
||||
" mujoco.mj_step(model, data)\n",
|
||||
" sim_time += time.time() - tic\n",
|
||||
@@ -1240,26 +1240,26 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"free_body_MJCF = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <asset>\n",
|
||||
" <texture 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",
|
||||
" <material name=\"grid\" texture=\"grid\" texrepeat=\"2 2\" texuniform=\"true\"\n",
|
||||
" reflectance=\".2\"/>\n",
|
||||
" </asset>\n",
|
||||
"\u003cmujoco\u003e\n",
|
||||
" \u003casset\u003e\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\"/\u003e\n",
|
||||
" \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"2 2\" texuniform=\"true\"\n",
|
||||
" reflectance=\".2\"/\u003e\n",
|
||||
" \u003c/asset\u003e\n",
|
||||
"\n",
|
||||
" <worldbody>\n",
|
||||
" <light pos=\"0 0 1\" mode=\"trackcom\"/>\n",
|
||||
" <geom name=\"ground\" type=\"plane\" pos=\"0 0 -.5\" size=\"2 2 .1\" material=\"grid\" solimp=\".99 .99 .01\" solref=\".001 1\"/>\n",
|
||||
" <body name=\"box_and_sphere\" pos=\"0 0 0\">\n",
|
||||
" <freejoint/>\n",
|
||||
" <geom name=\"red_box\" type=\"box\" size=\".1 .1 .1\" rgba=\"1 0 0 1\" solimp=\".99 .99 .01\" solref=\".001 1\"/>\n",
|
||||
" <geom name=\"green_sphere\" size=\".06\" pos=\".1 .1 .1\" rgba=\"0 1 0 1\"/>\n",
|
||||
" <camera name=\"fixed\" pos=\"0 -.6 .3\" xyaxes=\"1 0 0 0 1 2\"/>\n",
|
||||
" <camera name=\"track\" pos=\"0 -.6 .3\" xyaxes=\"1 0 0 0 1 2\" mode=\"track\"/>\n",
|
||||
" </body>\n",
|
||||
" </worldbody>\n",
|
||||
"</mujoco>\n",
|
||||
" \u003cworldbody\u003e\n",
|
||||
" \u003clight pos=\"0 0 1\" mode=\"trackcom\"/\u003e\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",
|
||||
" \u003cbody name=\"box_and_sphere\" pos=\"0 0 0\"\u003e\n",
|
||||
" \u003cfreejoint/\u003e\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",
|
||||
" \u003cgeom name=\"green_sphere\" size=\".06\" pos=\".1 .1 .1\" rgba=\"0 1 0 1\"/\u003e\n",
|
||||
" \u003ccamera name=\"fixed\" pos=\"0 -.6 .3\" xyaxes=\"1 0 0 0 1 2\"/\u003e\n",
|
||||
" \u003ccamera name=\"track\" pos=\"0 -.6 .3\" xyaxes=\"1 0 0 0 1 2\" mode=\"track\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003c/worldbody\u003e\n",
|
||||
"\u003c/mujoco\u003e\n",
|
||||
"\"\"\"\n",
|
||||
"model = mujoco.MjModel.from_xml_string(free_body_MJCF)\n",
|
||||
"renderer = mujoco.Renderer(model, 400, 600)\n",
|
||||
@@ -1311,7 +1311,7 @@
|
||||
"\n",
|
||||
"# simulate and render\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",
|
||||
" renderer.update_scene(data, \"track\", options)\n",
|
||||
" frame = renderer.render()\n",
|
||||
@@ -1430,36 +1430,36 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"MJCF = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <asset>\n",
|
||||
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
|
||||
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"none\"/>\n",
|
||||
" <material name=\"grid\" texture=\"grid\" texrepeat=\"6 6\"\n",
|
||||
" texuniform=\"true\" reflectance=\".2\"/>\n",
|
||||
" <material name=\"wall\" rgba='.5 .5 .5 1'/>\n",
|
||||
" </asset>\n",
|
||||
"\u003cmujoco\u003e\n",
|
||||
" \u003casset\u003e\n",
|
||||
" \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
|
||||
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"none\"/\u003e\n",
|
||||
" \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"6 6\"\n",
|
||||
" texuniform=\"true\" reflectance=\".2\"/\u003e\n",
|
||||
" \u003cmaterial name=\"wall\" rgba='.5 .5 .5 1'/\u003e\n",
|
||||
" \u003c/asset\u003e\n",
|
||||
"\n",
|
||||
" <default>\n",
|
||||
" <geom type=\"box\" size=\".05 .05 .05\" />\n",
|
||||
" <joint type=\"free\"/>\n",
|
||||
" </default>\n",
|
||||
" \u003cdefault\u003e\n",
|
||||
" \u003cgeom type=\"box\" size=\".05 .05 .05\" /\u003e\n",
|
||||
" \u003cjoint type=\"free\"/\u003e\n",
|
||||
" \u003c/default\u003e\n",
|
||||
"\n",
|
||||
" <worldbody>\n",
|
||||
" <light name=\"light\" pos=\"-.2 0 1\"/>\n",
|
||||
" <geom name=\"ground\" type=\"plane\" size=\".5 .5 10\" material=\"grid\"\n",
|
||||
" zaxis=\"-.3 0 1\" friction=\".1\"/>\n",
|
||||
" <camera name=\"y\" pos=\"-.1 -.6 .3\" xyaxes=\"1 0 0 0 1 2\"/>\n",
|
||||
" <body pos=\"0 0 .1\">\n",
|
||||
" <joint/>\n",
|
||||
" <geom/>\n",
|
||||
" </body>\n",
|
||||
" <body pos=\"0 .2 .1\">\n",
|
||||
" <joint/>\n",
|
||||
" <geom friction=\".33\"/>\n",
|
||||
" </body>\n",
|
||||
" </worldbody>\n",
|
||||
" \u003cworldbody\u003e\n",
|
||||
" \u003clight name=\"light\" pos=\"-.2 0 1\"/\u003e\n",
|
||||
" \u003cgeom name=\"ground\" type=\"plane\" size=\".5 .5 10\" material=\"grid\"\n",
|
||||
" zaxis=\"-.3 0 1\" friction=\".1\"/\u003e\n",
|
||||
" \u003ccamera name=\"y\" pos=\"-.1 -.6 .3\" xyaxes=\"1 0 0 0 1 2\"/\u003e\n",
|
||||
" \u003cbody pos=\"0 0 .1\"\u003e\n",
|
||||
" \u003cjoint/\u003e\n",
|
||||
" \u003cgeom/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003cbody pos=\"0 .2 .1\"\u003e\n",
|
||||
" \u003cjoint/\u003e\n",
|
||||
" \u003cgeom friction=\".33\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003c/worldbody\u003e\n",
|
||||
"\n",
|
||||
"</mujoco>\n",
|
||||
"\u003c/mujoco\u003e\n",
|
||||
"\"\"\"\n",
|
||||
"n_frames = 60\n",
|
||||
"height = 300\n",
|
||||
@@ -1474,7 +1474,7 @@
|
||||
"# simulate and render\n",
|
||||
"mujoco.mj_resetData(model, data)\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",
|
||||
" renderer.update_scene(data, \"y\")\n",
|
||||
" frame = renderer.render()\n",
|
||||
@@ -1500,51 +1500,51 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"MJCF = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <asset>\n",
|
||||
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
|
||||
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"none\"/>\n",
|
||||
" <material name=\"grid\" texture=\"grid\" texrepeat=\"1 1\"\n",
|
||||
" texuniform=\"true\" reflectance=\".2\"/>\n",
|
||||
" </asset>\n",
|
||||
"\u003cmujoco\u003e\n",
|
||||
" \u003casset\u003e\n",
|
||||
" \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" rgb1=\".1 .2 .3\"\n",
|
||||
" rgb2=\".2 .3 .4\" width=\"300\" height=\"300\" mark=\"none\"/\u003e\n",
|
||||
" \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"1 1\"\n",
|
||||
" texuniform=\"true\" reflectance=\".2\"/\u003e\n",
|
||||
" \u003c/asset\u003e\n",
|
||||
"\n",
|
||||
" <worldbody>\n",
|
||||
" <light name=\"light\" pos=\"0 0 1\"/>\n",
|
||||
" <geom name=\"floor\" type=\"plane\" pos=\"0 0 -.5\" size=\"2 2 .1\" material=\"grid\"/>\n",
|
||||
" <site name=\"anchor\" pos=\"0 0 .3\" size=\".01\"/>\n",
|
||||
" <camera name=\"fixed\" pos=\"0 -1.3 .5\" xyaxes=\"1 0 0 0 1 2\"/>\n",
|
||||
" \u003cworldbody\u003e\n",
|
||||
" \u003clight name=\"light\" pos=\"0 0 1\"/\u003e\n",
|
||||
" \u003cgeom name=\"floor\" type=\"plane\" pos=\"0 0 -.5\" size=\"2 2 .1\" material=\"grid\"/\u003e\n",
|
||||
" \u003csite name=\"anchor\" pos=\"0 0 .3\" size=\".01\"/\u003e\n",
|
||||
" \u003ccamera name=\"fixed\" pos=\"0 -1.3 .5\" xyaxes=\"1 0 0 0 1 2\"/\u003e\n",
|
||||
"\n",
|
||||
" <geom name=\"pole\" type=\"cylinder\" fromto=\".3 0 -.5 .3 0 -.1\" size=\".04\"/>\n",
|
||||
" <body name=\"bat\" pos=\".3 0 -.1\">\n",
|
||||
" <joint name=\"swing\" type=\"hinge\" damping=\"1\" axis=\"0 0 1\"/>\n",
|
||||
" <geom name=\"bat\" type=\"capsule\" fromto=\"0 0 .04 0 -.3 .04\"\n",
|
||||
" size=\".04\" rgba=\"0 0 1 1\"/>\n",
|
||||
" </body>\n",
|
||||
" \u003cgeom name=\"pole\" type=\"cylinder\" fromto=\".3 0 -.5 .3 0 -.1\" size=\".04\"/\u003e\n",
|
||||
" \u003cbody name=\"bat\" pos=\".3 0 -.1\"\u003e\n",
|
||||
" \u003cjoint name=\"swing\" type=\"hinge\" damping=\"1\" axis=\"0 0 1\"/\u003e\n",
|
||||
" \u003cgeom name=\"bat\" type=\"capsule\" fromto=\"0 0 .04 0 -.3 .04\"\n",
|
||||
" size=\".04\" rgba=\"0 0 1 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body name=\"box_and_sphere\" pos=\"0 0 0\">\n",
|
||||
" <joint name=\"free\" type=\"free\"/>\n",
|
||||
" <geom name=\"red_box\" type=\"box\" size=\".1 .1 .1\" rgba=\"1 0 0 1\"/>\n",
|
||||
" <geom name=\"green_sphere\" size=\".06\" pos=\".1 .1 .1\" rgba=\"0 1 0 1\"/>\n",
|
||||
" <site name=\"hook\" pos=\"-.1 -.1 -.1\" size=\".01\"/>\n",
|
||||
" <site name=\"IMU\"/>\n",
|
||||
" </body>\n",
|
||||
" </worldbody>\n",
|
||||
" \u003cbody name=\"box_and_sphere\" pos=\"0 0 0\"\u003e\n",
|
||||
" \u003cjoint name=\"free\" type=\"free\"/\u003e\n",
|
||||
" \u003cgeom name=\"red_box\" type=\"box\" size=\".1 .1 .1\" rgba=\"1 0 0 1\"/\u003e\n",
|
||||
" \u003cgeom name=\"green_sphere\" size=\".06\" pos=\".1 .1 .1\" rgba=\"0 1 0 1\"/\u003e\n",
|
||||
" \u003csite name=\"hook\" pos=\"-.1 -.1 -.1\" size=\".01\"/\u003e\n",
|
||||
" \u003csite name=\"IMU\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003c/worldbody\u003e\n",
|
||||
"\n",
|
||||
" <tendon>\n",
|
||||
" <spatial name=\"wire\" limited=\"true\" range=\"0 0.35\" width=\"0.003\">\n",
|
||||
" <site site=\"anchor\"/>\n",
|
||||
" <site site=\"hook\"/>\n",
|
||||
" </spatial>\n",
|
||||
" </tendon>\n",
|
||||
" \u003ctendon\u003e\n",
|
||||
" \u003cspatial name=\"wire\" limited=\"true\" range=\"0 0.35\" width=\"0.003\"\u003e\n",
|
||||
" \u003csite site=\"anchor\"/\u003e\n",
|
||||
" \u003csite site=\"hook\"/\u003e\n",
|
||||
" \u003c/spatial\u003e\n",
|
||||
" \u003c/tendon\u003e\n",
|
||||
"\n",
|
||||
" <actuator>\n",
|
||||
" <motor name=\"my_motor\" joint=\"swing\" gear=\"1\"/>\n",
|
||||
" </actuator>\n",
|
||||
" \u003cactuator\u003e\n",
|
||||
" \u003cmotor name=\"my_motor\" joint=\"swing\" gear=\"1\"/\u003e\n",
|
||||
" \u003c/actuator\u003e\n",
|
||||
"\n",
|
||||
" <sensor>\n",
|
||||
" <accelerometer name=\"accelerometer\" site=\"IMU\"/>\n",
|
||||
" </sensor>\n",
|
||||
"</mujoco>\n",
|
||||
" \u003csensor\u003e\n",
|
||||
" \u003caccelerometer name=\"accelerometer\" site=\"IMU\"/\u003e\n",
|
||||
" \u003c/sensor\u003e\n",
|
||||
"\u003c/mujoco\u003e\n",
|
||||
"\"\"\"\n",
|
||||
"model = mujoco.MjModel.from_xml_string(MJCF)\n",
|
||||
"renderer = mujoco.Renderer(model, 480, 480)\n",
|
||||
@@ -1587,7 +1587,7 @@
|
||||
"\n",
|
||||
"# simulate and render\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",
|
||||
" times.append(data.time)\n",
|
||||
" sensordata.append(data.sensor('accelerometer').data.copy())\n",
|
||||
@@ -1658,16 +1658,16 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"xml = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <worldbody>\n",
|
||||
" <light name=\"top\" pos=\"0 0 1\"/>\n",
|
||||
" <body name=\"box_and_sphere\" euler=\"0 0 -30\">\n",
|
||||
" <joint name=\"swing\" type=\"hinge\" axis=\"1 -1 0\" pos=\"-.2 -.2 -.2\"/>\n",
|
||||
" <geom name=\"red_box\" type=\"box\" size=\".2 .2 .2\" rgba=\"1 0 0 1\"/>\n",
|
||||
" <geom name=\"green_sphere\" pos=\".2 .2 .2\" size=\".1\" rgba=\"0 1 0 1\"/>\n",
|
||||
" </body>\n",
|
||||
" </worldbody>\n",
|
||||
"</mujoco>\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",
|
||||
"model = mujoco.MjModel.from_xml_string(xml)\n",
|
||||
"renderer = mujoco.Renderer(model)\n",
|
||||
@@ -1717,7 +1717,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 <= 1].mean()\n",
|
||||
"depth /= 2*depth[depth \u003c= 1].mean()\n",
|
||||
"# Scale to [0, 255]\n",
|
||||
"pixels = 255*np.clip(depth, 0, 1)\n",
|
||||
"\n",
|
||||
@@ -1888,7 +1888,7 @@
|
||||
"\n",
|
||||
"def add_visual_capsule(scene, point1, point2, radius, rgba):\n",
|
||||
" \"\"\"Adds one capsule to an mjvScene.\"\"\"\n",
|
||||
" if scene.ngeom >= scene.maxgeom:\n",
|
||||
" if scene.ngeom \u003e= scene.maxgeom:\n",
|
||||
" return\n",
|
||||
" scene.ngeom += 1 # increment ngeom\n",
|
||||
" # initialise a new capsule, add it to the scene using mjv_makeConnector\n",
|
||||
@@ -1908,7 +1908,7 @@
|
||||
"\n",
|
||||
"def modify_scene(scn):\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",
|
||||
" rgba=np.array((np.clip(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_forward(model, data)\n",
|
||||
"\n",
|
||||
"while data.time < duration:\n",
|
||||
"while data.time \u003c duration:\n",
|
||||
" # append data to the traces\n",
|
||||
" positions.append(data.geom_xpos[data.geom(\"green_sphere\").id].copy())\n",
|
||||
" times.append(data.time)\n",
|
||||
" speeds.append(get_geom_speed(model, data, \"green_sphere\"))\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",
|
||||
" modify_scene(renderer.scene)\n",
|
||||
" pixels = renderer.render()\n",
|
||||
@@ -1966,88 +1966,88 @@
|
||||
"source": [
|
||||
"#@title Load the \"dominos\" model\n",
|
||||
"dominos_xml = \"\"\"\n",
|
||||
"<mujoco>\n",
|
||||
" <asset>\n",
|
||||
" <texture type=\"skybox\" builtin=\"gradient\" rgb1=\".3 .5 .7\" rgb2=\"0 0 0\" width=\"32\" height=\"512\"/>\n",
|
||||
" <texture name=\"grid\" type=\"2d\" builtin=\"checker\" width=\"512\" height=\"512\" rgb1=\".1 .2 .3\" rgb2=\".2 .3 .4\"/>\n",
|
||||
" <material name=\"grid\" texture=\"grid\" texrepeat=\"2 2\" texuniform=\"true\" reflectance=\".2\"/>\n",
|
||||
" </asset>\n",
|
||||
"\u003cmujoco\u003e\n",
|
||||
" \u003casset\u003e\n",
|
||||
" \u003ctexture type=\"skybox\" builtin=\"gradient\" rgb1=\".3 .5 .7\" rgb2=\"0 0 0\" width=\"32\" height=\"512\"/\u003e\n",
|
||||
" \u003ctexture name=\"grid\" type=\"2d\" builtin=\"checker\" width=\"512\" height=\"512\" rgb1=\".1 .2 .3\" rgb2=\".2 .3 .4\"/\u003e\n",
|
||||
" \u003cmaterial name=\"grid\" texture=\"grid\" texrepeat=\"2 2\" texuniform=\"true\" reflectance=\".2\"/\u003e\n",
|
||||
" \u003c/asset\u003e\n",
|
||||
"\n",
|
||||
" <statistic meansize=\".01\"/>\n",
|
||||
" \u003cstatistic meansize=\".01\"/\u003e\n",
|
||||
"\n",
|
||||
" <visual>\n",
|
||||
" <global offheight=\"2160\" offwidth=\"3840\"/>\n",
|
||||
" <quality offsamples=\"8\"/>\n",
|
||||
" </visual>\n",
|
||||
" \u003cvisual\u003e\n",
|
||||
" \u003cglobal offheight=\"2160\" offwidth=\"3840\"/\u003e\n",
|
||||
" \u003cquality offsamples=\"8\"/\u003e\n",
|
||||
" \u003c/visual\u003e\n",
|
||||
"\n",
|
||||
" <default>\n",
|
||||
" <geom type=\"box\" solref=\".005 1\"/>\n",
|
||||
" <default class=\"static\">\n",
|
||||
" <geom rgba=\".3 .5 .7 1\"/>\n",
|
||||
" </default>\n",
|
||||
" </default>\n",
|
||||
" \u003cdefault\u003e\n",
|
||||
" \u003cgeom type=\"box\" solref=\".005 1\"/\u003e\n",
|
||||
" \u003cdefault class=\"static\"\u003e\n",
|
||||
" \u003cgeom rgba=\".3 .5 .7 1\"/\u003e\n",
|
||||
" \u003c/default\u003e\n",
|
||||
" \u003c/default\u003e\n",
|
||||
"\n",
|
||||
" <option timestep=\"5e-4\"/>\n",
|
||||
" \u003coption timestep=\"5e-4\"/\u003e\n",
|
||||
"\n",
|
||||
" <worldbody>\n",
|
||||
" <light pos=\".3 -.3 .8\" mode=\"trackcom\" diffuse=\"1 1 1\" specular=\".3 .3 .3\"/>\n",
|
||||
" <light pos=\"0 -.3 .4\" mode=\"targetbodycom\" target=\"box\" diffuse=\".8 .8 .8\" specular=\".3 .3 .3\"/>\n",
|
||||
" <geom name=\"floor\" type=\"plane\" size=\"3 3 .01\" pos=\"-0.025 -0.295 0\" material=\"grid\"/>\n",
|
||||
" <geom name=\"ramp\" pos=\".25 -.45 -.03\" size=\".04 .1 .07\" euler=\"-30 0 0\" class=\"static\"/>\n",
|
||||
" <camera name=\"top\" pos=\"-0.37 -0.78 0.49\" xyaxes=\"0.78 -0.63 0 0.27 0.33 0.9\"/>\n",
|
||||
" \u003cworldbody\u003e\n",
|
||||
" \u003clight pos=\".3 -.3 .8\" mode=\"trackcom\" diffuse=\"1 1 1\" specular=\".3 .3 .3\"/\u003e\n",
|
||||
" \u003clight pos=\"0 -.3 .4\" mode=\"targetbodycom\" target=\"box\" diffuse=\".8 .8 .8\" specular=\".3 .3 .3\"/\u003e\n",
|
||||
" \u003cgeom name=\"floor\" type=\"plane\" size=\"3 3 .01\" pos=\"-0.025 -0.295 0\" material=\"grid\"/\u003e\n",
|
||||
" \u003cgeom name=\"ramp\" pos=\".25 -.45 -.03\" size=\".04 .1 .07\" euler=\"-30 0 0\" class=\"static\"/\u003e\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",
|
||||
" <body name=\"ball\" pos=\".25 -.45 .1\">\n",
|
||||
" <freejoint name=\"ball\"/>\n",
|
||||
" <geom name=\"ball\" type=\"sphere\" size=\".02\" rgba=\".65 .81 .55 1\"/>\n",
|
||||
" </body>\n",
|
||||
" \u003cbody name=\"ball\" pos=\".25 -.45 .1\"\u003e\n",
|
||||
" \u003cfreejoint name=\"ball\"/\u003e\n",
|
||||
" \u003cgeom name=\"ball\" type=\"sphere\" size=\".02\" rgba=\".65 .81 .55 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body pos=\".26 -.3 .03\" euler=\"0 0 -90.0\">\n",
|
||||
" <freejoint/>\n",
|
||||
" <geom size=\".0015 .015 .03\" rgba=\"1 .5 .5 1\"/>\n",
|
||||
" </body>\n",
|
||||
" \u003cbody pos=\".26 -.3 .03\" euler=\"0 0 -90.0\"\u003e\n",
|
||||
" \u003cfreejoint/\u003e\n",
|
||||
" \u003cgeom size=\".0015 .015 .03\" rgba=\"1 .5 .5 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body pos=\".26 -.27 .04\" euler=\"0 0 -81.0\">\n",
|
||||
" <freejoint/>\n",
|
||||
" <geom size=\".002 .02 .04\" rgba=\"1 1 .5 1\"/>\n",
|
||||
" </body>\n",
|
||||
" \u003cbody pos=\".26 -.27 .04\" euler=\"0 0 -81.0\"\u003e\n",
|
||||
" \u003cfreejoint/\u003e\n",
|
||||
" \u003cgeom size=\".002 .02 .04\" rgba=\"1 1 .5 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body pos=\".24 -.21 .06\" euler=\"0 0 -63.0\">\n",
|
||||
" <freejoint/>\n",
|
||||
" <geom size=\".003 .03 .06\" rgba=\".5 1 .5 1\"/>\n",
|
||||
" </body>\n",
|
||||
" \u003cbody pos=\".24 -.21 .06\" euler=\"0 0 -63.0\"\u003e\n",
|
||||
" \u003cfreejoint/\u003e\n",
|
||||
" \u003cgeom size=\".003 .03 .06\" rgba=\".5 1 .5 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body pos=\".2 -.16 .08\" euler=\"0 0 -45.0\">\n",
|
||||
" <freejoint/>\n",
|
||||
" <geom size=\".004 .04 .08\" rgba=\".5 1 1 1\"/>\n",
|
||||
" </body>\n",
|
||||
" \u003cbody pos=\".2 -.16 .08\" euler=\"0 0 -45.0\"\u003e\n",
|
||||
" \u003cfreejoint/\u003e\n",
|
||||
" \u003cgeom size=\".004 .04 .08\" rgba=\".5 1 1 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body pos=\".15 -.12 .1\" euler=\"0 0 -27.0\">\n",
|
||||
" <freejoint/>\n",
|
||||
" <geom size=\".005 .05 .1\" rgba=\".5 .5 1 1\"/>\n",
|
||||
" </body>\n",
|
||||
" \u003cbody pos=\".15 -.12 .1\" euler=\"0 0 -27.0\"\u003e\n",
|
||||
" \u003cfreejoint/\u003e\n",
|
||||
" \u003cgeom size=\".005 .05 .1\" rgba=\".5 .5 1 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body pos=\".09 -.1 .12\" euler=\"0 0 -9.0\">\n",
|
||||
" <freejoint/>\n",
|
||||
" <geom size=\".006 .06 .12\" rgba=\"1 .5 1 1\"/>\n",
|
||||
" </body>\n",
|
||||
" \u003cbody pos=\".09 -.1 .12\" euler=\"0 0 -9.0\"\u003e\n",
|
||||
" \u003cfreejoint/\u003e\n",
|
||||
" \u003cgeom size=\".006 .06 .12\" rgba=\"1 .5 1 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body name=\"seasaw_wrapper\" pos=\"-.23 -.1 0\" euler=\"0 0 30\">\n",
|
||||
" <geom size=\".01 .01 .015\" pos=\"0 .05 .015\" class=\"static\"/>\n",
|
||||
" <geom size=\".01 .01 .015\" pos=\"0 -.05 .015\" class=\"static\"/>\n",
|
||||
" <geom type=\"cylinder\" size=\".01 .0175\" pos=\"-.09 0 .0175\" class=\"static\"/>\n",
|
||||
" <body name=\"seasaw\" pos=\"0 0 .03\">\n",
|
||||
" <joint axis=\"0 1 0\"/>\n",
|
||||
" <geom type=\"cylinder\" size=\".005 .039\" zaxis=\"0 1 0\" rgba=\".84 .15 .33 1\"/>\n",
|
||||
" <geom size=\".1 .02 .005\" pos=\"0 0 .01\" rgba=\".84 .15 .33 1\"/>\n",
|
||||
" </body>\n",
|
||||
" </body>\n",
|
||||
" \u003cbody name=\"seasaw_wrapper\" pos=\"-.23 -.1 0\" euler=\"0 0 30\"\u003e\n",
|
||||
" \u003cgeom size=\".01 .01 .015\" pos=\"0 .05 .015\" class=\"static\"/\u003e\n",
|
||||
" \u003cgeom size=\".01 .01 .015\" pos=\"0 -.05 .015\" class=\"static\"/\u003e\n",
|
||||
" \u003cgeom type=\"cylinder\" size=\".01 .0175\" pos=\"-.09 0 .0175\" class=\"static\"/\u003e\n",
|
||||
" \u003cbody name=\"seasaw\" pos=\"0 0 .03\"\u003e\n",
|
||||
" \u003cjoint axis=\"0 1 0\"/\u003e\n",
|
||||
" \u003cgeom type=\"cylinder\" size=\".005 .039\" zaxis=\"0 1 0\" rgba=\".84 .15 .33 1\"/\u003e\n",
|
||||
" \u003cgeom size=\".1 .02 .005\" pos=\"0 0 .01\" rgba=\".84 .15 .33 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
"\n",
|
||||
" <body name=\"box\" pos=\"-.3 -.14 .05501\" euler=\"0 0 -30\">\n",
|
||||
" <freejoint name=\"box\"/>\n",
|
||||
" <geom name=\"box\" size=\".01 .01 .01\" rgba=\".0 .7 .79 1\"/>\n",
|
||||
" </body>\n",
|
||||
" </worldbody>\n",
|
||||
"</mujoco>\n",
|
||||
" \u003cbody name=\"box\" pos=\"-.3 -.14 .05501\" euler=\"0 0 -30\"\u003e\n",
|
||||
" \u003cfreejoint name=\"box\"/\u003e\n",
|
||||
" \u003cgeom name=\"box\" size=\".01 .01 .01\" rgba=\".0 .7 .79 1\"/\u003e\n",
|
||||
" \u003c/body\u003e\n",
|
||||
" \u003c/worldbody\u003e\n",
|
||||
"\u003c/mujoco\u003e\n",
|
||||
"\"\"\"\n",
|
||||
"model = mujoco.MjModel.from_xml_string(dominos_xml)\n",
|
||||
"data = mujoco.MjData(model)\n",
|
||||
@@ -2070,9 +2070,9 @@
|
||||
"# Simulate and display video.\n",
|
||||
"frames = []\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",
|
||||
" if len(frames) < data.time * framerate:\n",
|
||||
" if len(frames) \u003c data.time * framerate:\n",
|
||||
" renderer.update_scene(data, camera='top')\n",
|
||||
" pixels = renderer.render()\n",
|
||||
" frames.append(pixels)\n",
|
||||
@@ -2091,15 +2091,15 @@
|
||||
"#@title Render from moving camera\n",
|
||||
"duration = 3 # (seconds)\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",
|
||||
"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",
|
||||
" 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",
|
||||
"assert throw_time > 0\n",
|
||||
"assert throw_time \u003e 0\n",
|
||||
"\n",
|
||||
"def mix(time, t0=0.0, width=1.0):\n",
|
||||
" \"\"\"Sigmoidal mixing function.\"\"\"\n",
|
||||
@@ -2144,9 +2144,9 @@
|
||||
"slowdown = 4 # 4x slow-down\n",
|
||||
"mujoco.mj_resetData(model, data)\n",
|
||||
"frames = []\n",
|
||||
"while data.time < duration:\n",
|
||||
"while data.time \u003c duration:\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",
|
||||
" renderer.update_scene(data, cam)\n",
|
||||
" pixels = renderer.render()\n",
|
||||
@@ -2167,23 +2167,10 @@
|
||||
},
|
||||
"gpuClass": "premium",
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"display_name": "Python 3",
|
||||
"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_minor": 4
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user