Remove plugin support from Composite particles.
This functionality is replaced by FlexComp. PiperOrigin-RevId: 672503965 Change-Id: I58953267de285f82e416f9f60576a336b7d0da4c
This commit is contained in:
committed by
Copybara-Service
parent
44145742a7
commit
4862b9e765
@@ -3136,12 +3136,7 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
|
|||||||
.. _body-composite-vertex:
|
.. _body-composite-vertex:
|
||||||
|
|
||||||
:at:`vertex`: :at-val:`real(3*nvert), optional`
|
:at:`vertex`: :at-val:`real(3*nvert), optional`
|
||||||
Vertex 3D positions in global coordinates (cable and shell).
|
Vertex 3D positions in global coordinates (cable only).
|
||||||
|
|
||||||
.. _body-composite-face:
|
|
||||||
|
|
||||||
:at:`face`: :at-val:`real(3*nvert), optional`
|
|
||||||
Face connectivity of the vertices (shell only).
|
|
||||||
|
|
||||||
.. _body-composite-initial:
|
.. _body-composite-initial:
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -402,9 +402,7 @@
|
|||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`offset<body-composite-offset>` | :ref:`flatinertia<body-composite-flatinertia>` | :ref:`solrefsmooth<body-composite-solrefsmooth>` | :ref:`solimpsmooth<body-composite-solimpsmooth>` | |
|
| | | | :ref:`offset<body-composite-offset>` | :ref:`flatinertia<body-composite-flatinertia>` | :ref:`solrefsmooth<body-composite-solrefsmooth>` | :ref:`solimpsmooth<body-composite-solimpsmooth>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`vertex<body-composite-vertex>` | :ref:`face<body-composite-face>` | :ref:`initial<body-composite-initial>` | :ref:`curve<body-composite-curve>` | |
|
| | | | :ref:`vertex<body-composite-vertex>` | :ref:`initial<body-composite-initial>` | :ref:`curve<body-composite-curve>` | :ref:`size<body-composite-size>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
|
||||||
| | | | :ref:`size<body-composite-size>` | | | | |
|
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
| |_2| composite |br| |_2| |L| | | .. table:: |
|
| |_2| composite |br| |_2| |L| | | .. table:: |
|
||||||
|
|||||||
+2
-1
@@ -17,7 +17,8 @@ General
|
|||||||
the MPR algorithm. The semantics of these options remain identical.
|
the MPR algorithm. The semantics of these options remain identical.
|
||||||
- The functions ``mjs_findMesh`` and ``mjs_findKeyframe`` were replaced by ``mjs_findElement``, which allows to look
|
- The functions ``mjs_findMesh`` and ``mjs_findKeyframe`` were replaced by ``mjs_findElement``, which allows to look
|
||||||
for any object type.
|
for any object type.
|
||||||
|
- The experimental use of 2D/3D elasticity plugins with :ref:`composite<body-composite>` has been removed. Users
|
||||||
|
should instead use :ref:`flexcomp<body-flexcomp>`, which provides the correct collision behavior.
|
||||||
- Added the :ref:`nativeccd<option-flag-nativeccd>` flag. When this flag is enabled, general convex collision
|
- Added the :ref:`nativeccd<option-flag-nativeccd>` flag. When this flag is enabled, general convex collision
|
||||||
detection is handled natively, as opposed to using `libccd <https://github.com/danfis/libccd>`__. This feature is in
|
detection is handled natively, as opposed to using `libccd <https://github.com/danfis/libccd>`__. This feature is in
|
||||||
early stages of testing.
|
early stages of testing.
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
<!-- Copyright 2021 DeepMind Technologies Limited
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<mujoco model="Flag">
|
|
||||||
<!-- Degree of Freedom (nv): 340
|
|
||||||
Tendons (ntendon): 288
|
|
||||||
Actuators (nu): 0
|
|
||||||
Constraints (nefc): 0
|
|
||||||
This model of a flag passively flapping in the wind has no constraints and is designed to
|
|
||||||
exert smooth dynamics computations.
|
|
||||||
-->
|
|
||||||
<statistic center=".4 0 .8" extent="1.3"/>
|
|
||||||
|
|
||||||
<option wind="5 5 0" density="10" solver="CG" tolerance="1e-6">
|
|
||||||
</option>
|
|
||||||
|
|
||||||
<extension>
|
|
||||||
<plugin plugin="mujoco.elasticity.shell"/>
|
|
||||||
</extension>
|
|
||||||
|
|
||||||
<worldbody>
|
|
||||||
<geom name="floor" type="plane" size="0 0 .1"/>
|
|
||||||
<light diffuse=".6 .6 .6" specular="0.2 0.2 0.2" pos="0 0 4" dir="0 0 -1"/>
|
|
||||||
<body pos="0 0 1">
|
|
||||||
<composite type="particle" count="9 19 1" spacing="0.05" flatinertia="0.01">
|
|
||||||
<skin texcoord="true" inflate="0.005" subgrid="4"/>
|
|
||||||
<geom type="ellipsoid" size="0.025 0.01 0.025" rgba=".8 .2 .1 1" group="4"/>
|
|
||||||
<plugin plugin="mujoco.elasticity.shell">
|
|
||||||
<config key="poisson" value="0"/>
|
|
||||||
<config key="thickness" value="1e-2"/>
|
|
||||||
<!--Units are in Pa (SI)-->
|
|
||||||
<config key="young" value="3e6"/>
|
|
||||||
</plugin>
|
|
||||||
</composite>
|
|
||||||
</body>
|
|
||||||
</worldbody>
|
|
||||||
|
|
||||||
<equality>
|
|
||||||
<connect body1="B0_0_0" anchor="0 0 0" solref="0.0002 1"/>
|
|
||||||
</equality>
|
|
||||||
</mujoco>
|
|
||||||
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
<!-- Copyright 2021 DeepMind Technologies Limited
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<mujoco model="Floppy">
|
|
||||||
<include file="scene.xml"/>
|
|
||||||
|
|
||||||
<extension>
|
|
||||||
<plugin plugin="mujoco.elasticity.solid"/>
|
|
||||||
</extension>
|
|
||||||
|
|
||||||
<compiler autolimits="true"/>
|
|
||||||
|
|
||||||
<option solver="Newton" tolerance="1e-6" timestep=".001"/>
|
|
||||||
|
|
||||||
<size memory="100M"/>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<map stiffness="100"/>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<worldbody>
|
|
||||||
<composite type="particle" count="24 4 4" spacing="0.1" offset=".1 0 1.5">
|
|
||||||
<geom size=".025" rgba=".8 .2 .1 1" group="4"
|
|
||||||
condim="3" solref="0.01 1" solimp=".95 .99 .0001"/>
|
|
||||||
<skin inflate="0" rgba="0 .7 .7 .6"/>
|
|
||||||
<plugin plugin="mujoco.elasticity.solid">
|
|
||||||
<config key="poisson" value="0.2"/>
|
|
||||||
<config key="damping" value="0.002"/>
|
|
||||||
<!--Units are in Pa (SI)-->
|
|
||||||
<config key="young" value="5e4"/>
|
|
||||||
</plugin>
|
|
||||||
</composite>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<joint name="hinge" pos="0 0 .5" axis="0 1 0" damping="50"/>
|
|
||||||
<geom type="cylinder" size=".4" fromto="0 -.5 .5 0 .5 .5" density="300"/>
|
|
||||||
</body>
|
|
||||||
</worldbody>
|
|
||||||
|
|
||||||
<actuator>
|
|
||||||
<motor name="cylinder" joint="hinge" gear="1 0 0 0 0 0" ctrlrange="-100 100"/>
|
|
||||||
</actuator>
|
|
||||||
</mujoco>
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<!-- Copyright 2021 DeepMind Technologies Limited
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<mujoco model="Jelly">
|
|
||||||
<include file="scene.xml"/>
|
|
||||||
|
|
||||||
<extension>
|
|
||||||
<plugin plugin="mujoco.elasticity.solid"/>
|
|
||||||
</extension>
|
|
||||||
|
|
||||||
<option solver="CG" tolerance="1e-6" timestep=".001"/>
|
|
||||||
|
|
||||||
<size memory="10M"/>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<map stiffness="100"/>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<default>
|
|
||||||
<default class="wall">
|
|
||||||
<geom type="plane" size=".5 .5 .05"/>
|
|
||||||
</default>
|
|
||||||
</default>
|
|
||||||
|
|
||||||
<worldbody>
|
|
||||||
<body mocap="true" pos="-.1 .05 0" zaxis=".5 0 1">
|
|
||||||
<geom type="capsule" size=".1 .1" group="1" condim="1"/>
|
|
||||||
</body>
|
|
||||||
<geom name="+x" class="wall" zaxis="1 0 0" pos="-.5 0 -.25"/>
|
|
||||||
<geom name="-x" class="wall" zaxis="-1 0 0" pos=".5 0 -.25"/>
|
|
||||||
<geom name="+y" class="wall" zaxis="0 1 0" pos="0 -.5 -.25"/>
|
|
||||||
<geom name="-y" class="wall" zaxis="0 -1 0" pos="0 .5 -.25"/>
|
|
||||||
<composite type="particle" count="8 8 8" spacing="0.07" offset="0 0 1">
|
|
||||||
<geom size=".025" rgba=".8 .2 .1 1" group="4"/>
|
|
||||||
<skin inflate="0" rgba="0 .7 .7 .6"/>
|
|
||||||
<plugin plugin="mujoco.elasticity.solid">
|
|
||||||
<config key="poisson" value="0"/>
|
|
||||||
<config key="damping" value="0.001"/>
|
|
||||||
<!--Units are in Pa (SI)-->
|
|
||||||
<config key="young" value="5e4"/>
|
|
||||||
</plugin>
|
|
||||||
</composite>
|
|
||||||
</worldbody>
|
|
||||||
</mujoco>
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<!-- Copyright 2021 DeepMind Technologies Limited
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<mujoco model="Plate">
|
|
||||||
<include file="scene.xml"/>
|
|
||||||
|
|
||||||
<extension>
|
|
||||||
<plugin plugin="mujoco.elasticity.shell"/>
|
|
||||||
</extension>
|
|
||||||
|
|
||||||
<option solver="CG" tolerance="1e-6"/>
|
|
||||||
|
|
||||||
<size memory="10M"/>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<map stiffness="100"/>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<default>
|
|
||||||
<default class="wall">
|
|
||||||
<geom type="plane" size=".5 .5 .05"/>
|
|
||||||
</default>
|
|
||||||
</default>
|
|
||||||
|
|
||||||
<worldbody>
|
|
||||||
<body mocap="true" pos="-.1 .05 0" zaxis=".5 0 1">
|
|
||||||
<geom type="capsule" size=".1 .1" group="1"/>
|
|
||||||
</body>
|
|
||||||
<composite type="particle" count="16 16 1" spacing="0.05" offset="0 0 1">
|
|
||||||
<geom size=".02" rgba=".8 .2 .1 1" group="4" density="1000"
|
|
||||||
condim="3" solref="0.01 1" solimp=".95 .99 .0001"/>
|
|
||||||
<skin inflate="0.0001" rgba=".4 0 .3 1" subgrid="1"/>
|
|
||||||
<plugin plugin="mujoco.elasticity.shell">
|
|
||||||
<config key="poisson" value="0"/>
|
|
||||||
<config key="thickness" value="1e-2"/>
|
|
||||||
<!--Units are in Pa (SI)-->
|
|
||||||
<config key="young" value="3e7"/>
|
|
||||||
</plugin>
|
|
||||||
</composite>
|
|
||||||
</worldbody>
|
|
||||||
</mujoco>
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +0,0 @@
|
|||||||
<!-- Copyright 2021 DeepMind Technologies Limited
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<mujoco model="Press">
|
|
||||||
<include file="scene.xml"/>
|
|
||||||
|
|
||||||
<extension>
|
|
||||||
<plugin plugin="mujoco.elasticity.solid"/>
|
|
||||||
</extension>
|
|
||||||
|
|
||||||
<compiler autolimits="true"/>
|
|
||||||
|
|
||||||
<option solver="Newton" tolerance="1e-6" timestep=".001"/>
|
|
||||||
|
|
||||||
<size memory="10M"/>
|
|
||||||
|
|
||||||
<visual>
|
|
||||||
<map stiffness="100"/>
|
|
||||||
</visual>
|
|
||||||
|
|
||||||
<worldbody>
|
|
||||||
<composite prefix="A" type="particle" count="4 4 4" spacing="0.2" offset="0 0 .5">
|
|
||||||
<geom size=".025" rgba=".8 .2 .1 1" group="4"
|
|
||||||
condim="3" solref="0.01 1" solimp=".95 .99 .0001"/>
|
|
||||||
<skin inflate="0" rgba="0 .7 .7 .6"/>
|
|
||||||
<plugin plugin="mujoco.elasticity.solid">
|
|
||||||
<config key="poisson" value="0.4"/>
|
|
||||||
<config key="damping" value="0.001"/>
|
|
||||||
<!--Units are in Pa (SI)-->
|
|
||||||
<config key="young" value="1e4"/>
|
|
||||||
</plugin>
|
|
||||||
</composite>
|
|
||||||
|
|
||||||
<composite prefix="B" type="particle" count="4 4 4" spacing="0.2" offset="1 0 .5">
|
|
||||||
<geom size=".025" rgba=".8 .2 .1 1" group="4"
|
|
||||||
condim="3" solref="0.01 1" solimp=".95 .99 .0001"/>
|
|
||||||
<skin inflate="0" rgba="0 .7 .7 .6"/>
|
|
||||||
<plugin plugin="mujoco.elasticity.solid">
|
|
||||||
<config key="poisson" value="0"/>
|
|
||||||
<config key="damping" value="0.001"/>
|
|
||||||
<!--Units are in Pa (SI)-->
|
|
||||||
<config key="young" value="5e4"/>
|
|
||||||
</plugin>
|
|
||||||
</composite>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<joint name="soft" type="slide" axis="0 0 1" damping="500"/>
|
|
||||||
<geom type="box" size=".35 .35 0.05" pos=".1 .1 .8" density="300"/>
|
|
||||||
</body>
|
|
||||||
<body>
|
|
||||||
<joint name="stiff" type="slide" axis="0 0 1" damping="500"/>
|
|
||||||
<geom type="box" size=".35 .35 0.05" pos="1.1 .1 .8" density="300"/>
|
|
||||||
</body>
|
|
||||||
</worldbody>
|
|
||||||
|
|
||||||
<actuator>
|
|
||||||
<motor name="soft" joint="soft" gear="-1 0 0 0 0 0" ctrlrange="-150 300"/>
|
|
||||||
<motor name="stiff" joint="stiff" gear="-1 0 0 0 0 0" ctrlrange="-150 1600"/>
|
|
||||||
</actuator>
|
|
||||||
</mujoco>
|
|
||||||
@@ -123,8 +123,7 @@ Membrane::Membrane(const mjModel* m, mjData* d, int instance, mjtNum nu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// vertex positions
|
// vertex positions
|
||||||
mjtNum* body_pos =
|
mjtNum* body_pos = m->flex_xvert0 + 3*m->flex_vertadr[f0];
|
||||||
f0 < 0 ? m->body_pos + 3*i0 : m->flex_xvert0 + 3*m->flex_vertadr[f0];
|
|
||||||
|
|
||||||
// generate triangles from the vertices
|
// generate triangles from the vertices
|
||||||
nt = CreateStencils<Stencil2D>(elements, edges, simplex, edgeidx);
|
nt = CreateStencils<Stencil2D>(elements, edges, simplex, edgeidx);
|
||||||
@@ -136,7 +135,7 @@ Membrane::Membrane(const mjModel* m, mjData* d, int instance, mjtNum nu,
|
|||||||
for (int t = 0; t < nt; t++) {
|
for (int t = 0; t < nt; t++) {
|
||||||
int* v = elements[t].vertices;
|
int* v = elements[t].vertices;
|
||||||
for (int i = 0; i < kNumVerts; i++) {
|
for (int i = 0; i < kNumVerts; i++) {
|
||||||
int bi = f0 < 0 ? i0+v[i] : m->flex_vertbodyid[m->flex_vertadr[f0]+v[i]];
|
int bi = m->flex_vertbodyid[m->flex_vertadr[f0]+v[i]];
|
||||||
if (bi && m->body_plugin[bi] != instance) {
|
if (bi && m->body_plugin[bi] != instance) {
|
||||||
mju_error("Body %d does not have plugin instance %d", bi, instance);
|
mju_error("Body %d does not have plugin instance %d", bi, instance);
|
||||||
}
|
}
|
||||||
@@ -182,12 +181,7 @@ void Membrane::Compute(const mjModel* m, mjData* d, int instance) {
|
|||||||
mjtNum kD = damping / m->opt.timestep;
|
mjtNum kD = damping / m->opt.timestep;
|
||||||
|
|
||||||
// update edge lengths
|
// update edge lengths
|
||||||
if (f0 < 0) {
|
UpdateSquaredLengthsFlex(deformed, d->flexedge_length + m->flex_edgeadr[f0]);
|
||||||
UpdateSquaredLengths(deformed, edges, d->xpos+3*i0);
|
|
||||||
} else {
|
|
||||||
UpdateSquaredLengthsFlex(deformed,
|
|
||||||
d->flexedge_length + m->flex_edgeadr[f0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we add generalized Rayleigh damping as decribed in Section 5.2 of
|
// we add generalized Rayleigh damping as decribed in Section 5.2 of
|
||||||
// Kharevych et al., "Geometric, Variational Integrators for Computer
|
// Kharevych et al., "Geometric, Variational Integrators for Computer
|
||||||
@@ -199,18 +193,14 @@ void Membrane::Compute(const mjModel* m, mjData* d, int instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compute gradient of elastic energy and insert into passive force
|
// compute gradient of elastic energy and insert into passive force
|
||||||
int flex_vertadr = f0 < 0 ? -1 : m->flex_vertadr[f0];
|
int flex_vertadr = m->flex_vertadr[f0];
|
||||||
mjtNum* xpos = f0 < 0 ? d->xpos + 3*i0 : d->flexvert_xpos + 3*flex_vertadr;
|
mjtNum* xpos = d->flexvert_xpos + 3*flex_vertadr;
|
||||||
mjtNum* qfrc = d->qfrc_passive + (f0 < 0 ? m->body_dofadr[i0] : 0);
|
mjtNum* qfrc = d->qfrc_passive;
|
||||||
|
|
||||||
ComputeForce<Stencil2D>(force, elements, metric, elongation, m, xpos);
|
ComputeForce<Stencil2D>(force, elements, metric, elongation, m, xpos);
|
||||||
|
|
||||||
// insert into passive force
|
// insert into passive force
|
||||||
if (f0 < 0) {
|
AddFlexForce(qfrc, force, m, d, xpos, f0);
|
||||||
mju_addTo(qfrc, force.data(), force.size());
|
|
||||||
} else {
|
|
||||||
AddFlexForce(qfrc, force, m, d, xpos, f0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update stored lengths
|
// update stored lengths
|
||||||
if (kD > 0) {
|
if (kD > 0) {
|
||||||
|
|||||||
@@ -131,8 +131,7 @@ Solid::Solid(const mjModel* m, mjData* d, int instance, mjtNum nu, mjtNum E,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// vertex positions
|
// vertex positions
|
||||||
mjtNum* body_pos =
|
mjtNum* body_pos = m->flex_xvert0 + 3*m->flex_vertadr[f0];
|
||||||
f0 < 0 ? m->body_pos + 3*i0 : m->flex_xvert0 + 3*m->flex_vertadr[f0];
|
|
||||||
|
|
||||||
// generate tetrahedra from the vertices
|
// generate tetrahedra from the vertices
|
||||||
nt = CreateStencils<Stencil3D>(elements, edges, simplex, edgeidx);
|
nt = CreateStencils<Stencil3D>(elements, edges, simplex, edgeidx);
|
||||||
@@ -144,7 +143,7 @@ Solid::Solid(const mjModel* m, mjData* d, int instance, mjtNum nu, mjtNum E,
|
|||||||
for (int t = 0; t < nt; t++) {
|
for (int t = 0; t < nt; t++) {
|
||||||
int* v = elements[t].vertices;
|
int* v = elements[t].vertices;
|
||||||
for (int i = 0; i < kNumVerts; i++) {
|
for (int i = 0; i < kNumVerts; i++) {
|
||||||
int bi = f0 < 0 ? i0+v[i] : m->flex_vertbodyid[m->flex_vertadr[f0]+v[i]];
|
int bi = m->flex_vertbodyid[m->flex_vertadr[f0]+v[i]];
|
||||||
if (bi && m->body_plugin[bi] != instance) {
|
if (bi && m->body_plugin[bi] != instance) {
|
||||||
mju_error("Body %d does not have plugin instance %d", bi, instance);
|
mju_error("Body %d does not have plugin instance %d", bi, instance);
|
||||||
}
|
}
|
||||||
@@ -189,12 +188,7 @@ void Solid::Compute(const mjModel* m, mjData* d, int instance) {
|
|||||||
mjtNum kD = damping / m->opt.timestep;
|
mjtNum kD = damping / m->opt.timestep;
|
||||||
|
|
||||||
// update edge lengths
|
// update edge lengths
|
||||||
if (f0 < 0) {
|
UpdateSquaredLengthsFlex(deformed, d->flexedge_length + m->flex_edgeadr[f0]);
|
||||||
UpdateSquaredLengths(deformed, edges, d->xpos+3*i0);
|
|
||||||
} else {
|
|
||||||
UpdateSquaredLengthsFlex(deformed,
|
|
||||||
d->flexedge_length + m->flex_edgeadr[f0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we add generalized Rayleigh damping as decribed in Section 5.2 of
|
// we add generalized Rayleigh damping as decribed in Section 5.2 of
|
||||||
// Kharevych et al., "Geometric, Variational Integrators for Computer
|
// Kharevych et al., "Geometric, Variational Integrators for Computer
|
||||||
@@ -206,18 +200,14 @@ void Solid::Compute(const mjModel* m, mjData* d, int instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compute gradient of elastic energy and insert into passive force
|
// compute gradient of elastic energy and insert into passive force
|
||||||
int flex_vertadr = f0 < 0 ? -1 : m->flex_vertadr[f0];
|
int flex_vertadr = m->flex_vertadr[f0];
|
||||||
mjtNum* xpos = f0 < 0 ? d->xpos + 3*i0 : d->flexvert_xpos + 3*flex_vertadr;
|
mjtNum* xpos = d->flexvert_xpos + 3*flex_vertadr;
|
||||||
mjtNum* qfrc = d->qfrc_passive + (f0 < 0 ? m->body_dofadr[i0] : 0);
|
mjtNum* qfrc = d->qfrc_passive;
|
||||||
|
|
||||||
ComputeForce<Stencil3D>(force, elements, metric, elongation, m, xpos);
|
ComputeForce<Stencil3D>(force, elements, metric, elongation, m, xpos);
|
||||||
|
|
||||||
// insert into passive force
|
// insert into passive force
|
||||||
if (f0 < 0) {
|
AddFlexForce(qfrc, force, m, d, xpos, f0);
|
||||||
mju_addTo(qfrc, force.data(), force.size());
|
|
||||||
} else {
|
|
||||||
AddFlexForce(qfrc, force, m, d, xpos, f0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update stored lengths
|
// update stored lengths
|
||||||
if (kD > 0) {
|
if (kD > 0) {
|
||||||
|
|||||||
+11
-201
@@ -301,6 +301,17 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check plugin compatibility
|
||||||
|
// TODO: move mujoco.elasticity.cable to the engine
|
||||||
|
if (plugin.active) {
|
||||||
|
if (type != mjCOMPTYPE_CABLE) {
|
||||||
|
return comperr(error, "Only cable composite supports plugins", error_sz);
|
||||||
|
}
|
||||||
|
if (plugin_name != "mujoco.elasticity.cable") {
|
||||||
|
return comperr(error, "Only mujoco.elasticity.cable is supported by composites", error_sz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// overwrite plugin name
|
// overwrite plugin name
|
||||||
if (plugin_instance_name.empty() && plugin.active) {
|
if (plugin_instance_name.empty() && plugin.active) {
|
||||||
plugin_instance_name = "composite" + prefix;
|
plugin_instance_name = "composite" + prefix;
|
||||||
@@ -372,93 +383,6 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjsBody* body, char* error, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create faces
|
|
||||||
if (userface.empty()) {
|
|
||||||
if (dim == 3) {
|
|
||||||
int cube2tets[6][4] = {{0, 3, 1, 7}, {0, 1, 4, 7},
|
|
||||||
{1, 3, 2, 7}, {1, 2, 6, 7},
|
|
||||||
{1, 5, 4, 7}, {1, 6, 5, 7}};
|
|
||||||
for (int ix = 0; ix < count[0]-1; ix++) {
|
|
||||||
for (int iy = 0; iy < count[1]-1; iy++) {
|
|
||||||
for (int iz = 0; iz < count[2]-1; iz++) {
|
|
||||||
int vert[8] = {
|
|
||||||
count[2]*count[1]*(ix+0) + count[2]*(iy+0) + iz+0,
|
|
||||||
count[2]*count[1]*(ix+1) + count[2]*(iy+0) + iz+0,
|
|
||||||
count[2]*count[1]*(ix+1) + count[2]*(iy+1) + iz+0,
|
|
||||||
count[2]*count[1]*(ix+0) + count[2]*(iy+1) + iz+0,
|
|
||||||
count[2]*count[1]*(ix+0) + count[2]*(iy+0) + iz+1,
|
|
||||||
count[2]*count[1]*(ix+1) + count[2]*(iy+0) + iz+1,
|
|
||||||
count[2]*count[1]*(ix+1) + count[2]*(iy+1) + iz+1,
|
|
||||||
count[2]*count[1]*(ix+0) + count[2]*(iy+1) + iz+1,
|
|
||||||
};
|
|
||||||
for (int s = 0; s < 6; s++) {
|
|
||||||
for (int v = 0; v < 4; v++) {
|
|
||||||
face.push_back(vert[cube2tets[s][v]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (dim == 2) {
|
|
||||||
int quad2tri[2][3] = {{0, 1, 2}, {0, 2, 3}};
|
|
||||||
for (int ix = 0; ix < count[0]-1; ix++) {
|
|
||||||
for (int iy = 0; iy < count[1]-1; iy++) {
|
|
||||||
int vert[4] = {
|
|
||||||
count[2]*count[1]*(ix+0) + count[2]*(iy+0),
|
|
||||||
count[2]*count[1]*(ix+1) + count[2]*(iy+0),
|
|
||||||
count[2]*count[1]*(ix+1) + count[2]*(iy+1),
|
|
||||||
count[2]*count[1]*(ix+0) + count[2]*(iy+1),
|
|
||||||
};
|
|
||||||
for (int s = 0; s < 2; s++) {
|
|
||||||
for (int v = 0; v < 3; v++) {
|
|
||||||
face.push_back(vert[quad2tri[s][v]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
userface = VectorToString(face);
|
|
||||||
} else {
|
|
||||||
dim = 2; // can only load a surface for now
|
|
||||||
face = StringToVector<int>(userface);
|
|
||||||
for (int i=0; i<face.size(); face[i++]--) {};
|
|
||||||
userface = VectorToString(face);
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute volume
|
|
||||||
std::vector<double> volume(uservert.size()/3);
|
|
||||||
double thickness = 1;
|
|
||||||
if (dim == 2 && plugin.active) {
|
|
||||||
try {
|
|
||||||
mjCPlugin* pplugin = static_cast<mjCPlugin*>(plugin.instance);
|
|
||||||
thickness = std::stod(pplugin->config_attribs["thickness"], nullptr);
|
|
||||||
} catch (const std::invalid_argument& e) {
|
|
||||||
return comperr(error, "Invalid thickness attribute", error_sz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!userface.empty()) {
|
|
||||||
face = StringToVector<int>(userface);
|
|
||||||
for (int j=0; j<face.size()/3; j++) {
|
|
||||||
double area[3];
|
|
||||||
double edge1[3];
|
|
||||||
double edge2[3];
|
|
||||||
|
|
||||||
for (int i=0; i<3; i++) {
|
|
||||||
edge1[i] = uservert[3*face[3*j+1]+i] - uservert[3*face[3*j]+i];
|
|
||||||
edge2[i] = uservert[3*face[3*j+2]+i] - uservert[3*face[3*j]+i];
|
|
||||||
}
|
|
||||||
|
|
||||||
mjuu_crossvec(area, edge1, edge2);
|
|
||||||
for (int i=0; i<3; i++) {
|
|
||||||
volume[face[3*j+i]] += sqrt(mjuu_dot3(area, area)) / 2 * thickness;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i=0; i<uservert.size()/3; i++) {
|
|
||||||
volume[i] = 6 * spacing * spacing / 2 * thickness;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create bodies and geoms
|
// create bodies and geoms
|
||||||
for (int i=0; i<uservert.size()/3; i++) {
|
for (int i=0; i<uservert.size()/3; i++) {
|
||||||
// create body
|
// create body
|
||||||
@@ -506,83 +430,6 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjsBody* body, char* error, int
|
|||||||
s->type = mjGEOM_SPHERE;
|
s->type = mjGEOM_SPHERE;
|
||||||
mju::sprintf_arr(txt, "%sS%d", prefix.c_str(), i);
|
mju::sprintf_arr(txt, "%sS%d", prefix.c_str(), i);
|
||||||
mjs_setString(s->name, txt);
|
mjs_setString(s->name, txt);
|
||||||
|
|
||||||
// add plugin
|
|
||||||
if (plugin.active) {
|
|
||||||
mjsPlugin* pplugin = &b->plugin;
|
|
||||||
mjCPlugin* cplugin = static_cast<mjCPlugin*>(plugin.instance);
|
|
||||||
pplugin->active = true;
|
|
||||||
pplugin->instance = plugin.instance;
|
|
||||||
mjs_setString(pplugin->instance_name, plugin_instance_name.c_str());
|
|
||||||
mjs_setString(pplugin->name, mjs_getString(plugin.name));
|
|
||||||
|
|
||||||
if (i==0 && !cplugin->config_attribs["face"].empty()) {
|
|
||||||
return comperr(error, "Face attribute already exists in plugin", error_sz);
|
|
||||||
}
|
|
||||||
|
|
||||||
cplugin->config_attribs["face"] = userface;
|
|
||||||
cplugin->config_attribs["edge"] = "";
|
|
||||||
|
|
||||||
// update density
|
|
||||||
if (dim == 2) {
|
|
||||||
g->density *= volume[i] / (4./3. * mjPI * pow(g->size[0], 3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add isometry constraints
|
|
||||||
if (dim==2) {
|
|
||||||
char txt0[100], txt1[100], txt2[100];
|
|
||||||
std::vector<std::pair<int, int>> edge;
|
|
||||||
|
|
||||||
// create edges
|
|
||||||
for (int i=0; i<face.size()/3; i++) {
|
|
||||||
for (int j=0; j<3; j++) {
|
|
||||||
int v0 = face[3*i+(j+0)%3];
|
|
||||||
int v1 = face[3*i+(j+1)%3];
|
|
||||||
edge.push_back(v0 < v1 ? std::pair(v0, v1) : std::pair(v1, v0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(edge.begin(), edge.end());
|
|
||||||
auto last = std::unique(edge.begin(), edge.end());
|
|
||||||
edge.erase(last, edge.end());
|
|
||||||
|
|
||||||
// create constraints
|
|
||||||
for (int i=0; i<edge.size(); i++) {
|
|
||||||
int v0 = edge[i].first;
|
|
||||||
int v1 = edge[i].second;
|
|
||||||
|
|
||||||
mju::sprintf_arr(txt0, "%sT%d_%d", prefix.c_str(), v0, v1);
|
|
||||||
mju::sprintf_arr(txt1, "%sS%d", prefix.c_str(), v0);
|
|
||||||
mju::sprintf_arr(txt2, "%sS%d", prefix.c_str(), v1);
|
|
||||||
|
|
||||||
// create tendon
|
|
||||||
mjsTendon* ten = mjs_addTendon(&model->spec, &def[mjCOMPKIND_TENDON].spec);
|
|
||||||
mjs_setDefault(ten->element, &model->Default()->spec);
|
|
||||||
mjs_setString(ten->name, txt0);
|
|
||||||
ten->group = 4;
|
|
||||||
mjs_wrapSite(ten, txt1);
|
|
||||||
mjs_wrapSite(ten, txt2);
|
|
||||||
|
|
||||||
// add equality constraint
|
|
||||||
mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_TENDON].spec);
|
|
||||||
mjs_setDefault(eq->element, &model->Default()->spec);
|
|
||||||
eq->type = mjEQ_TENDON;
|
|
||||||
mjs_setString(eq->name1, mjs_getString(ten->name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skin && dim==3) {
|
|
||||||
MakeSkin3(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skin && dim==2) {
|
|
||||||
if (skinsubgrid>0) {
|
|
||||||
MakeSkin2Subgrid(model, skininflate);
|
|
||||||
} else {
|
|
||||||
MakeSkin2(model, skininflate);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1303,43 +1150,6 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
|
|||||||
skin->inflate = inflate;
|
skin->inflate = inflate;
|
||||||
skin->group = skingroup;
|
skin->group = skingroup;
|
||||||
|
|
||||||
// copy skin from existing mesh
|
|
||||||
if (type==mjCOMPTYPE_PARTICLE && username.empty()) {
|
|
||||||
std::vector<int> skinface;
|
|
||||||
skinface = StringToVector<int>(userface);
|
|
||||||
int nvert = uservert.size()/3;
|
|
||||||
|
|
||||||
for (int j=0; j<2; j++) {
|
|
||||||
for (int i=0; i<nvert; i++) {
|
|
||||||
vert.push_back(0);
|
|
||||||
vert.push_back(0);
|
|
||||||
vert.push_back(0);
|
|
||||||
|
|
||||||
mju::sprintf_arr(txt, "%sB%d", prefix.c_str(), i);
|
|
||||||
mjs_appendString(skin->bodyname, txt);
|
|
||||||
bindpos.push_back(0);
|
|
||||||
bindpos.push_back(0);
|
|
||||||
bindpos.push_back(0);
|
|
||||||
bindquat.push_back(1);
|
|
||||||
bindquat.push_back(0);
|
|
||||||
bindquat.push_back(0);
|
|
||||||
bindquat.push_back(0);
|
|
||||||
|
|
||||||
vertid.push_back({j*nvert+i});
|
|
||||||
vertweight.push_back({1});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0; i<skinface.size()/3; i++) {
|
|
||||||
face.push_back(j*nvert+skinface[3*i]);
|
|
||||||
face.push_back(j*nvert+skinface[3*i+(j==0 ? 1 : 2)]);
|
|
||||||
face.push_back(j*nvert+skinface[3*i+(j==0 ? 2 : 1)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyIntoSkin(skin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// populate mesh: two sides
|
// populate mesh: two sides
|
||||||
for (int i=0; i<2; i++) {
|
for (int i=0; i<2; i++) {
|
||||||
for (int ix=0; ix<count[0]; ix++) {
|
for (int ix=0; ix<count[0]; ix++) {
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ class mjCComposite {
|
|||||||
// currently used only for cable
|
// currently used only for cable
|
||||||
std::string initial; // root boundary type
|
std::string initial; // root boundary type
|
||||||
std::vector<float> uservert; // user-specified vertex positions
|
std::vector<float> uservert; // user-specified vertex positions
|
||||||
std::string userface; // connectivity
|
|
||||||
double size[3]; // rope size (meaning depends on the shape)
|
double size[3]; // rope size (meaning depends on the shape)
|
||||||
mjtCompShape curve[3]; // geometric shape
|
mjtCompShape curve[3]; // geometric shape
|
||||||
|
|
||||||
|
|||||||
@@ -296,8 +296,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
|
|||||||
{"<"},
|
{"<"},
|
||||||
{"config", "*", "2", "key", "value"},
|
{"config", "*", "2", "key", "value"},
|
||||||
{">"},
|
{">"},
|
||||||
{"composite", "*", "13", "prefix", "type", "count", "spacing", "offset",
|
{"composite", "*", "12", "prefix", "type", "count", "spacing", "offset",
|
||||||
"flatinertia", "solrefsmooth", "solimpsmooth", "vertex", "face",
|
"flatinertia", "solrefsmooth", "solimpsmooth", "vertex",
|
||||||
"initial", "curve", "size"},
|
"initial", "curve", "size"},
|
||||||
{"<"},
|
{"<"},
|
||||||
{"joint", "*", "17", "kind", "group", "stiffness", "damping", "armature",
|
{"joint", "*", "17", "kind", "group", "stiffness", "damping", "armature",
|
||||||
@@ -2371,9 +2371,6 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, mjsDefault* def) {
|
|||||||
comp.uservert = std::move(uservert.value());
|
comp.uservert = std::move(uservert.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
// shell
|
|
||||||
ReadAttrTxt(elem, "face", comp.userface);
|
|
||||||
|
|
||||||
// process curve string
|
// process curve string
|
||||||
std::istringstream iss(curves);
|
std::istringstream iss(curves);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ void ABSL_ATTRIBUTE_NOINLINE mulMatVecSparse_8(mjtNum* res,
|
|||||||
// ----------------------------- benchmark ------------------------------------
|
// ----------------------------- benchmark ------------------------------------
|
||||||
|
|
||||||
static void BM_MatVecSparse(benchmark::State& state, int unroll) {
|
static void BM_MatVecSparse(benchmark::State& state, int unroll) {
|
||||||
static mjModel* m = LoadModelFromPath("plugin/elasticity/flag.xml");
|
static mjModel* m = LoadModelFromPath("plugin/elasticity/flag_flex.xml");
|
||||||
mjData* d = mj_makeData(m);
|
mjData* d = mj_makeData(m);
|
||||||
|
|
||||||
// warm-up rollout to get a typical state
|
// warm-up rollout to get a typical state
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ static void run_parse_benchmark(const std::string xml_path,
|
|||||||
// run_parse_benchmark).
|
// run_parse_benchmark).
|
||||||
|
|
||||||
void ABSL_ATTRIBUTE_NO_TAIL_CALL BM_ParseFlagPlugin(benchmark::State& state) {
|
void ABSL_ATTRIBUTE_NO_TAIL_CALL BM_ParseFlagPlugin(benchmark::State& state) {
|
||||||
run_parse_benchmark(GetModelPath("plugin/elasticity/flag.xml"), state);
|
run_parse_benchmark(GetModelPath("plugin/elasticity/flag_flex.xml"), state);
|
||||||
}
|
}
|
||||||
BENCHMARK(BM_ParseFlagPlugin);
|
BENCHMARK(BM_ParseFlagPlugin);
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ static void run_step_benchmark(const mjModel* model, benchmark::State& state) {
|
|||||||
|
|
||||||
void ABSL_ATTRIBUTE_NO_TAIL_CALL BM_StepFlagPlugin(benchmark::State& state) {
|
void ABSL_ATTRIBUTE_NO_TAIL_CALL BM_StepFlagPlugin(benchmark::State& state) {
|
||||||
MujocoErrorTestGuard guard;
|
MujocoErrorTestGuard guard;
|
||||||
static mjModel* model = LoadModelFromPath("plugin/elasticity/flag.xml");
|
static mjModel* model = LoadModelFromPath("plugin/elasticity/flag_flex.xml");
|
||||||
run_step_benchmark(model, state);
|
run_step_benchmark(model, state);
|
||||||
}
|
}
|
||||||
BENCHMARK(BM_StepFlagPlugin);
|
BENCHMARK(BM_StepFlagPlugin);
|
||||||
|
|||||||
@@ -184,12 +184,13 @@ TEST_F(ElasticityTest, InvalidThickness) {
|
|||||||
</extension>
|
</extension>
|
||||||
|
|
||||||
<worldbody>
|
<worldbody>
|
||||||
<composite type="particle" count="2 2 1" spacing="1">
|
<flexcomp type="grid" count="2 2 1" spacing="1 1 1"
|
||||||
<geom size=".025"/>
|
radius=".025" name="test" dim="2">
|
||||||
<plugin plugin="mujoco.elasticity.shell">
|
<plugin plugin="mujoco.elasticity.shell">
|
||||||
<config key="thickness" value="hello"/>
|
<config key="thickness" value="hello"/>
|
||||||
</plugin>
|
</plugin>
|
||||||
</composite>
|
<edge equality="false"/>
|
||||||
|
</flexcomp>
|
||||||
</worldbody>
|
</worldbody>
|
||||||
</mujoco>
|
</mujoco>
|
||||||
)";
|
)";
|
||||||
@@ -197,6 +198,7 @@ TEST_F(ElasticityTest, InvalidThickness) {
|
|||||||
char error[1024] = {0};
|
char error[1024] = {0};
|
||||||
mjModel* m = LoadModelFromString(xml, error, sizeof(error));
|
mjModel* m = LoadModelFromString(xml, error, sizeof(error));
|
||||||
ASSERT_THAT(m, testing::IsNull());
|
ASSERT_THAT(m, testing::IsNull());
|
||||||
|
EXPECT_THAT(error, ::testing::HasSubstr("Invalid parameter"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------- solid -----------------------------------
|
// -------------------------------- solid -----------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user