Add circle to flexcomp and remove rope and loop from composite.
Add pulley example to show a circle use case. Switch on flex edge rendering by default (no effect when flex skin is rendered). PiperOrigin-RevId: 700738379 Change-Id: I8469bbf194de01c8dab66c9a51c49879013df141
This commit is contained in:
committed by
Copybara-Service
parent
85c6fc1bdb
commit
300450f8b8
+8
-15
@@ -2981,20 +2981,6 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
|
||||
define the tendons). The "main" tendons are parallel to the axes of the grid. In addition one can create diagonal
|
||||
"shear" tendons, using the :el:`tendon` sub-element. This type is suitable for simulating strings as well as cloth.
|
||||
|
||||
The **rope** type creates a 1D grid of bodies, each having a geom with user-defined type (sphere, capsule or
|
||||
ellipsoid) and 2 hinge joints with axes orthogonal to the grid, creating a universal joint with the previous body.
|
||||
This corresponds to a kinematic chain which can bend but cannot stretch or twist. In addition, one can specify
|
||||
stretch and twist joints (slide and hinge respectively) with the :el:`joint` sub-element. When specified, these extra
|
||||
joints are equality-constrained, but the constraint is soft by default so that some stretch and twist are possible.
|
||||
The rope can extend in one or both directions from the parent body. To specify the origin of the rope, the parent
|
||||
body *must* be named so that it fits the automatic naming convention. For example, to make the parent be the first
|
||||
body in the chain, and assuming we have prefix="C", the parent body should be named "CB0". When the parent is not at
|
||||
the end, the rope consists of two kinematic chains starting at the parent and extending in opposite directions.
|
||||
|
||||
The **loop** type is the same as the rope type except the elements are arranged in a circle, and the first and last
|
||||
elements are equality-constrained to remain connected (using the "connect" constraint type). The softness of this
|
||||
equality constraint is adjusted with the attributes solrefsmooth and solimpsmooth.
|
||||
|
||||
The **cable** type creates a 1D chain of bodies connected with ball joints, each having a geom with user-defined type
|
||||
(cylinder, capsule or box). The geometry can either be defined with an array of 3D vertex coordinates :at:`vertex`
|
||||
or with prescribed functions with the option :at:`curve`. Currently, only linear and trigonometric functions are
|
||||
@@ -3489,7 +3475,7 @@ saving the XML:
|
||||
|
||||
.. _body-flexcomp-type:
|
||||
|
||||
:at:`type`: :at-val:`[grid, box, cylinder, ellipsoid, mesh, gmsh, direct], "grid"`
|
||||
:at:`type`: :at-val:`[grid, box, cylinder, ellipsoid, disc, circle, mesh, gmsh, direct], "grid"`
|
||||
This attribute determines the type of :el:`flexcomp` object. The remaining attributes and sub-elements are then
|
||||
interpreted according to the type. Default settings are also adjusted depending on the type. Different types
|
||||
correspond to different methods for specifying the flexcomp points and the stretchable elements that connect them.
|
||||
@@ -3513,6 +3499,13 @@ saving the XML:
|
||||
|
||||
**ellipsoid** is the same as **box**, except the points are projected on the surface of an ellipsoid.
|
||||
|
||||
**disc** is the same as **box**, except the points are projected on the surface of a disc. It is only compatible
|
||||
with :at:`dim=2`.
|
||||
|
||||
**circle** is the same as **grid**, except the points are sampled along a circle so that the first and last points
|
||||
are the same. The radius of the circle is computed such that each segment has the requested spacing. It is only
|
||||
compatible with :at:`dim=1`.
|
||||
|
||||
**mesh** loads the flexcomp points and elements (i.e. triangles) from a mesh file, in the same file formats as mesh
|
||||
assets. A mesh asset is not actually added to the model. Instead the vertex and face data from the mesh file are used
|
||||
to populate the point and element data of the flexcomp. :at:`dim` is automatically set to 2. Recall that a mesh asset
|
||||
|
||||
@@ -6,6 +6,11 @@ Changelog
|
||||
Upcoming version (not yet released)
|
||||
-----------------------------------
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
- Removed rope and loop from :ref:`composite<body-composite>`. The user is encouraged to instead use the :at:`cable`
|
||||
plugin or :ref:`flexcomp<body-flexcomp>`, respectively.
|
||||
|
||||
MJX
|
||||
^^^
|
||||
- Added muscle actuators.
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<!-- 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="Pulley">
|
||||
<include file="scene.xml"/>
|
||||
|
||||
<option>
|
||||
<flag gravity="disable"/>
|
||||
</option>
|
||||
|
||||
<statistic center="0 -.3 1" extent="2.5"/>
|
||||
|
||||
<worldbody>
|
||||
<flexcomp name="cable" type="circle" count="40 1 1" spacing=".15 1 1" dim="1"
|
||||
radius="0.02" pos="0 0 1" rgba="1 0 0 1">
|
||||
<edge equality="true"/>
|
||||
</flexcomp>
|
||||
<body name="left" pos="-.7 0 1">
|
||||
<joint name="expand_left" type="slide" axis="-1 0 0" range="0 2" damping="20"/>
|
||||
<joint name="rotate" type="hinge" axis="0 0 1"/>
|
||||
<geom type="cylinder" size=".2 .2" density="1"/>
|
||||
</body>
|
||||
<body name="right" pos=".7 0 1">
|
||||
<joint name="expand_right" type="slide" axis="1 0 0" range="0 2" damping="20"/>
|
||||
<joint type="hinge" axis="0 0 1"/>
|
||||
<geom type="cylinder" size=".2 .2" density="1"/>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<actuator>
|
||||
<position name="expand_left" joint="expand_left" ctrlrange="0 2" kp="100"/>
|
||||
<position name="expand_right" joint="expand_right" ctrlrange="0 2" kp="100"/>
|
||||
<velocity name="rotate" joint="rotate" ctrlrange="0 8"/>
|
||||
</actuator>
|
||||
|
||||
<keyframe>
|
||||
<key ctrl=".7 .7 8"/>
|
||||
</keyframe>
|
||||
</mujoco>
|
||||
@@ -93,7 +93,7 @@ const char* mjVISSTRING[mjNVISFLAG][3] = {
|
||||
{"Static Body", "1", "D"},
|
||||
{"Skin", "1", ";"},
|
||||
{"Flex Vert", "0", ""},
|
||||
{"Flex Edge", "0", ""},
|
||||
{"Flex Edge", "1", ""},
|
||||
{"Flex Face", "0", ""},
|
||||
{"Flex Skin", "1", ""},
|
||||
{"Body Tree", "0", "`"},
|
||||
|
||||
+7
-172
@@ -309,15 +309,15 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz)
|
||||
|
||||
case mjCOMPTYPE_ROPE:
|
||||
return comperr(error,
|
||||
"The \"rope\" composite type is deprecated. Please use "
|
||||
"\"cable\" instead.",
|
||||
error_sz);
|
||||
"The \"rope\" composite type is deprecated. Please use "
|
||||
"\"cable\" instead.",
|
||||
error_sz);
|
||||
|
||||
case mjCOMPTYPE_LOOP:
|
||||
mju_warning(
|
||||
"The \"loop\" composite type is deprecated. Please use \"cable\" "
|
||||
"instead.");
|
||||
return MakeRope(model, body, error, error_sz);
|
||||
return comperr(error,
|
||||
"The \"loop\" composite type is deprecated. Please use "
|
||||
"\"flexcomp\" instead.",
|
||||
error_sz);
|
||||
|
||||
case mjCOMPTYPE_CABLE:
|
||||
return MakeCable(model, body, error, error_sz);
|
||||
@@ -729,171 +729,6 @@ mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix,
|
||||
}
|
||||
|
||||
|
||||
// make rope
|
||||
bool mjCComposite::MakeRope(mjCModel* model, mjsBody* body, char* error, int error_sz) {
|
||||
// check dim
|
||||
if (dim!=1) {
|
||||
return comperr(error, "Rope must be one-dimensional", error_sz);
|
||||
}
|
||||
|
||||
// check root body name prefix
|
||||
char txt[200];
|
||||
mju::sprintf_arr(txt, "%sB", prefix.c_str());
|
||||
std::string body_name = mjs_getString(body->name);
|
||||
if (std::strncmp(txt, body_name.substr(0, strlen(txt)).c_str(), mju::sizeof_arr(txt))) {
|
||||
mju::strcat_arr(txt, " must be the beginning of root body name");
|
||||
return comperr(error, txt, error_sz);
|
||||
}
|
||||
|
||||
// read origin coordinate from root body
|
||||
mju::strcpy_arr(txt, body_name.substr(strlen(txt)).c_str());
|
||||
int ox = -1;
|
||||
if (sscanf(txt, "%d", &ox)!=1) {
|
||||
return comperr(error, "Root body name must contain X coordinate", error_sz);
|
||||
}
|
||||
if (ox<0 || ox>=count[0]) {
|
||||
return comperr(error, "Root body coordinate out of range", error_sz);
|
||||
}
|
||||
|
||||
// add origin
|
||||
AddRopeBody(model, body, ox, ox);
|
||||
|
||||
// add elements: right
|
||||
mjsBody* pbody = body;
|
||||
for (int ix=ox; ix<count[0]-1; ix++) {
|
||||
pbody = AddRopeBody(model, pbody, ix, ix+1);
|
||||
}
|
||||
|
||||
// add elements: left
|
||||
pbody = body;
|
||||
for (int ix=ox; ix>0; ix--) {
|
||||
pbody = AddRopeBody(model, pbody, ix, ix-1);
|
||||
}
|
||||
|
||||
// close loop
|
||||
if (type==mjCOMPTYPE_LOOP) {
|
||||
char txt2[200];
|
||||
|
||||
// add equality constraint
|
||||
mjsEquality* eq = mjs_addEquality(&model->spec, 0);
|
||||
eq->type = mjEQ_CONNECT;
|
||||
mju::sprintf_arr(txt, "%sB0", prefix.c_str());
|
||||
mju::sprintf_arr(txt2, "%sB%d", prefix.c_str(), count[0]-1);
|
||||
mjs_setString(eq->name1, txt);
|
||||
mjs_setString(eq->name2, txt2);
|
||||
mjuu_setvec(eq->data, -0.5*spacing, 0, 0);
|
||||
mju_copy(eq->solref, solrefsmooth, mjNREF);
|
||||
mju_copy(eq->solimp, solimpsmooth, mjNIMP);
|
||||
|
||||
// remove contact between connected bodies
|
||||
mjsExclude* pair = mjs_addExclude(&model->spec);
|
||||
mjs_setString(pair->bodyname1, std::string(txt).c_str());
|
||||
mjs_setString(pair->bodyname2, std::string(txt2).c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// add child body for cloth
|
||||
mjsBody* mjCComposite::AddRopeBody(mjCModel* model, mjsBody* body, int ix, int ix1) {
|
||||
char txt[100];
|
||||
bool isroot = (ix==ix1);
|
||||
double dx = spacing*(ix1-ix);
|
||||
|
||||
// add child if not root
|
||||
if (!isroot) {
|
||||
body = mjs_addBody(body, 0);
|
||||
mju::sprintf_arr(txt, "%sB%d", prefix.c_str(), ix1);
|
||||
mjs_setString(body->name, txt);
|
||||
|
||||
// loop
|
||||
if (type==mjCOMPTYPE_LOOP) {
|
||||
double alpha = 2*mjPI/count[0];
|
||||
double R = 0.5*spacing*sin(mjPI-alpha)/sin(0.5*alpha);
|
||||
|
||||
if (ix1>ix) {
|
||||
mjuu_setvec(body->pos, R*cos(0.5*alpha), R*sin(0.5*alpha), 0);
|
||||
mjuu_setvec(body->quat, cos(0.5*alpha), 0, 0, sin(0.5*alpha));
|
||||
} else {
|
||||
mjuu_setvec(body->pos, -R*cos(0.5*alpha), R*sin(0.5*alpha), 0);
|
||||
mjuu_setvec(body->quat, cos(-0.5*alpha), 0, 0, sin(-0.5*alpha));
|
||||
}
|
||||
}
|
||||
|
||||
// no loop
|
||||
else {
|
||||
mjuu_setvec(body->pos, dx, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// add geom
|
||||
mjsGeom* geom = mjs_addGeom(body, &def[0].spec);
|
||||
mjs_setDefault(geom->element, mjs_getDefault(body->element));
|
||||
mju::sprintf_arr(txt, "%sG%d", prefix.c_str(), ix1);
|
||||
mjs_setString(geom->name, txt);
|
||||
mjuu_setvec(geom->pos, 0, 0, 0);
|
||||
mjuu_setvec(geom->quat, sqrt(0.5), 0, sqrt(0.5), 0);
|
||||
|
||||
// root: no joints
|
||||
if (isroot) {
|
||||
return body;
|
||||
}
|
||||
|
||||
// add main joint
|
||||
for (int i=0; i<2; i++) {
|
||||
// add joint
|
||||
mjsJoint* jnt = mjs_addJoint(body, &defjoint[mjCOMPKIND_JOINT][0].spec);
|
||||
mjs_setDefault(jnt->element, mjs_getDefault(body->element));
|
||||
mju::sprintf_arr(txt, "%sJ%d_%d", prefix.c_str(), i, ix1);
|
||||
mjs_setString(jnt->name, txt);
|
||||
jnt->type = mjJNT_HINGE;
|
||||
mjuu_setvec(jnt->pos, -0.5*dx, 0, 0);
|
||||
mjuu_setvec(jnt->axis, 0, 0, 0);
|
||||
jnt->axis[i+1] = 1;
|
||||
}
|
||||
|
||||
// add twist joint
|
||||
if (add[mjCOMPKIND_TWIST]) {
|
||||
// add joint
|
||||
mjsJoint* jnt = mjs_addJoint(body, &defjoint[mjCOMPKIND_TWIST][0].spec);
|
||||
mjs_setDefault(jnt->element, mjs_getDefault(body->element));
|
||||
mju::sprintf_arr(txt, "%sJT%d", prefix.c_str(), ix1);
|
||||
mjs_setString(jnt->name, txt);
|
||||
jnt->type = mjJNT_HINGE;
|
||||
mjuu_setvec(jnt->pos, -0.5*dx, 0, 0);
|
||||
mjuu_setvec(jnt->axis, 1, 0, 0);
|
||||
|
||||
// add constraint
|
||||
mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_TWIST].spec);
|
||||
mjs_setDefault(eq->element, &model->Default()->spec);
|
||||
eq->type = mjEQ_JOINT;
|
||||
mjs_setString(eq->name1, mjs_getString(jnt->name));
|
||||
}
|
||||
|
||||
// add stretch joint
|
||||
if (add[mjCOMPKIND_STRETCH]) {
|
||||
// add joint
|
||||
mjsJoint* jnt = mjs_addJoint(body, &defjoint[mjCOMPKIND_STRETCH][0].spec);
|
||||
mjs_setDefault(jnt->element, mjs_getDefault(body->element));
|
||||
mju::sprintf_arr(txt, "%sJS%d", prefix.c_str(), ix1);
|
||||
mjs_setString(jnt->name, txt);
|
||||
jnt->type = mjJNT_SLIDE;
|
||||
mjuu_setvec(jnt->pos, -0.5*dx, 0, 0);
|
||||
mjuu_setvec(jnt->axis, 1, 0, 0);
|
||||
|
||||
// add constraint
|
||||
mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_STRETCH].spec);
|
||||
mjs_setDefault(eq->element, &model->Default()->spec);
|
||||
eq->type = mjEQ_JOINT;
|
||||
mjs_setString(eq->name1, mjs_getString(jnt->name));
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// add shear tendons to 2D
|
||||
void mjCComposite::MakeShear(mjCModel* model) {
|
||||
|
||||
@@ -70,7 +70,6 @@ class mjCComposite {
|
||||
|
||||
bool MakeParticle(mjCModel* model, mjsBody* body, char* error, int error_sz);
|
||||
bool MakeGrid(mjCModel* model, mjsBody* body, char* error, int error_sz);
|
||||
bool MakeRope(mjCModel* model, mjsBody* body, char* error, int error_sz);
|
||||
bool MakeCable(mjCModel* model, mjsBody* body, char* error, int error_sz);
|
||||
void MakeShear(mjCModel* model);
|
||||
|
||||
@@ -124,7 +123,6 @@ class mjCComposite {
|
||||
int dim; // dimensionality
|
||||
|
||||
private:
|
||||
mjsBody* AddRopeBody(mjCModel* model, mjsBody* body, int ix, int ix1);
|
||||
mjsBody* AddCableBody(mjCModel* model, mjsBody* body, int ix, double normal[3], double prev_quat[4]);
|
||||
|
||||
// temporary skin vectors
|
||||
|
||||
@@ -157,6 +157,7 @@ bool mjCFlexcomp::Make(mjsBody* body, char* error, int error_sz) {
|
||||
bool res;
|
||||
switch (type) {
|
||||
case mjFCOMPTYPE_GRID:
|
||||
case mjFCOMPTYPE_CIRCLE:
|
||||
res = MakeGrid(error, error_sz);
|
||||
break;
|
||||
|
||||
@@ -548,15 +549,30 @@ bool mjCFlexcomp::MakeGrid(char* error, int error_sz) {
|
||||
// 1D
|
||||
if (dim == 1) {
|
||||
for (int ix=0; ix < count[0]; ix++) {
|
||||
// add point
|
||||
point.push_back(spacing[0]*(ix - 0.5*(count[0]-1)));
|
||||
point.push_back(0);
|
||||
point.push_back(0);
|
||||
if (type == mjFCOMPTYPE_CIRCLE) {
|
||||
// add point
|
||||
double theta = 2*mjPI/(count[0]-1);
|
||||
double radius = spacing[0]/std::sin(theta/2)/2;
|
||||
point.push_back(radius*std::cos(theta*ix));
|
||||
point.push_back(radius*std::sin(theta*ix));
|
||||
point.push_back(0);
|
||||
|
||||
// add element
|
||||
if (ix < count[0]-1) {
|
||||
element.push_back(ix);
|
||||
element.push_back(ix+1);
|
||||
// add element
|
||||
if (ix < count[0]-1) {
|
||||
element.push_back(ix);
|
||||
element.push_back(ix == count[0]-2 ? 0 : ix+1);
|
||||
}
|
||||
} else {
|
||||
// add point
|
||||
point.push_back(spacing[0]*(ix - 0.5*(count[0]-1)));
|
||||
point.push_back(0);
|
||||
point.push_back(0);
|
||||
|
||||
// add element
|
||||
if (ix < count[0]-1) {
|
||||
element.push_back(ix);
|
||||
element.push_back(ix+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ typedef enum _mjtFcompType {
|
||||
mjFCOMPTYPE_ELLIPSOID,
|
||||
mjFCOMPTYPE_SQUARE,
|
||||
mjFCOMPTYPE_DISC,
|
||||
mjFCOMPTYPE_CIRCLE,
|
||||
mjFCOMPTYPE_MESH,
|
||||
mjFCOMPTYPE_GMSH,
|
||||
mjFCOMPTYPE_DIRECT,
|
||||
|
||||
@@ -794,6 +794,7 @@ const mjMap fcomp_map[mjNFCOMPTYPES] = {
|
||||
{"ellipsoid", mjFCOMPTYPE_ELLIPSOID},
|
||||
{"square", mjFCOMPTYPE_SQUARE},
|
||||
{"disc", mjFCOMPTYPE_DISC},
|
||||
{"circle", mjFCOMPTYPE_CIRCLE},
|
||||
{"mesh", mjFCOMPTYPE_MESH},
|
||||
{"gmsh", mjFCOMPTYPE_GMSH},
|
||||
{"direct", mjFCOMPTYPE_DIRECT}
|
||||
|
||||
Reference in New Issue
Block a user