Add two new attributes to weld constraints:
- `anchor` determines the point of wrench application, in the frame of body2. - `tfratio` scales applied torques relative to applied forces. - Add visualisation of both anchor points to both weld and connect constraints. - Add a test model showing how the new weld parameters behave. PiperOrigin-RevId: 469228149 Change-Id: I836b0791f10fb624607a12ef3c687da991c21789
This commit is contained in:
committed by
Copybara-Service
parent
558aaf2923
commit
abc0a39b7a
@@ -56,9 +56,10 @@ TEST_F(CoreSmoothTest, MjKinematicsWorldXipos) {
|
||||
|
||||
// --------------------------- connect constraint ------------------------------
|
||||
|
||||
// test that bodies hanging on connects lead to expected force sensor readings
|
||||
void TestConnect(const char* const filepath) {
|
||||
const std::string xml_path = GetTestDataFilePath(filepath);
|
||||
TEST_F(CoreSmoothTest, RnePostConnectForceSlide) {
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/connect/force_slide.xml";
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
@@ -74,46 +75,88 @@ void TestConnect(const char* const filepath) {
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostConnectForceSlide) {
|
||||
constexpr char kModelFilePath[] =
|
||||
"engine/testdata/core_smooth/rne_post/connect/force_slide.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostConnectForceSlideRotated) {
|
||||
constexpr char kModelFilePath[] =
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/connect/force_slide_rotated.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
// settle physics:
|
||||
for (int i=0; i < 1000; i++) {
|
||||
mj_step(model, data);
|
||||
}
|
||||
for (int i=0; i < 3; i++) {
|
||||
EXPECT_NEAR(data->sensordata[i], model->sensor_user[i], 1e-6);
|
||||
}
|
||||
mj_deleteData(data);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostConnectForceFree) {
|
||||
constexpr char kModelFilePath[] =
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/connect/force_free.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
// settle physics:
|
||||
for (int i=0; i < 1000; i++) {
|
||||
mj_step(model, data);
|
||||
}
|
||||
for (int i=0; i < 3; i++) {
|
||||
EXPECT_NEAR(data->sensordata[i], model->sensor_user[i], 1e-6);
|
||||
}
|
||||
mj_deleteData(data);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostConnectTorque) {
|
||||
constexpr char kModelFilePath[] =
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/connect/torque_free.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
// settle physics:
|
||||
for (int i=0; i < 1000; i++) {
|
||||
mj_step(model, data);
|
||||
}
|
||||
for (int i=0; i < 3; i++) {
|
||||
EXPECT_NEAR(data->sensordata[i], model->sensor_user[i], 1e-6);
|
||||
}
|
||||
mj_deleteData(data);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostConnectMultipleConstraints) {
|
||||
constexpr char kModelFilePath[] =
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/connect/multiple_constraints.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
// settle physics:
|
||||
for (int i=0; i < 1000; i++) {
|
||||
mj_step(model, data);
|
||||
}
|
||||
for (int i=0; i < 3; i++) {
|
||||
EXPECT_NEAR(data->sensordata[i], model->sensor_user[i], 1e-6);
|
||||
}
|
||||
mj_deleteData(data);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------- weld constraint ---------------------------------
|
||||
|
||||
// test that bodies attached with welds lead to expected force sensor readings
|
||||
void TestWeld(const char* const filepath) {
|
||||
const std::string xml_path = GetTestDataFilePath(filepath);
|
||||
TEST_F(CoreSmoothTest, RnePostWeldForceFree) {
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/weld/force_free.xml";
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
@@ -134,65 +177,75 @@ void TestWeld(const char* const filepath) {
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostWeldForceFree) {
|
||||
constexpr char kModelFilePath[] =
|
||||
"engine/testdata/core_smooth/rne_post/weld/force_free.xml";
|
||||
TestWeld(kModelFilePath);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostWeldForceFreeRotated) {
|
||||
constexpr char kModelFilePath[] =
|
||||
TEST_F(CoreSmoothTest, RnePostWeldForceFreeRotatoed) {
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/weld/force_free_rotated.xml";
|
||||
TestWeld(kModelFilePath);
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
// settle physics:
|
||||
for (int i=0; i < 1000; i++) {
|
||||
mj_step(model, data);
|
||||
}
|
||||
for (int sensor_index=0; sensor_index < model->nsensor; sensor_index++) {
|
||||
for (int i=0; i < 3; i++) {
|
||||
EXPECT_NEAR(
|
||||
data->sensordata[model->sensor_adr[sensor_index] + i],
|
||||
model->sensor_user[model->nuser_sensor*sensor_index + i],
|
||||
1e-6);
|
||||
}
|
||||
}
|
||||
mj_deleteData(data);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostWeldForceTorqueFree) {
|
||||
constexpr char kModelFilePath[] =
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/weld/force_torque_free.xml";
|
||||
TestWeld(kModelFilePath);
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
// settle physics:
|
||||
for (int i=0; i < 1000; i++) {
|
||||
mj_step(model, data);
|
||||
}
|
||||
for (int sensor_index=0; sensor_index < model->nsensor; sensor_index++) {
|
||||
for (int i=0; i < 3; i++) {
|
||||
EXPECT_NEAR(
|
||||
data->sensordata[model->sensor_adr[sensor_index] + i],
|
||||
model->sensor_user[model->nuser_sensor*sensor_index + i],
|
||||
1e-6);
|
||||
}
|
||||
}
|
||||
mj_deleteData(data);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, RnePostWeldForceTorqueFreeRotated) {
|
||||
constexpr char kModelFilePath[] =
|
||||
static const char* const kModelFilePath =
|
||||
"engine/testdata/core_smooth/rne_post/weld/force_torque_free_rotated.xml";
|
||||
TestWeld(kModelFilePath);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, WeldRatioForceFree) {
|
||||
constexpr char kModelFilePath[] =
|
||||
"engine/testdata/core_smooth/rne_post/weld/tfratio0_force_free.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, WeldRatioForceSlide) {
|
||||
constexpr char kModelFilePath[] =
|
||||
"engine/testdata/core_smooth/rne_post/weld/tfratio0_force_slide.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, WeldRatioTorqueFree) {
|
||||
constexpr char kModelFilePath[] =
|
||||
"engine/testdata/core_smooth/rne_post/weld/tfratio0_torque_free.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(CoreSmoothTest, WeldRatioForceSlideRotated) {
|
||||
constexpr char kModelFilePath[] =
|
||||
"engine/testdata/core_smooth/rne_post/weld/tfratio0_force_slide_rotated.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
}
|
||||
|
||||
TEST_F(CoreSmoothTest, WeldRatioMultipleConstraints) {
|
||||
constexpr char kModelFilePath[] =
|
||||
"engine/testdata/core_smooth/rne_post/weld/tfratio0_multiple_constraints.xml";
|
||||
TestConnect(kModelFilePath);
|
||||
const std::string xml_path = GetTestDataFilePath(kModelFilePath);
|
||||
mjModel* model =
|
||||
mj_loadXML(xml_path.c_str(), nullptr, 0, 0);
|
||||
mjData* data = mj_makeData(model);
|
||||
// settle physics:
|
||||
for (int i=0; i < 1000; i++) {
|
||||
mj_step(model, data);
|
||||
}
|
||||
for (int sensor_index=0; sensor_index < model->nsensor; sensor_index++) {
|
||||
for (int i=0; i < 3; i++) {
|
||||
EXPECT_NEAR(
|
||||
data->sensordata[model->sensor_adr[sensor_index] + i],
|
||||
model->sensor_user[model->nuser_sensor*sensor_index + i],
|
||||
1e-6);
|
||||
}
|
||||
}
|
||||
mj_deleteData(data);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,43 +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>
|
||||
<!--
|
||||
body2 is held by body1 through the weld constraint, so the force sensor on body1
|
||||
should register -2*gravity (for the weight of both bodies).
|
||||
-->
|
||||
<option gravity="1 2 3"/>
|
||||
|
||||
<default>
|
||||
<!-- A cube of size 0.1^3 with density of 1000 has mass of 1. -->
|
||||
<geom density="1000" size="0.05 0.05 0.05" type="box"/>
|
||||
</default>
|
||||
|
||||
<worldbody>
|
||||
<body name="body1">
|
||||
<geom/>
|
||||
<site name="sensor"/>
|
||||
</body>
|
||||
<body name="body2" pos="1 2 3">
|
||||
<joint type="free"/>
|
||||
<geom/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<equality>
|
||||
<weld body1="body1" body2="body2" anchor="0 0 0" tfratio="0"/>
|
||||
</equality>
|
||||
|
||||
<sensor>
|
||||
<force site="sensor" user="-2 -4 -6"/>
|
||||
</sensor>
|
||||
</mujoco>
|
||||
@@ -1,43 +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>
|
||||
<!--
|
||||
body2 is held by body1 through the weld constraint, so the force sensor on body1
|
||||
should register 20 (for the weight of both bodies).
|
||||
-->
|
||||
<option gravity="0 0 -1"/>
|
||||
|
||||
<default>
|
||||
<!-- A cube of size 0.1^3 with density of 1000 has mass of 1. -->
|
||||
<geom size="0.05 0.05 0.05" type="box"/>
|
||||
</default>
|
||||
|
||||
<worldbody>
|
||||
<body name="body1">
|
||||
<geom/>
|
||||
<site name="sensor"/>
|
||||
</body>
|
||||
<body name="body2" pos="0 0 -0.1">
|
||||
<joint type="slide" axis="0 0 1"/>
|
||||
<geom/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<equality>
|
||||
<weld body1="body1" body2="body2" anchor="0 0 0" tfratio="0"/>
|
||||
</equality>
|
||||
|
||||
<sensor>
|
||||
<force site="sensor" user="0 0 2"/>
|
||||
</sensor>
|
||||
</mujoco>
|
||||
-43
@@ -1,43 +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>
|
||||
<!--
|
||||
body2 is held by body1 through the weld constraint, so the force sensor on body1
|
||||
should register 20 (for the weight of both bodies), rotated into the y-z plane.
|
||||
-->
|
||||
<option gravity="0 0 -1"/>
|
||||
|
||||
<default>
|
||||
<!-- A cube of size 0.1^3 with density of 1000 has mass of 1. -->
|
||||
<geom size="0.05 0.05 0.05" type="box"/>
|
||||
</default>
|
||||
|
||||
<worldbody>
|
||||
<body name="body1" euler="0 45 0">
|
||||
<geom/>
|
||||
<site name="sensor" euler="0 0 90"/>
|
||||
</body>
|
||||
<body name="body2" pos="0 0 -0.2">
|
||||
<joint type="slide" axis="0 0 1"/>
|
||||
<geom/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<equality>
|
||||
<weld body1="body1" body2="body2" anchor="0 0 0" tfratio="0"/>
|
||||
</equality>
|
||||
|
||||
<sensor>
|
||||
<force site="sensor" user="0 1.41421356237 1.41421356237"/>
|
||||
</sensor>
|
||||
</mujoco>
|
||||
-59
@@ -1,59 +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>
|
||||
<!--
|
||||
Same as force_free.xml, but with a distractor constraint.
|
||||
-->
|
||||
<option gravity="1 2 3"/>
|
||||
|
||||
<default>
|
||||
<!-- A cube of size 0.1^3 with density of 1000 has mass of 1. -->
|
||||
<geom size="0.05 0.05 0.05" type="box"/>
|
||||
</default>
|
||||
|
||||
<worldbody>
|
||||
<body name="body0" pos="-3 0 0">
|
||||
<joint name="joint0" type="slide" axis="0 0 1"/>
|
||||
<geom/>
|
||||
</body>
|
||||
<body name="body1">
|
||||
<geom/>
|
||||
<site name="sensor"/>
|
||||
</body>
|
||||
<body name="body2" pos="1 2 3">
|
||||
<joint type="free"/>
|
||||
<geom/>
|
||||
</body>
|
||||
<body name="body3" pos="3 0 0">
|
||||
<geom/>
|
||||
<body name="body3b" pos="3 0 -1">
|
||||
<joint type="slide" axis="0 0 1" frictionloss="9"/>
|
||||
<geom/>
|
||||
</body>
|
||||
</body>
|
||||
<body name="body4" pos="4 0 0">
|
||||
<joint type="free"/>
|
||||
<geom/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<equality>
|
||||
<joint joint1="joint0"/>
|
||||
<weld body1="body3" body2="body4"/>
|
||||
<weld body1="body1" body2="body2" anchor="0 0 0" tfratio="0"/>
|
||||
</equality>
|
||||
|
||||
<sensor>
|
||||
<force site="sensor" user="-2 -4 -6"/>
|
||||
</sensor>
|
||||
</mujoco>
|
||||
@@ -1,43 +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>
|
||||
<!--
|
||||
body2 is free, but because it's offset on y it wants to rotate about x due to gravity on z. The
|
||||
connect prevents that, so the torque sensor should record the weight*offset of the second body.
|
||||
-->
|
||||
<option gravity="0 0 -1"/>
|
||||
|
||||
<default>
|
||||
<!-- A cube of size 0.1^3 with density of 1000 has mass of 1. -->
|
||||
<geom size="0.05 0.05 0.05" type="box"/>
|
||||
</default>
|
||||
|
||||
<worldbody>
|
||||
<body name="body1">
|
||||
<geom/>
|
||||
<site name="sensor"/>
|
||||
</body>
|
||||
<body name="body2" pos="0 2 0">
|
||||
<freejoint/>
|
||||
<geom/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<equality>
|
||||
<weld body1="body1" body2="body2" anchor="0 0 0" tfratio="0"/>
|
||||
</equality>
|
||||
|
||||
<sensor>
|
||||
<torque site="sensor" user="2 0 0"/>
|
||||
</sensor>
|
||||
</mujoco>
|
||||
Vendored
-58
@@ -1,58 +0,0 @@
|
||||
<mujoco>
|
||||
<option>
|
||||
<flag contact="disable"/>
|
||||
</option>
|
||||
|
||||
<default>
|
||||
<default class="static">
|
||||
<geom size=".5 .1 .5" rgba=".5 .7 .5 .3"/>
|
||||
</default>
|
||||
<default class="free">
|
||||
<geom type="box" size=".2" fromto="0 0 0 0 -2 0" rgba=".4 .7 .6 .3"/>
|
||||
</default>
|
||||
</default>
|
||||
|
||||
<worldbody>
|
||||
<geom pos="0 0 -2" type="plane" size="10 10 .01"/>
|
||||
<light pos="0 0 20"/>
|
||||
|
||||
<body name="box1" pos="-3 0 0">
|
||||
<geom type="box" class="static"/>
|
||||
</body>
|
||||
<body name="beam1" pos="-3 0 0">
|
||||
<freejoint/>
|
||||
<geom class="free"/>
|
||||
</body>
|
||||
|
||||
<body name="box2" pos="-1 0 0">
|
||||
<geom type="box" class="static"/>
|
||||
</body>
|
||||
<body name="beam2" pos="-1 0 0">
|
||||
<freejoint/>
|
||||
<geom class="free"/>
|
||||
</body>
|
||||
|
||||
<body name="box3" pos="1 0 0">
|
||||
<geom type="box" class="static"/>
|
||||
</body>
|
||||
<body name="beam3" pos="1 0 0">
|
||||
<freejoint/>
|
||||
<geom class="free"/>
|
||||
</body>
|
||||
|
||||
<body name="box4" pos="3 0 0">
|
||||
<geom type="box" class="static"/>
|
||||
</body>
|
||||
<body name="beam4" pos="3 0 0">
|
||||
<freejoint/>
|
||||
<geom class="free"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<equality>
|
||||
<weld name="weak torques" body1="box1" body2="beam1" tfratio="0.002"/>
|
||||
<weld name="anchor no torques" body1="box2" body2="beam2" tfratio="0" anchor="0 -2 0"/>
|
||||
<weld name="relpose" body1="box3" body2="beam3" relpose="0 0 0 1 -.3 0 0"/>
|
||||
<weld name="relpose+anchor" body1="box4" body2="beam4" relpose="0 0 0 1 -.3 0 0" anchor="0 0 -1"/>
|
||||
</equality>
|
||||
</mujoco>
|
||||
Reference in New Issue
Block a user