Add attach tag to MJCF.
PiperOrigin-RevId: 651117953 Change-Id: I57b0e53ed44607d479b3785d908e0837c0804cf3
This commit is contained in:
committed by
Copybara-Service
parent
5b080bacc4
commit
27b9ddda5b
+83
-22
@@ -110,11 +110,11 @@ Meta elements
|
||||
|
||||
These elements are not strictly part of the low-level MJCF format definition, but rather instruct the compiler to
|
||||
perform some operation on the model. A general property of meta-elements is that they disappear from the model upon
|
||||
saving the XML. There are currently five meta-elements in MJCF:
|
||||
saving the XML. There are currently six meta-elements in MJCF:
|
||||
|
||||
- :ref:`include<include>`, :ref:`frame<frame>`, and :ref:`replicate<replicate>` which are outside of the schema.
|
||||
- :ref:`composite<body-composite>` and :ref:`flexcomp<body-flexcomp>` which are part of the schema, but serve to
|
||||
procedurally generate other MJCF elements.
|
||||
- :ref:`composite<body-composite>`, :ref:`flexcomp<body-flexcomp>` and :ref:`attach<body-attach>` which are part of the
|
||||
schema, but serve to procedurally generate other MJCF elements.
|
||||
|
||||
.. _frame:
|
||||
|
||||
@@ -1739,6 +1739,24 @@ properties are grouped together.
|
||||
definition could in fact come from a defaults class. The remaining material properties always apply.
|
||||
|
||||
|
||||
.. _asset-model:
|
||||
|
||||
:el-prefix:`asset/` |-| **model** (*)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
This element specifies other MJCF models which may be used for :ref:`attachment<body-attach>` in the current model.
|
||||
|
||||
.. _asset-model-name:
|
||||
|
||||
:at:`name`: :at-val:`string, required`
|
||||
Name of the sub-model, used for referencing in :ref:`attach<body-attach>`. If unspecified, the
|
||||
:ref:`model name<mujoco-model>` is used.
|
||||
|
||||
.. _asset-model-file:
|
||||
|
||||
:at:`file`: :at-val:`string, required`
|
||||
The file from which the sub-model will be loaded. Note that the sub-model must be a valid MJCF model.
|
||||
|
||||
|
||||
.. _body:
|
||||
|
||||
**(world)body** (R)
|
||||
@@ -2816,24 +2834,6 @@ the direction specified by the dir attribute. It does not have a full spatial fr
|
||||
The specular color of the light.
|
||||
|
||||
|
||||
.. _body-plugin:
|
||||
|
||||
:el-prefix:`body/` |-| **plugin** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Associate this body with an :ref:`engine plugin<exPlugin>`. Either :at:`plugin` or :at:`instance` are required.
|
||||
|
||||
.. _body-plugin-plugin:
|
||||
|
||||
:at:`plugin`: :at-val:`string, optional`
|
||||
Plugin identifier, used for implicit plugin instantiation.
|
||||
|
||||
.. _body-plugin-instance:
|
||||
|
||||
:at:`instance`: :at-val:`string, optional`
|
||||
Instance name, used for explicit plugin instantiation.
|
||||
|
||||
|
||||
.. _body-composite:
|
||||
|
||||
:el-prefix:`body/` |-| **composite** (*)
|
||||
@@ -3638,10 +3638,71 @@ Associate this flexcomp with an :ref:`engine plugin<exPlugin>`. Either :at:`plug
|
||||
Instance name, used for explicit plugin instantiation.
|
||||
|
||||
|
||||
.. _body-plugin:
|
||||
|
||||
:el-prefix:`body/` |-| **plugin** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Associate this body with an :ref:`engine plugin<exPlugin>`. Either :at:`plugin` or :at:`instance` are required.
|
||||
|
||||
.. _body-plugin-plugin:
|
||||
|
||||
:at:`plugin`: :at-val:`string, optional`
|
||||
Plugin identifier, used for implicit plugin instantiation.
|
||||
|
||||
.. _body-plugin-instance:
|
||||
|
||||
:at:`instance`: :at-val:`string, optional`
|
||||
Instance name, used for explicit plugin instantiation.
|
||||
|
||||
|
||||
.. _body-attach:
|
||||
|
||||
:el-prefix:`body/` |-| **attach** (*)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :el:`attach` element is used to insert a sub-tree of bodies from another model into this model's kinematic tree.
|
||||
Unlike :ref:`include<include>`, which is implemented in the parser and is equivalent to copying and pasting XML from
|
||||
one file into another, :el:`attach` is implemented in the model compiler. In order to use this element, the sub-model
|
||||
must first be defined as an :ref:`asset<model-asset>`. When creating an attachment, the top body of the attached subtree
|
||||
is specified, and all referencing elements outside the kinematic tree (e.g., sensors and actuators), are
|
||||
also copied into the top-level model. Additionally, any elements referenced from within the attached subtree (e.g.
|
||||
defaults and assets) will be copied in to the top-level model. :el:`attach` is a :ref:`meta-element`, so upon saving
|
||||
all attachments will appear in the saved XML file.
|
||||
|
||||
.. admonition:: Known issues
|
||||
:class: attention
|
||||
|
||||
The :el:`attach` meta-element is new and not well tested. Please report any issues you encounter to the development
|
||||
team. Additionally, the following known limitations exist, to be addressed in a future release:
|
||||
|
||||
- The world body cannot be attached.
|
||||
- An entire model cannot be attached (i.e. including all elements, referenced or not).
|
||||
- All assets from the child model will be copied in, whether they are referenced or not.
|
||||
- Self-attach or circular references are not checked for and will lead to infinite loops.
|
||||
- :ref:`Keyframes<keyframe>` are not yet supported. When attaching, all keyframes will be deleted.
|
||||
|
||||
.. _body-attach-model:
|
||||
|
||||
:at:`model`: :at-val:`string, optional`
|
||||
The sub-model from which to attach a subtree.
|
||||
|
||||
.. _body-attach-body:
|
||||
|
||||
:at:`body`: :at-val:`string, optional`
|
||||
Name of the body in the sub-model to attach here. The body and its subtree will be attached.
|
||||
|
||||
.. _body-attach-prefix:
|
||||
|
||||
:at:`prefix`: :at-val:`string, optional`
|
||||
Prefix to prepend to names of elements in the sub-model. If empty, the names are unchanged. This attribute is
|
||||
required to prevent name collisions with the parent or when attaching the same sub-tree multiple times.
|
||||
|
||||
|
||||
.. _body-frame:
|
||||
|
||||
:el-prefix:`body/` |-| **frame** (*)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Frames specify a coordinate transformation which is applied to all child elements. They disappear during compilation
|
||||
and the transformation they encode is accumulated in their direct children. See :ref:`frame<frame>` for examples.
|
||||
|
||||
@@ -177,6 +177,13 @@
|
||||
| | | | :ref:`reflectance<asset-material-reflectance>` | :ref:`metallic<asset-material-metallic>` | :ref:`roughness<asset-material-roughness>` | :ref:`rgba<asset-material-rgba>` | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_| asset |br| |_| |L| | | .. table:: |
|
||||
| :ref:`model | \* | :class: mjcf-attributes |
|
||||
| <asset-model>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`name<asset-model-name>` | :ref:`file<asset-model-file>` | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| mujoco |br| |L| | | .. table:: |
|
||||
| :ref:`body | R | :class: mjcf-attributes |
|
||||
| <body>` | | |
|
||||
@@ -261,6 +268,13 @@
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_| body |br| |_| |L| | | .. table:: |
|
||||
| :ref:`attach | \* | :class: mjcf-attributes |
|
||||
| <body-attach>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`model<body-attach-model>` | :ref:`body<body-attach-body>` | :ref:`prefix<body-attach-prefix>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_| body |br| |_| |L| | | .. table:: |
|
||||
| :ref:`site | \* | :class: mjcf-attributes |
|
||||
| <body-site>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
|
||||
+15
-12
@@ -39,27 +39,30 @@ General
|
||||
:align: right
|
||||
:width: 240px
|
||||
|
||||
7. Added support for orthographic cameras. This is available for both fixed cameras and the free camera, using the
|
||||
7. Add :ref:`attach<body-attach>` meta-element to MJCF, which allows attaching a model to a body.
|
||||
8. Added support for orthographic cameras. This is available for both fixed cameras and the free camera, using the
|
||||
:ref:`camera/orthographic<body-camera-orthographic>` and :ref:`global/orthographic<visual-global-orthographic>`
|
||||
attributes, respectively.
|
||||
8. Added :ref:`maxhullvert<asset-mesh-maxhullvert>`, the maximum number of vertices in a mesh's convex hull.
|
||||
9. Added :ref:`mj_setKeyframe` for saving the current state into a model keyframe.
|
||||
10. Added support for ``ball`` joints in the URDF parser ("spherical" in URDF).
|
||||
11. Replaced ``mjUSEDOUBLE`` which was previously hard-coded in
|
||||
9. Added :ref:`maxhullvert<asset-mesh-maxhullvert>`, the maximum number of vertices in a mesh's convex hull.
|
||||
10. Added :ref:`mj_setKeyframe` for saving the current state into a model keyframe.
|
||||
11. Added support for ``ball`` joints in the URDF parser ("spherical" in URDF).
|
||||
12. Deprecated :ref:`mju_rotVecMat` and :ref:`mju_rotVecMatT` in favor of :ref:`mju_mulMatVec3` and
|
||||
:ref:`mju_mulMatTVec3`. These functions names and argument ordering are more consistent with the rest of the API.
|
||||
13. Replaced ``mjUSEDOUBLE`` which was previously hard-coded in
|
||||
`mjtnum.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjtnum.h>`__
|
||||
with the build-time flag ``mjUSESINGLE``. If this symbol is not defined, MuJoCo will use double-precision floating
|
||||
point, as usual. If ``mjUSESINGLE`` is defined, MuJoCo will use single-precision floating point. See :ref:`mjtNum`.
|
||||
|
||||
Relatedly, fixed various type errors that prevented building with single-precision.
|
||||
12. Quaternions in ``mjData->qpos`` and ``mjData->mocap_quat`` are no longer normalized in-place by
|
||||
14. Quaternions in ``mjData->qpos`` and ``mjData->mocap_quat`` are no longer normalized in-place by
|
||||
:ref:`mj_kinematics`. Instead they are normalized when they are used. After the first step, quaternions in
|
||||
``mjData->qpos`` will be normalized.
|
||||
|
||||
MJX
|
||||
~~~
|
||||
13. Added support for :ref:`elliptic friction cones<option-cone>`.
|
||||
14. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings.
|
||||
15. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients.
|
||||
15. Added support for :ref:`elliptic friction cones<option-cone>`.
|
||||
16. Fixed a bug that resulted in less-optimal linesearch solutions for some difficult constraint settings.
|
||||
17. Fixed a bug in the Newton solver that sometimes resulted in less-optimal gradients.
|
||||
|
||||
|
||||
.. youtube:: P83tKA1iz2Y
|
||||
@@ -68,14 +71,14 @@ MJX
|
||||
|
||||
Simulate
|
||||
^^^^^^^^
|
||||
16. Added improved tutorial video.
|
||||
17. Improved the Brownian noise generator.
|
||||
18. Added improved tutorial video.
|
||||
19. Improved the Brownian noise generator.
|
||||
|
||||
|br| |br| |br| |br|
|
||||
|
||||
Python bindings
|
||||
^^^^^^^^^^^^^^^
|
||||
18. Fixed a memory leak when using ``copy.deepcopy()`` on a ``mujoco.MjData`` instance (:github:issue:`1572`).
|
||||
20. Fixed a memory leak when using ``copy.deepcopy()`` on a ``mujoco.MjData`` instance (:github:issue:`1572`).
|
||||
|
||||
Version 3.1.6 (Jun 3, 2024)
|
||||
---------------------------
|
||||
|
||||
@@ -20,82 +20,11 @@
|
||||
|
||||
<asset>
|
||||
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/>
|
||||
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128"
|
||||
rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1"/>
|
||||
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
|
||||
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
|
||||
<material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/>
|
||||
<texture name="floor" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
|
||||
<material name="floor" texture="floor" texrepeat="1 1" texuniform="true" reflectance=".2"/>
|
||||
<model name="humanoid" file="humanoid.xml"/>
|
||||
</asset>
|
||||
|
||||
<default>
|
||||
<motor ctrlrange="-1 1" ctrllimited="true"/>
|
||||
<default class="body">
|
||||
|
||||
<!-- geoms -->
|
||||
<geom type="capsule" condim="1" friction=".7" solimp=".9 .99 .003" solref=".015 1" material="body" group="1"/>
|
||||
<default class="thigh">
|
||||
<geom size=".06"/>
|
||||
</default>
|
||||
<default class="shin">
|
||||
<geom fromto="0 0 0 0 0 -.3" size=".049"/>
|
||||
</default>
|
||||
<default class="foot">
|
||||
<geom size=".027"/>
|
||||
<default class="foot1">
|
||||
<geom fromto="-.07 -.01 0 .14 -.03 0"/>
|
||||
</default>
|
||||
<default class="foot2">
|
||||
<geom fromto="-.07 .01 0 .14 .03 0"/>
|
||||
</default>
|
||||
</default>
|
||||
<default class="arm_upper">
|
||||
<geom size=".04"/>
|
||||
</default>
|
||||
<default class="arm_lower">
|
||||
<geom size=".031"/>
|
||||
</default>
|
||||
<default class="hand">
|
||||
<geom type="sphere" size=".04"/>
|
||||
</default>
|
||||
|
||||
<!-- joints -->
|
||||
<joint type="hinge" damping=".2" stiffness="1" armature=".01" limited="true" solimplimit="0 .99 .01"/>
|
||||
<default class="joint_big">
|
||||
<joint damping="5" stiffness="10"/>
|
||||
<default class="hip_x">
|
||||
<joint range="-30 10"/>
|
||||
</default>
|
||||
<default class="hip_z">
|
||||
<joint range="-60 35"/>
|
||||
</default>
|
||||
<default class="hip_y">
|
||||
<joint axis="0 1 0" range="-150 20"/>
|
||||
</default>
|
||||
<default class="joint_big_stiff">
|
||||
<joint stiffness="20"/>
|
||||
</default>
|
||||
</default>
|
||||
<default class="knee">
|
||||
<joint pos="0 0 .02" axis="0 -1 0" range="-160 2"/>
|
||||
</default>
|
||||
<default class="ankle">
|
||||
<joint range="-50 50"/>
|
||||
<default class="ankle_y">
|
||||
<joint pos="0 0 .08" axis="0 1 0" stiffness="6"/>
|
||||
</default>
|
||||
<default class="ankle_x">
|
||||
<joint pos="0 0 .04" stiffness="3"/>
|
||||
</default>
|
||||
</default>
|
||||
<default class="shoulder">
|
||||
<joint range="-85 60"/>
|
||||
</default>
|
||||
<default class="elbow">
|
||||
<joint range="-100 50" stiffness="0"/>
|
||||
</default>
|
||||
</default>
|
||||
</default>
|
||||
|
||||
<visual>
|
||||
<map force="0.1" zfar="30"/>
|
||||
<rgba haze="0.15 0.25 0.35 1"/>
|
||||
@@ -104,127 +33,11 @@
|
||||
</visual>
|
||||
|
||||
<worldbody>
|
||||
<geom name="floor" size="10 10 .05" type="plane" material="grid" condim="3"/>
|
||||
<geom name="floor" size="10 10 .05" type="plane" material="floor" condim="3"/>
|
||||
<light directional="true" diffuse=".4 .4 .4" specular="0.1 0.1 0.1" pos="0 0 5" dir="0 0 -1" castshadow="false"/>
|
||||
<light name="spotlight" mode="targetbodycom" target="world" diffuse="1 1 1" specular="0.3 0.3 0.3" pos="-6 -6 4" cutoff="60"/>
|
||||
<replicate count="22" euler="0 0 16.36" sep="-">
|
||||
<body name="torso" pos="-5 0 1.282" childclass="body">
|
||||
<camera name="back" pos="-3 0 1" xyaxes="0 -1 0 1 0 2" mode="trackcom"/>
|
||||
<camera name="side" pos="0 -3 1" xyaxes="1 0 0 0 1 2" mode="trackcom"/>
|
||||
<freejoint name="root"/>
|
||||
<geom name="torso" fromto="0 -.07 0 0 .07 0" size=".07"/>
|
||||
<geom name="waist_upper" fromto="-.01 -.06 -.12 -.01 .06 -.12" size=".06"/>
|
||||
<body name="head" pos="0 0 .19">
|
||||
<geom name="head" type="sphere" size=".09"/>
|
||||
<camera name="egocentric" pos=".09 0 0" xyaxes="0 -1 0 .1 0 1" fovy="80"/>
|
||||
</body>
|
||||
<body name="waist_lower" pos="-.01 0 -.26">
|
||||
<geom name="waist_lower" fromto="0 -.06 0 0 .06 0" size=".06"/>
|
||||
<joint name="abdomen_z" pos="0 0 .065" axis="0 0 1" range="-45 45" class="joint_big_stiff"/>
|
||||
<joint name="abdomen_y" pos="0 0 .065" axis="0 1 0" range="-75 30" class="joint_big"/>
|
||||
<body name="pelvis" pos="0 0 -.165">
|
||||
<joint name="abdomen_x" pos="0 0 .1" axis="1 0 0" range="-35 35" class="joint_big"/>
|
||||
<geom name="butt" fromto="-.02 -.07 0 -.02 .07 0" size=".09"/>
|
||||
<body name="thigh_right" pos="0 -.1 -.04">
|
||||
<joint name="hip_x_right" axis="1 0 0" class="hip_x"/>
|
||||
<joint name="hip_z_right" axis="0 0 1" class="hip_z"/>
|
||||
<joint name="hip_y_right" class="hip_y"/>
|
||||
<geom name="thigh_right" fromto="0 0 0 0 .01 -.34" class="thigh"/>
|
||||
<body name="shin_right" pos="0 .01 -.4">
|
||||
<joint name="knee_right" class="knee"/>
|
||||
<geom name="shin_right" class="shin"/>
|
||||
<body name="foot_right" pos="0 0 -.39">
|
||||
<joint name="ankle_y_right" class="ankle_y"/>
|
||||
<joint name="ankle_x_right" class="ankle_x" axis="1 0 .5"/>
|
||||
<geom name="foot1_right" class="foot1"/>
|
||||
<geom name="foot2_right" class="foot2"/>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
<body name="thigh_left" pos="0 .1 -.04">
|
||||
<joint name="hip_x_left" axis="-1 0 0" class="hip_x"/>
|
||||
<joint name="hip_z_left" axis="0 0 -1" class="hip_z"/>
|
||||
<joint name="hip_y_left" class="hip_y"/>
|
||||
<geom name="thigh_left" fromto="0 0 0 0 -.01 -.34" class="thigh"/>
|
||||
<body name="shin_left" pos="0 -.01 -.4">
|
||||
<joint name="knee_left" class="knee"/>
|
||||
<geom name="shin_left" fromto="0 0 0 0 0 -.3" class="shin"/>
|
||||
<body name="foot_left" pos="0 0 -.39">
|
||||
<joint name="ankle_y_left" class="ankle_y"/>
|
||||
<joint name="ankle_x_left" class="ankle_x" axis="-1 0 -.5"/>
|
||||
<geom name="foot1_left" class="foot1"/>
|
||||
<geom name="foot2_left" class="foot2"/>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
<body name="upper_arm_right" pos="0 -.17 .06">
|
||||
<joint name="shoulder1_right" axis="2 1 1" class="shoulder"/>
|
||||
<joint name="shoulder2_right" axis="0 -1 1" class="shoulder"/>
|
||||
<geom name="upper_arm_right" fromto="0 0 0 .16 -.16 -.16" class="arm_upper"/>
|
||||
<body name="lower_arm_right" pos=".18 -.18 -.18">
|
||||
<joint name="elbow_right" axis="0 -1 1" class="elbow"/>
|
||||
<geom name="lower_arm_right" fromto=".01 .01 .01 .17 .17 .17" class="arm_lower"/>
|
||||
<body name="hand_right" pos=".18 .18 .18">
|
||||
<geom name="hand_right" zaxis="1 1 1" class="hand"/>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
<body name="upper_arm_left" pos="0 .17 .06">
|
||||
<joint name="shoulder1_left" axis="-2 1 -1" class="shoulder"/>
|
||||
<joint name="shoulder2_left" axis="0 -1 -1" class="shoulder"/>
|
||||
<geom name="upper_arm_left" fromto="0 0 0 .16 .16 -.16" class="arm_upper"/>
|
||||
<body name="lower_arm_left" pos=".18 .18 -.18">
|
||||
<joint name="elbow_left" axis="0 -1 -1" class="elbow"/>
|
||||
<geom name="lower_arm_left" fromto=".01 -.01 .01 .17 -.17 .17" class="arm_lower"/>
|
||||
<body name="hand_left" pos=".18 -.18 .18">
|
||||
<geom name="hand_left" zaxis="1 -1 1" class="hand"/>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
</body>
|
||||
<replicate count="22" euler="0 0 16.36" sep="-" offset="1 0 0">
|
||||
<attach model="humanoid" body="torso" prefix="_"/>
|
||||
</replicate>
|
||||
</worldbody>
|
||||
|
||||
<contact>
|
||||
<exclude body1="waist_lower" body2="thigh_right"/>
|
||||
<exclude body1="waist_lower" body2="thigh_left"/>
|
||||
</contact>
|
||||
|
||||
<tendon>
|
||||
<fixed name="hamstring_right" limited="true" range="-0.3 2">
|
||||
<joint joint="hip_y_right" coef=".5"/>
|
||||
<joint joint="knee_right" coef="-.5"/>
|
||||
</fixed>
|
||||
<fixed name="hamstring_left" limited="true" range="-0.3 2">
|
||||
<joint joint="hip_y_left" coef=".5"/>
|
||||
<joint joint="knee_left" coef="-.5"/>
|
||||
</fixed>
|
||||
</tendon>
|
||||
|
||||
<actuator>
|
||||
<motor name="abdomen_z" gear="40" joint="abdomen_z"/>
|
||||
<motor name="abdomen_y" gear="40" joint="abdomen_y"/>
|
||||
<motor name="abdomen_x" gear="40" joint="abdomen_x"/>
|
||||
<motor name="hip_x_right" gear="40" joint="hip_x_right"/>
|
||||
<motor name="hip_z_right" gear="40" joint="hip_z_right"/>
|
||||
<motor name="hip_y_right" gear="120" joint="hip_y_right"/>
|
||||
<motor name="knee_right" gear="80" joint="knee_right"/>
|
||||
<motor name="ankle_y_right" gear="20" joint="ankle_y_right"/>
|
||||
<motor name="ankle_x_right" gear="20" joint="ankle_x_right"/>
|
||||
<motor name="hip_x_left" gear="40" joint="hip_x_left"/>
|
||||
<motor name="hip_z_left" gear="40" joint="hip_z_left"/>
|
||||
<motor name="hip_y_left" gear="120" joint="hip_y_left"/>
|
||||
<motor name="knee_left" gear="80" joint="knee_left"/>
|
||||
<motor name="ankle_y_left" gear="20" joint="ankle_y_left"/>
|
||||
<motor name="ankle_x_left" gear="20" joint="ankle_x_left"/>
|
||||
<motor name="shoulder1_right" gear="20" joint="shoulder1_right"/>
|
||||
<motor name="shoulder2_right" gear="20" joint="shoulder2_right"/>
|
||||
<motor name="elbow_right" gear="40" joint="elbow_right"/>
|
||||
<motor name="shoulder1_left" gear="20" joint="shoulder1_left"/>
|
||||
<motor name="shoulder2_left" gear="20" joint="shoulder2_left"/>
|
||||
<motor name="elbow_left" gear="40" joint="elbow_left"/>
|
||||
</actuator>
|
||||
|
||||
</mujoco>
|
||||
|
||||
@@ -101,6 +101,7 @@ int mjs_attachBody(mjsFrame* parent, const mjsBody* child,
|
||||
try {
|
||||
*frame_parent += std::string(prefix) + *child_body + std::string(suffix);
|
||||
} catch (mjCError& e) {
|
||||
frame_parent->model->SetError(e);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -116,6 +117,7 @@ int mjs_attachFrame(mjsBody* parent, const mjsFrame* child,
|
||||
try {
|
||||
*body_parent += std::string(prefix) + *child_frame + std::string(suffix);
|
||||
} catch (mjCError& e) {
|
||||
body_parent->model->SetError(e);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -158,6 +160,14 @@ void mj_deleteSpec(mjSpec* s) {
|
||||
|
||||
|
||||
|
||||
// add spec (model asset) to spec
|
||||
void mjs_addSpec(mjSpec* s, mjSpec* child) {
|
||||
mjCModel* model = static_cast<mjCModel*>(s->element);
|
||||
model->AppendSpec(child);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// delete object, it will call the appropriate destructor since ~mjCBase is virtual
|
||||
void mjs_delete(mjsElement* element) {
|
||||
mjCBase* object = static_cast<mjCBase*>(element);
|
||||
@@ -466,6 +476,14 @@ mjSpec* mjs_getSpec(mjsBody* body) {
|
||||
|
||||
|
||||
|
||||
// find spec (model asset) by name
|
||||
mjSpec* mjs_findSpec(mjSpec* s, const char* name) {
|
||||
mjCModel* model = static_cast<mjCModel*>(s->element);
|
||||
return model->FindSpec(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get default
|
||||
mjsDefault* mjs_getDefault(mjsElement* element) {
|
||||
mjCModel* model = static_cast<mjCBase*>(element)->model;
|
||||
|
||||
@@ -60,6 +60,9 @@ MJAPI void mj_copyBack(mjSpec* s, const mjModel* m);
|
||||
// Delete spec.
|
||||
MJAPI void mj_deleteSpec(mjSpec* s);
|
||||
|
||||
// Add spec (model asset) to spec.
|
||||
MJAPI void mjs_addSpec(mjSpec* s, mjSpec* child);
|
||||
|
||||
|
||||
//---------------------------------- Attachment ----------------------------------------------------
|
||||
|
||||
@@ -182,6 +185,9 @@ MJAPI mjsMaterial* mjs_addMaterial(mjSpec* s, mjsDefault* def);
|
||||
// Get spec from body.
|
||||
MJAPI mjSpec* mjs_getSpec(mjsBody* body);
|
||||
|
||||
// Find spec (model asset) by name.
|
||||
MJAPI mjSpec* mjs_findSpec(mjSpec* spec, const char* name);
|
||||
|
||||
// Find body in model by name.
|
||||
MJAPI mjsBody* mjs_findBody(mjSpec* s, const char* name);
|
||||
|
||||
|
||||
+25
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <csetjmp>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -33,7 +34,6 @@
|
||||
#include <mujoco/mjspec.h>
|
||||
#include <mujoco/mjtnum.h>
|
||||
#include <mujoco/mjplugin.h>
|
||||
#include <mujoco/mjvisualize.h>
|
||||
#include "cc/array_safety.h"
|
||||
#include "engine/engine_forward.h"
|
||||
#include "engine/engine_io.h"
|
||||
@@ -338,6 +338,7 @@ mjCModel& mjCModel::operator-=(const mjCBody& subtree) {
|
||||
// add default tree to this model
|
||||
mjCModel_& mjCModel::operator+=(mjCDef& subtree) {
|
||||
defaults_.push_back(&subtree);
|
||||
def_map[subtree.name] = &subtree;
|
||||
|
||||
// set parent to the main default if this is not the only default in the model
|
||||
if (!subtree.parent && &subtree != defaults_[0]) {
|
||||
@@ -660,6 +661,11 @@ mjCPlugin* mjCModel::AddPlugin() {
|
||||
}
|
||||
|
||||
|
||||
// append spec to spec
|
||||
void mjCModel::AppendSpec(mjSpec* spec) {
|
||||
specs_.push_back(spec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------ API FOR ACCESS TO MODEL ELEMENTS ---------------------------------------
|
||||
@@ -886,6 +892,18 @@ mjCFrame* mjCModel::FindFrame(mjCBody* body, std::string name) const{
|
||||
|
||||
|
||||
|
||||
// find spec by name
|
||||
mjSpec* mjCModel::FindSpec(std::string name) const {
|
||||
for (auto spec : specs_) {
|
||||
if (mjs_getString(spec->modelname) == name) {
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// detect null pose
|
||||
bool mjCModel::IsNullPose(const mjtNum* pos, const mjtNum* quat) const {
|
||||
bool result = true;
|
||||
@@ -3247,6 +3265,12 @@ mjModel* mjCModel::Compile(const mjVFS* vfs, mjModel** m) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// destroy attached specs
|
||||
for (auto spec : specs_) {
|
||||
mj_deleteSpec(spec);
|
||||
}
|
||||
specs_.clear();
|
||||
|
||||
// restore error handler, mark as compiled, return mjModel
|
||||
_mjPRIVATE__set_tls_error_fn(save_error);
|
||||
_mjPRIVATE__set_tls_warning_fn(save_warning);
|
||||
|
||||
@@ -192,7 +192,7 @@ class mjCModel : public mjCModel_, private mjSpec {
|
||||
mjCTuple* AddTuple();
|
||||
mjCKey* AddKey();
|
||||
mjCPlugin* AddPlugin();
|
||||
|
||||
void AppendSpec(mjSpec* spec);
|
||||
|
||||
// delete elements marked as discard=true
|
||||
template <class T> void Delete(std::vector<T*>& elements,
|
||||
@@ -209,12 +209,14 @@ class mjCModel : public mjCModel_, private mjSpec {
|
||||
// API for access to other variables
|
||||
bool IsCompiled() const; // is model already compiled
|
||||
const mjCError& GetError() const; // get reference of error object
|
||||
void SetError(const mjCError& error) { errInfo = error; } // set value of error object
|
||||
mjCBody* GetWorld(); // pointer to world body
|
||||
mjCDef* FindDefault(std::string name); // find defaults class name
|
||||
mjCDef* AddDefault(std::string name, mjCDef* parent = nullptr); // add defaults class to array
|
||||
mjCBase* FindObject(mjtObj type, std::string name) const; // find object given type and name
|
||||
mjCBody* FindBody(mjCBody* body, std::string name); // find body given name
|
||||
mjCFrame* FindFrame(mjCBody* body, std::string name) const; // find frame given name
|
||||
mjSpec* FindSpec(std::string name) const; // find spec given name
|
||||
bool IsNullPose(const mjtNum* pos, const mjtNum* quat) const; // detect null pose
|
||||
void SetActivePlugins(const std::vector<std::pair<const mjpPlugin*, int>>&& active_plugins) {
|
||||
active_plugins_ = std::move(active_plugins);
|
||||
@@ -312,6 +314,7 @@ class mjCModel : public mjCModel_, private mjSpec {
|
||||
std::vector<mjCTuple*> tuples_; // list of tuple fields
|
||||
std::vector<mjCKey*> keys_; // list of keyframe fields
|
||||
std::vector<mjCPlugin*> plugins_; // list of plugin instances
|
||||
std::vector<mjSpec*> specs_; // list of specs
|
||||
|
||||
// pointers to objects created inside kinematic tree
|
||||
std::vector<mjCBody*> bodies_; // list of bodies
|
||||
|
||||
@@ -697,6 +697,9 @@ void mjCBase::NameSpace(const mjCModel* m) {
|
||||
if (!name.empty()) {
|
||||
name = m->prefix + name + m->suffix;
|
||||
}
|
||||
if (!classname.empty() && m != model) {
|
||||
classname = m->prefix + classname + m->suffix;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1000,6 +1003,9 @@ void mjCBody::NameSpace_(const mjCModel* m, bool propagate) {
|
||||
if (!name.empty()) {
|
||||
name = m->prefix + name + m->suffix;
|
||||
}
|
||||
if (!classname.empty() && m != model) {
|
||||
classname = m->prefix + classname + m->suffix;
|
||||
}
|
||||
|
||||
for (auto& body : bodies) {
|
||||
body->prefix = m->prefix;
|
||||
@@ -2004,6 +2010,9 @@ void mjCGeom::NameSpace(const mjCModel* m) {
|
||||
if (!name.empty()) {
|
||||
name = m->prefix + name + m->suffix;
|
||||
}
|
||||
if (!classname.empty() && m != model) {
|
||||
classname = m->prefix + classname + m->suffix;
|
||||
}
|
||||
if (!spec_material_.empty() && model != m) {
|
||||
spec_material_ = m->prefix + spec_material_ + m->suffix;
|
||||
}
|
||||
@@ -2768,6 +2777,9 @@ void mjCCamera::NameSpace(const mjCModel* m) {
|
||||
if (!name.empty()) {
|
||||
name = m->prefix + name + m->suffix;
|
||||
}
|
||||
if (!classname.empty() && m != model) {
|
||||
classname = m->prefix + classname + m->suffix;
|
||||
}
|
||||
if (!spec_targetbody_.empty()) {
|
||||
spec_targetbody_ = m->prefix + spec_targetbody_ + m->suffix;
|
||||
}
|
||||
@@ -2917,6 +2929,9 @@ void mjCLight::NameSpace(const mjCModel* m) {
|
||||
if (!name.empty()) {
|
||||
name = m->prefix + name + m->suffix;
|
||||
}
|
||||
if (!classname.empty() && m != model) {
|
||||
classname = m->prefix + classname + m->suffix;
|
||||
}
|
||||
if (!spec_targetbody_.empty()) {
|
||||
spec_targetbody_ = m->prefix + spec_targetbody_ + m->suffix;
|
||||
}
|
||||
|
||||
+1
-1
@@ -369,7 +369,7 @@ mjSpec* mjParseXML(const char* filename, const mjVFS* vfs,
|
||||
|
||||
// parse MuJoCo model
|
||||
parser.SetModel(spec);
|
||||
parser.Parse(root);
|
||||
parser.Parse(root, vfs);
|
||||
}
|
||||
|
||||
else if (!strcasecmp(root->Value(), "robot")) {
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "tinyxml2.h"
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include <mujoco/mjspec.h>
|
||||
#include "xml/xml_util.h"
|
||||
|
||||
@@ -79,7 +80,7 @@ class mjXBase : public mjXUtil {
|
||||
virtual ~mjXBase() = default;
|
||||
|
||||
// parse: implemented in derived parser classes
|
||||
virtual void Parse(tinyxml2::XMLElement* root) {};
|
||||
virtual void Parse(tinyxml2::XMLElement* root, const mjVFS* vfs = nullptr) {};
|
||||
|
||||
// write: implemented in derived writer class
|
||||
virtual std::string Write(char *error, std::size_t error_sz) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "xml/xml_native_reader.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
@@ -38,6 +39,7 @@
|
||||
#include "engine/engine_util_errmem.h"
|
||||
#include "engine/engine_util_misc.h"
|
||||
#include <mujoco/mjspec.h>
|
||||
#include "user/user_api.h"
|
||||
#include "user/user_composite.h"
|
||||
#include "user/user_flexcomp.h"
|
||||
#include "user/user_util.h"
|
||||
@@ -243,6 +245,7 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
|
||||
"hflip", "vflip"},
|
||||
{"material", "*", "12", "name", "class", "texture", "texrepeat", "texuniform",
|
||||
"emission", "specular", "shininess", "reflectance", "metallic", "roughness", "rgba"},
|
||||
{"model", "*", "2", "name", "file"},
|
||||
{">"},
|
||||
|
||||
{"body", "R", "11", "name", "childclass", "pos", "quat", "mocap",
|
||||
@@ -267,6 +270,7 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
|
||||
{"config", "*", "2", "key", "value"},
|
||||
{">"},
|
||||
{">"},
|
||||
{"attach", "*", "3", "model", "body", "prefix"},
|
||||
{"site", "*", "15", "name", "class", "type", "group", "pos", "quat",
|
||||
"material", "size", "fromto", "axisangle", "xyaxes", "zaxis", "euler", "rgba", "user"},
|
||||
{"camera", "*", "20", "name", "class", "orthographic", "fovy", "ipd", "resolution", "pos",
|
||||
@@ -805,7 +809,7 @@ void mjXReader::PrintSchema(std::stringstream& str, bool html, bool pad) {
|
||||
|
||||
// main entry point for XML parser
|
||||
// mjCModel is allocated here; caller is responsible for deallocation
|
||||
void mjXReader::Parse(XMLElement* root) {
|
||||
void mjXReader::Parse(XMLElement* root, const mjVFS* vfs) {
|
||||
// check schema
|
||||
if (!schema.GetError().empty()) {
|
||||
throw mjXError(0, "XML Schema Construction Error: %s\n",
|
||||
@@ -880,7 +884,7 @@ void mjXReader::Parse(XMLElement* root) {
|
||||
|
||||
for (XMLElement* section = FirstChildElement(root, "asset"); section;
|
||||
section = NextSiblingElement(section, "asset")) {
|
||||
Asset(section);
|
||||
Asset(section, vfs);
|
||||
}
|
||||
|
||||
for (XMLElement* section = FirstChildElement(root, "contact"); section;
|
||||
@@ -3045,7 +3049,7 @@ void mjXReader::Visual(XMLElement* section) {
|
||||
|
||||
|
||||
// asset section parser
|
||||
void mjXReader::Asset(XMLElement* section) {
|
||||
void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
|
||||
int n;
|
||||
string text, name, texname, content_type;
|
||||
XMLElement* elem;
|
||||
@@ -3209,6 +3213,27 @@ void mjXReader::Asset(XMLElement* section) {
|
||||
}
|
||||
}
|
||||
|
||||
// model sub-element
|
||||
else if (name=="model") {
|
||||
auto filename = modelfiledir_ + ReadAttrFile(elem, "file", "").value();
|
||||
|
||||
// parse the child
|
||||
std::array<char, 1024> error;
|
||||
mjSpec* child = mj_parseXML(filename.c_str(), vfs, error.data(), error.size());
|
||||
if (!child) {
|
||||
throw mjXError(elem, "could not parse model file with error: %s", error.data());
|
||||
}
|
||||
|
||||
// overwrite model name if given
|
||||
std::string modelname = "";
|
||||
if (ReadAttrTxt(elem, "name", modelname)) {
|
||||
mjs_setString(child->modelname, modelname.c_str());
|
||||
}
|
||||
|
||||
// store child spec in model
|
||||
mjs_addSpec(model, child);
|
||||
}
|
||||
|
||||
// advance to next element
|
||||
elem = NextSiblingElement(elem);
|
||||
}
|
||||
@@ -3437,8 +3462,8 @@ void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
|
||||
Body(elem, subtree, pframe);
|
||||
|
||||
// attach to parent
|
||||
if (mjs_attachFrame(pbody, pframe, /*prefix=*/"", suffix.c_str()) < 0) {
|
||||
throw mjXError(elem, "failed to attach frame");
|
||||
if (mjs_attachFrame(pbody, pframe, /*prefix=*/"", suffix.c_str()) != 0) {
|
||||
throw mjXError(elem, mjs_getError(model));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3496,6 +3521,35 @@ void mjXReader::Body(XMLElement* section, mjsBody* pbody, mjsFrame* frame) {
|
||||
Body(elem, pchild, nullptr);
|
||||
}
|
||||
|
||||
// attachment
|
||||
else if (name=="attach") {
|
||||
std::string model_name, body_name, prefix;
|
||||
ReadAttrTxt(elem, "model", model_name);
|
||||
ReadAttrTxt(elem, "body", body_name);
|
||||
ReadAttrTxt(elem, "prefix", prefix);
|
||||
|
||||
mjsBody* child = mjs_findBody(model, (prefix+body_name).c_str());
|
||||
mjsFrame* pframe = frame ? frame : mjs_addFrame(pbody, nullptr);
|
||||
|
||||
if (!child) {
|
||||
mjSpec* asset = mjs_findSpec(model, model_name.c_str());
|
||||
if (!asset) {
|
||||
throw mjXError(0, "could not find model '%s'", model_name.c_str());
|
||||
}
|
||||
child = mjs_findBody(asset, body_name.c_str());
|
||||
if (!child) {
|
||||
throw mjXError(0, "could not find body '%s''%s'", body_name.c_str());
|
||||
}
|
||||
if (mjs_attachBody(pframe, child, prefix.c_str(), "") != 0) {
|
||||
mj_deleteSpec(asset);
|
||||
throw mjXError(elem, mjs_getError(model));
|
||||
}
|
||||
} else {
|
||||
// only set frame to existing body
|
||||
mjs_setFrame(child->element, pframe);
|
||||
}
|
||||
}
|
||||
|
||||
// no match
|
||||
else {
|
||||
throw mjXError(elem, "unrecognized model element '%s'", name.c_str());
|
||||
|
||||
@@ -30,7 +30,7 @@ class mjXReader : public mjXBase {
|
||||
mjXReader(); // constructor
|
||||
virtual ~mjXReader() = default; // destructor
|
||||
|
||||
void Parse(tinyxml2::XMLElement* root); // parse XML document
|
||||
void Parse(tinyxml2::XMLElement* root, const mjVFS* vfs = nullptr); // parse XML document
|
||||
void PrintSchema(std::stringstream& str, bool html, bool pad); // print text or HTML schema
|
||||
|
||||
void SetModelFileDir(std::string modelfiledir);
|
||||
@@ -53,7 +53,7 @@ class mjXReader : public mjXBase {
|
||||
void Custom(tinyxml2::XMLElement* section); // custom section
|
||||
void Visual(tinyxml2::XMLElement* section); // visual section
|
||||
void Statistic(tinyxml2::XMLElement* section); // statistic section
|
||||
void Asset(tinyxml2::XMLElement* section); // asset section
|
||||
void Asset(tinyxml2::XMLElement* section, const mjVFS* vfs); // asset section
|
||||
void Body(tinyxml2::XMLElement* section, mjsBody* pbody,
|
||||
mjsFrame* pframe); // body/world section
|
||||
void Contact(tinyxml2::XMLElement* section); // contact section
|
||||
@@ -99,7 +99,7 @@ class mjXReader : public mjXBase {
|
||||
};
|
||||
|
||||
// MJCF schema
|
||||
#define nMJCF 230
|
||||
#define nMJCF 232
|
||||
extern const char* MJCF[nMJCF][mjXATTRNUM];
|
||||
|
||||
#endif // MUJOCO_SRC_XML_XML_NATIVE_READER_H_
|
||||
|
||||
+1
-1
@@ -364,7 +364,7 @@ void mjXURDF::Body(XMLElement* body_elem) {
|
||||
}
|
||||
}
|
||||
|
||||
void mjXURDF::Parse(XMLElement* root) {
|
||||
void mjXURDF::Parse(XMLElement* root, const mjVFS* vfs) {
|
||||
double pos[3] = {0};
|
||||
mjuu_setvec(pos, 0, 0, 0);
|
||||
double quat[4] = {1, 0, 0, 0};
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include <mujoco/mjspec.h>
|
||||
#include "xml/xml_base.h"
|
||||
#include "tinyxml2.h"
|
||||
@@ -41,7 +42,7 @@ class mjXURDF : public mjXBase {
|
||||
double* pos,
|
||||
double* quat,
|
||||
bool static_body);
|
||||
void Parse(tinyxml2::XMLElement* root); // main parser
|
||||
void Parse(tinyxml2::XMLElement* root, const mjVFS* vfs = nullptr); // main parser
|
||||
|
||||
private:
|
||||
std::string GetPrefixedName(const std::string& name); // get prefix/name of element
|
||||
|
||||
@@ -502,8 +502,8 @@ TEST_F(MujocoTest, AttachDifferent) {
|
||||
<joint type="hinge" name="attached-hinge-1"/>
|
||||
<geom class="attached-cylinder-1" material="attached-material-1"/>
|
||||
<light mode="targetbody" target="attached-targetbody-1"/>
|
||||
<body name="attached-targetbody-1"/>
|
||||
<body/>
|
||||
<body name="attached-targetbody-1"/>
|
||||
<body/>
|
||||
</body>
|
||||
</frame>
|
||||
</body>
|
||||
@@ -618,8 +618,8 @@ TEST_F(MujocoTest, AttachFrame) {
|
||||
<joint type="hinge" name="attached-hinge-1"/>
|
||||
<geom class="attached-cylinder-1" material="attached-material-1"/>
|
||||
<light mode="targetbody" target="attached-targetbody-1"/>
|
||||
<body name="attached-targetbody-1"/>
|
||||
<body/>
|
||||
<body name="attached-targetbody-1"/>
|
||||
<body/>
|
||||
</body>
|
||||
</frame>
|
||||
</frame>
|
||||
@@ -650,7 +650,7 @@ TEST_F(MujocoTest, AttachFrame) {
|
||||
mjSpec* parent = mj_parseXMLString(xml_parent, 0, er.data(), er.size());
|
||||
EXPECT_THAT(parent, NotNull()) << er.data();
|
||||
|
||||
// get frame
|
||||
// get body
|
||||
mjsBody* body = mjs_findBody(parent, "sphere");
|
||||
EXPECT_THAT(body, NotNull());
|
||||
|
||||
@@ -662,7 +662,7 @@ TEST_F(MujocoTest, AttachFrame) {
|
||||
mjsFrame* frame = mjs_findFrame(child, "pframe");
|
||||
EXPECT_THAT(frame, NotNull());
|
||||
|
||||
// attach child to parent frame
|
||||
// attach child frame to parent body
|
||||
EXPECT_THAT(
|
||||
mjs_attachFrame(body, frame, /*prefix=*/"attached-", /*suffix=*/"-1"), 0);
|
||||
|
||||
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
<mujoco model="child">
|
||||
<worldbody>
|
||||
<body name="body">
|
||||
<geom name="geom" size="1" pos="2 0 0"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
<mujoco>
|
||||
<asset>
|
||||
<model name="other" file="child.xml"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="parent">
|
||||
<geom name="geom" size="2"/>
|
||||
<attach model="other" body="body" prefix="other"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
@@ -1054,6 +1054,7 @@ TEST_F(XMLReaderTest, DuplicateFrameName) {
|
||||
|
||||
|
||||
// ---------------------- test replicate parsing -------------------------------
|
||||
|
||||
TEST_F(XMLReaderTest, ParseReplicate) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
@@ -1253,7 +1254,146 @@ TEST_F(XMLReaderTest, ParseReplicateRepeatedName) {
|
||||
std::array<char, 1024> error;
|
||||
mjSpec* spec = mj_parseXMLString(xml, 0, error.data(), error.size());
|
||||
EXPECT_THAT(spec, IsNull()) << error.data();
|
||||
EXPECT_THAT(error.data(), HasSubstr("failed to attach frame"));
|
||||
EXPECT_THAT(error.data(), HasSubstr("repeated name 'b' in actuator"));
|
||||
EXPECT_THAT(error.data(), HasSubstr("Element 'replicate'"));
|
||||
}
|
||||
|
||||
// ---------------------- test spec assets parsing -----------------------------
|
||||
|
||||
TEST_F(XMLReaderTest, ParseSpecAssets) {
|
||||
std::array<char, 1024> er;
|
||||
|
||||
static const char* const kParentPath =
|
||||
"xml/testdata/parent.xml";
|
||||
static const char* const kChildPath =
|
||||
"xml/testdata/child.xml";
|
||||
|
||||
const std::string xml_parent = GetTestDataFilePath(kParentPath);
|
||||
const std::string xml_child = GetTestDataFilePath(kChildPath);
|
||||
|
||||
mjModel* parent = mj_loadXML(xml_parent.c_str(), 0, er.data(), er.size());
|
||||
EXPECT_THAT(parent, NotNull()) << er.data();
|
||||
|
||||
mjModel* child = mj_loadXML(xml_child.c_str(), 0, er.data(), er.size());
|
||||
EXPECT_THAT(child, NotNull()) << er.data();
|
||||
|
||||
mj_deleteModel(parent);
|
||||
mj_deleteModel(child);
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, AttachSpecAssets) {
|
||||
static constexpr char xml_parent[] = R"(
|
||||
<mujoco>
|
||||
<asset>
|
||||
<model name="child" file="xml_child.xml"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="parent">
|
||||
<geom name="geom" size="2"/>
|
||||
<replicate count="2" offset="0 0 1">
|
||||
<attach model="child" body="body" prefix="other"/>
|
||||
</replicate>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
static constexpr char xml_child[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body name="body">
|
||||
<geom name="geom" size="1" pos="2 0 0"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
static constexpr char xml_expected[] = R"(
|
||||
<mujoco>
|
||||
<worldbody>
|
||||
<body name="parent">
|
||||
<geom name="geom" size="2"/>
|
||||
<body name="otherbody0">
|
||||
<geom name="othergeom0" size="1" pos="2 0 0"/>
|
||||
</body>
|
||||
<body name="otherbody1" pos="0 0 1">
|
||||
<geom name="othergeom1" size="1" pos="2 0 0"/>
|
||||
</body>
|
||||
</body>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
auto vfs = std::make_unique<mjVFS>();
|
||||
mj_defaultVFS(vfs.get());
|
||||
mj_addBufferVFS(vfs.get(), "xml_child.xml", xml_child, sizeof(xml_child));
|
||||
|
||||
std::array<char, 1024> er;
|
||||
mjModel* model =
|
||||
LoadModelFromString(xml_parent, er.data(), er.size(), vfs.get());
|
||||
EXPECT_THAT(model, NotNull()) << er.data();
|
||||
|
||||
mjModel* expected = LoadModelFromString(xml_expected, er.data(), er.size());
|
||||
EXPECT_THAT(expected, NotNull()) << er.data();
|
||||
|
||||
mjtNum tol = 0;
|
||||
std::string field = "";
|
||||
EXPECT_LE(CompareModel(model, expected, field), tol)
|
||||
<< "Expected and attached models are different!\n"
|
||||
<< "Different field: " << field << '\n';;
|
||||
|
||||
mj_deleteModel(model);
|
||||
mj_deleteModel(expected);
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, InvalidAttach) {
|
||||
static constexpr char xml_parent[] = R"(
|
||||
<mujoco>
|
||||
<asset>
|
||||
<model name="other" file="child.xml"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<body name="parent">
|
||||
<joint name="joint1"/>
|
||||
<geom size="2"/>
|
||||
<attach model="other" body="body"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<actuator>
|
||||
<motor name="actuator" joint="joint1"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
static constexpr char xml_child[] = R"(
|
||||
<mujoco model="child">
|
||||
<worldbody>
|
||||
<body name="body">
|
||||
<joint name="joint2"/>
|
||||
<geom size="1" pos="2 0 0"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<actuator>
|
||||
<motor name="actuator" joint="joint2"/>
|
||||
</actuator>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
auto vfs = std::make_unique<mjVFS>();
|
||||
mj_defaultVFS(vfs.get());
|
||||
mj_addBufferVFS(vfs.get(), "child.xml", xml_child, sizeof(xml_child));
|
||||
|
||||
std::array<char, 1024> er;
|
||||
mjModel* model =
|
||||
LoadModelFromString(xml_parent, er.data(), er.size(), vfs.get());
|
||||
|
||||
EXPECT_THAT(model, IsNull()) << er.data();
|
||||
EXPECT_THAT(er.data(), HasSubstr("repeated name 'actuator' in actuator"));
|
||||
EXPECT_THAT(er.data(), HasSubstr("Element 'attach'"));
|
||||
mj_deleteVFS(vfs.get());
|
||||
}
|
||||
|
||||
// ----------------------- test camera parsing ---------------------------------
|
||||
|
||||
Reference in New Issue
Block a user