Add tendon actuator force limits and tendon actuator force sensor.

PiperOrigin-RevId: 745096883
Change-Id: Ib9acb727fbbfc6b0b0323ee6a889053a7a878056
This commit is contained in:
Taylor Howell
2025-04-08 05:15:27 -07:00
committed by Copybara-Service
parent 16e49f2761
commit 96dda6ea75
26 changed files with 464 additions and 74 deletions
+51
View File
@@ -4630,12 +4630,28 @@ length X, as in the clip on the right of `this example model
solver. If this attribute is "auto", and :at:`autolimits` is set in :ref:`compiler <compiler>`, length limits
will be enabled if range is defined.
.. _tendon-spatial-actuatorfrclimited:
:at:`actuatorfrclimited`: :at-val:`[false, true, auto], "auto"`
This attribute specifies whether actuator forces acting on the tendon should be clamped. See :ref:`CForceRange` for
details. This attribute interacts with the :ref:`actuatorfrcrange<tendon-spatial-actuatorfrcrange>` attribute. If
this attribute is "false", actuator force clamping is disabled. If it is "true", actuator force clamping is enabled.
If this attribute is "auto", and :at:`autolimits` is set in :ref:`compiler <compiler>`, actuator force clamping will
be enabled if :at:`actuatorfrcrange` is defined.
.. _tendon-spatial-range:
:at:`range`: :at-val:`real(2), "0 0"`
Range of allowed tendon lengths. Setting this attribute without specifying :at:`limited` is an error, unless
:at:`autolimits` is set in :ref:`compiler <compiler>`.
.. _tendon-spatial-actuatorfrcrange:
:at:`actuatorfrcrange`: :at-val:`real(2), "0 0"`
Range for clamping total actuator forces acting on this tendon. See :ref:`CForceRange` for details. The compiler
expects the lower bound to be nonpositive and the upper bound to be nonnegative. |br| Setting this attribute without
specifying :at:`actuatorfrclimited` is an error if :at:`compiler-autolimits` is "false".
.. _tendon-spatial-solreflimit:
.. _tendon-spatial-solimplimit:
@@ -4820,8 +4836,12 @@ as above.
.. _tendon-fixed-limited:
.. _tendon-fixed-actuatorfrclimited:
.. _tendon-fixed-range:
.. _tendon-fixed-actuatorfrcrange:
.. _tendon-fixed-solreflimit:
.. _tendon-fixed-solimplimit:
@@ -6385,6 +6405,33 @@ joint or when a single actuator acts on multiple joints. See :ref:`CForceRange`
The joint where actuator forces will be sensed. The sensor output is copied from ``mjData.qfrc_actuator``.
.. _sensor-tendonactuatorfrc:
:el-prefix:`sensor/` |-| **tendonactuatorfrc** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This element creates an actuator force sensor, measured at a tendon. The quantity being sensed is the total force
contributed by all actuators to a single tendon. This type of sensor is important when multiple actuators act on a
single tendon. See :ref:`CForceRange` for details.
.. _sensor-tendonactuatorfrc-name:
.. _sensor-tendonactuatorfrc-noise:
.. _sensor-tendonactuatorfrc-cutoff:
.. _sensor-tendonactuatorfrc-user:
:at:`name`, :at:`noise`, :at:`cutoff`, :at:`user`
See :ref:`CSensor`.
.. _sensor-tendonactuatorfrc-tendon:
:at:`tendon`: :at-val:`string, required`
The tendon where actuator forces will be sensed.
.. _sensor-ballquat:
:el-prefix:`sensor/` |-| **ballquat** (*)
@@ -8277,8 +8324,12 @@ if omitted.
.. _default-tendon-limited:
.. _default-tendon-actuatorfrclimited:
.. _default-tendon-range:
.. _default-tendon-actuatorfrcrange:
.. _default-tendon-solreflimit:
.. _default-tendon-solimplimit:
+20 -7
View File
@@ -621,13 +621,15 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`name<tendon-spatial-name>` | :ref:`class<tendon-spatial-class>` | :ref:`group<tendon-spatial-group>` | :ref:`limited<tendon-spatial-limited>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`range<tendon-spatial-range>` | :ref:`solreflimit<tendon-spatial-solreflimit>` | :ref:`solimplimit<tendon-spatial-solimplimit>` | :ref:`solreffriction<tendon-spatial-solreffriction>` | |
| | | | :ref:`actuatorfrclimited<tendon-spatial-actuatorfrclimited>` | :ref:`range<tendon-spatial-range>` | :ref:`actuatorfrcrange<tendon-spatial-actuatorfrcrange>` | :ref:`solreflimit<tendon-spatial-solreflimit>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`solimpfriction<tendon-spatial-solimpfriction>` | :ref:`frictionloss<tendon-spatial-frictionloss>` | :ref:`springlength<tendon-spatial-springlength>` | :ref:`width<tendon-spatial-width>` | |
| | | | :ref:`solimplimit<tendon-spatial-solimplimit>` | :ref:`solreffriction<tendon-spatial-solreffriction>` | :ref:`solimpfriction<tendon-spatial-solimpfriction>` | :ref:`frictionloss<tendon-spatial-frictionloss>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`material<tendon-spatial-material>` | :ref:`margin<tendon-spatial-margin>` | :ref:`stiffness<tendon-spatial-stiffness>` | :ref:`damping<tendon-spatial-damping>` | |
| | | | :ref:`springlength<tendon-spatial-springlength>` | :ref:`width<tendon-spatial-width>` | :ref:`material<tendon-spatial-material>` | :ref:`margin<tendon-spatial-margin>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`armature<tendon-spatial-armature>` | :ref:`rgba<tendon-spatial-rgba>` | :ref:`user<tendon-spatial-user>` | | |
| | | | :ref:`stiffness<tendon-spatial-stiffness>` | :ref:`damping<tendon-spatial-damping>` | :ref:`armature<tendon-spatial-armature>` | :ref:`rgba<tendon-spatial-rgba>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`user<tendon-spatial-user>` | | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_2| spatial |br| |_2| |L| | | .. table:: |
@@ -657,11 +659,13 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`name<tendon-fixed-name>` | :ref:`class<tendon-fixed-class>` | :ref:`group<tendon-fixed-group>` | :ref:`limited<tendon-fixed-limited>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`range<tendon-fixed-range>` | :ref:`solreflimit<tendon-fixed-solreflimit>` | :ref:`solimplimit<tendon-fixed-solimplimit>` | :ref:`solreffriction<tendon-fixed-solreffriction>` | |
| | | | :ref:`actuatorfrclimited<tendon-fixed-actuatorfrclimited>` | :ref:`range<tendon-fixed-range>` | :ref:`actuatorfrcrange<tendon-fixed-actuatorfrcrange>` | :ref:`solreflimit<tendon-fixed-solreflimit>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`solimpfriction<tendon-fixed-solimpfriction>` | :ref:`frictionloss<tendon-fixed-frictionloss>` | :ref:`springlength<tendon-fixed-springlength>` | :ref:`margin<tendon-fixed-margin>` | |
| | | | :ref:`solimplimit<tendon-fixed-solimplimit>` | :ref:`solreffriction<tendon-fixed-solreffriction>` | :ref:`solimpfriction<tendon-fixed-solimpfriction>` | :ref:`frictionloss<tendon-fixed-frictionloss>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`stiffness<tendon-fixed-stiffness>` | :ref:`damping<tendon-fixed-damping>` | :ref:`armature<tendon-fixed-armature>` | :ref:`user<tendon-fixed-user>` | |
| | | | :ref:`springlength<tendon-fixed-springlength>` | :ref:`margin<tendon-fixed-margin>` | :ref:`stiffness<tendon-fixed-stiffness>` | :ref:`damping<tendon-fixed-damping>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`armature<tendon-fixed-armature>` | :ref:`user<tendon-fixed-user>` | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_2| fixed |br| |_2| |L| | | .. table:: |
@@ -1004,6 +1008,15 @@
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| sensor |br| |_| |L| | | .. table:: |
| :ref:`tendonactuatorfrc | \* | :class: mjcf-attributes |
| <sensor-tendonactuatorfrc>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`name<sensor-tendonactuatorfrc-name>` | :ref:`tendon<sensor-tendonactuatorfrc-tendon>` | :ref:`cutoff<sensor-tendonactuatorfrc-cutoff>` | :ref:`noise<sensor-tendonactuatorfrc-noise>` | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
| | | | :ref:`user<sensor-tendonactuatorfrc-user>` | | | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |_| sensor |br| |_| |L| | | .. table:: |
| :ref:`ballquat | \* | :class: mjcf-attributes |
| <sensor-ballquat>` | | |
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
+2
View File
@@ -20,6 +20,8 @@ General
bodies when saving to XML.
- Added :ref:`orientation<body-composite-quat>` attribute to :ref:`composite<body-composite>`. Moreover, allow the
composite to be the direct child of a frame.
- Added :ref:`tendon actuator force limits<tendon-spatial-actuatorfrclimited>` and
:ref:`tendon actuator force sensor<sensor-tendonactuatorfrc>`.
Bug fixes
^^^^^^^^^
+7
View File
@@ -649,6 +649,7 @@ typedef enum mjtSensor_ { // type of sensor
mjSENS_ACTUATORVEL, // scalar actuator velocity
mjSENS_ACTUATORFRC, // scalar actuator force
mjSENS_JOINTACTFRC, // scalar actuator force, measured at the joint
mjSENS_TENDONACTFRC, // scalar actuator force, measured at the tendon
// sensors related to ball joints
mjSENS_BALLQUAT, // 4D ball joint quaternion
@@ -1330,12 +1331,14 @@ struct mjModel_ {
int* tendon_matid; // material id for rendering (ntendon x 1)
int* tendon_group; // group for visibility (ntendon x 1)
mjtByte* tendon_limited; // does tendon have length limits (ntendon x 1)
mjtByte* tendon_actfrclimited; // does tendon have actuator force limits (ntendon x 1)
mjtNum* tendon_width; // width for rendering (ntendon x 1)
mjtNum* tendon_solref_lim; // constraint solver reference: limit (ntendon x mjNREF)
mjtNum* tendon_solimp_lim; // constraint solver impedance: limit (ntendon x mjNIMP)
mjtNum* tendon_solref_fri; // constraint solver reference: friction (ntendon x mjNREF)
mjtNum* tendon_solimp_fri; // constraint solver impedance: friction (ntendon x mjNIMP)
mjtNum* tendon_range; // tendon length limits (ntendon x 2)
mjtNum* tendon_actfrcrange; // range of total actuator force (ntendon x 2)
mjtNum* tendon_margin; // min distance for limit detection (ntendon x 1)
mjtNum* tendon_stiffness; // stiffness coefficient (ntendon x 1)
mjtNum* tendon_damping; // damping coefficient (ntendon x 1)
@@ -2186,7 +2189,9 @@ typedef struct mjsTendon_ { // tendon specification
// length range
int limited; // does tendon have limits (mjtLimited)
int actfrclimited; // does tendon have actuator force limits
double range[2]; // length limits
double actfrcrange[2]; // actuator force limits
double margin; // margin value for tendon limit detection
mjtNum solref_limit[mjNREF]; // solver reference: tendon limits
mjtNum solimp_limit[mjNIMP]; // solver impedance: tendon limits
@@ -3086,8 +3091,10 @@ struct mjvSceneState_ {
int* tendon_matid;
int* tendon_group;
mjtByte* tendon_limited;
mjtByte* tendon_actfrclimited;
mjtNum* tendon_width;
mjtNum* tendon_range;
mjtNum* tendon_actfrcrange;
mjtNum* tendon_stiffness;
mjtNum* tendon_damping;
mjtNum* tendon_frictionloss;
+4 -1
View File
@@ -724,7 +724,10 @@ Force clamping at joint input with :ref:`joint/actuatorfrcrange<body-joint-actua
:ref:`jointactuatorfrc<sensor-jointactuatorfrc>` sensor to report the total actuator force acting on a joint.
The standard :ref:`actuatorfrc<sensor-actuatorfrc>` sensor will continue to report the pre-clamped actuator force.
The three clamping options above are non-exclusive and can be combined as required.
Force clamping at tendon input with :ref:`tendon/actuatorfrcrange<tendon-spatial-actuatorfrcrange>`:
This tendon attribute clamps input forces from all actuators acting on the tendon.
The clamping options above are non-exclusive and can be combined as required.
.. _CLengthRange:
+3
View File
@@ -317,6 +317,7 @@ typedef enum mjtSensor_ { // type of sensor
mjSENS_ACTUATORVEL, // scalar actuator velocity
mjSENS_ACTUATORFRC, // scalar actuator force
mjSENS_JOINTACTFRC, // scalar actuator force, measured at the joint
mjSENS_TENDONACTFRC, // scalar actuator force, measured at the tendon
// sensors related to ball joints
mjSENS_BALLQUAT, // 4D ball joint quaternion
@@ -1031,12 +1032,14 @@ struct mjModel_ {
int* tendon_matid; // material id for rendering (ntendon x 1)
int* tendon_group; // group for visibility (ntendon x 1)
mjtByte* tendon_limited; // does tendon have length limits (ntendon x 1)
mjtByte* tendon_actfrclimited; // does tendon have actuator force limits (ntendon x 1)
mjtNum* tendon_width; // width for rendering (ntendon x 1)
mjtNum* tendon_solref_lim; // constraint solver reference: limit (ntendon x mjNREF)
mjtNum* tendon_solimp_lim; // constraint solver impedance: limit (ntendon x mjNIMP)
mjtNum* tendon_solref_fri; // constraint solver reference: friction (ntendon x mjNREF)
mjtNum* tendon_solimp_fri; // constraint solver impedance: friction (ntendon x mjNIMP)
mjtNum* tendon_range; // tendon length limits (ntendon x 2)
mjtNum* tendon_actfrcrange; // range of total actuator force (ntendon x 2)
mjtNum* tendon_margin; // min distance for limit detection (ntendon x 1)
mjtNum* tendon_stiffness; // stiffness coefficient (ntendon x 1)
mjtNum* tendon_damping; // damping coefficient (ntendon x 1)
+2
View File
@@ -628,7 +628,9 @@ typedef struct mjsTendon_ { // tendon specification
// length range
int limited; // does tendon have limits (mjtLimited)
int actfrclimited; // does tendon have actuator force limits
double range[2]; // length limits
double actfrcrange[2]; // actuator force limits
double margin; // margin value for tendon limit detection
mjtNum solref_limit[mjNREF]; // solver reference: tendon limits
mjtNum solimp_limit[mjNIMP]; // solver impedance: tendon limits
+2
View File
@@ -593,8 +593,10 @@ struct mjvSceneState_ {
int* tendon_matid;
int* tendon_group;
mjtByte* tendon_limited;
mjtByte* tendon_actfrclimited;
mjtNum* tendon_width;
mjtNum* tendon_range;
mjtNum* tendon_actfrcrange;
mjtNum* tendon_stiffness;
mjtNum* tendon_damping;
mjtNum* tendon_frictionloss;
+2
View File
@@ -475,12 +475,14 @@
XMJV( int, tendon_matid, ntendon, 1 ) \
XMJV( int, tendon_group, ntendon, 1 ) \
XMJV( mjtByte, tendon_limited, ntendon, 1 ) \
XMJV( mjtByte, tendon_actfrclimited, ntendon, 1 ) \
XMJV( mjtNum, tendon_width, ntendon, 1 ) \
X ( mjtNum, tendon_solref_lim, ntendon, mjNREF ) \
X ( mjtNum, tendon_solimp_lim, ntendon, mjNIMP ) \
X ( mjtNum, tendon_solref_fri, ntendon, mjNREF ) \
X ( mjtNum, tendon_solimp_fri, ntendon, mjNIMP ) \
XMJV( mjtNum, tendon_range, ntendon, 2 ) \
XMJV( mjtNum, tendon_actfrcrange, ntendon, 2 ) \
X ( mjtNum, tendon_margin, ntendon, 1 ) \
XMJV( mjtNum, tendon_stiffness, ntendon, 1 ) \
XMJV( mjtNum, tendon_damping, ntendon, 1 ) \
+1 -1
View File
@@ -349,7 +349,7 @@ class SupportTest(parameterized.TestCase):
self.assertEqual(
str(e.exception),
'mjSpec signature does not match mjx.Model signature:'
' 4300287342280373816 != 9887180086914550999',
' 17856615236057737915 != 12517827274439268436',
)
_CONTACTS = """
+4
View File
@@ -763,11 +763,13 @@ class Model(PyTreeNode):
tendon_adr: address of first object in tendon's path (ntendon,)
tendon_num: number of objects in tendon's path (ntendon,)
tendon_limited: does tendon have length limits (ntendon,)
tendon_actfrclimited: tendon has actuator force limits (ntendon,)
tendon_solref_lim: constraint solver reference: limit (ntendon, mjNREF)
tendon_solimp_lim: constraint solver impedance: limit (ntendon, mjNIMP)
tendon_solref_fri: constraint solver reference: friction (ntendon, mjNREF)
tendon_solimp_fri: constraint solver impedance: friction (ntendon, mjNIMP)
tendon_range: tendon length limits (ntendon, 2)
tendon_actfrcrange: tendon actuator force limits (ntendon, 2)
tendon_margin: min distance for limit detection (ntendon,)
tendon_stiffness: stiffness coefficient (ntendon,)
tendon_damping: damping coefficient (ntendon,)
@@ -1106,11 +1108,13 @@ class Model(PyTreeNode):
tendon_adr: np.ndarray
tendon_num: np.ndarray
tendon_limited: np.ndarray
tendon_actfrclimited: np.ndarray
tendon_solref_lim: jax.Array
tendon_solimp_lim: jax.Array
tendon_solref_fri: jax.Array
tendon_solimp_fri: jax.Array
tendon_range: jax.Array
tendon_actfrcrange: jax.Array
tendon_margin: jax.Array
tendon_stiffness: jax.Array
tendon_damping: jax.Array
+29 -28
View File
@@ -340,34 +340,35 @@ ENUMS: Mapping[str, EnumDecl] = dict([
('mjSENS_ACTUATORVEL', 14),
('mjSENS_ACTUATORFRC', 15),
('mjSENS_JOINTACTFRC', 16),
('mjSENS_BALLQUAT', 17),
('mjSENS_BALLANGVEL', 18),
('mjSENS_JOINTLIMITPOS', 19),
('mjSENS_JOINTLIMITVEL', 20),
('mjSENS_JOINTLIMITFRC', 21),
('mjSENS_TENDONLIMITPOS', 22),
('mjSENS_TENDONLIMITVEL', 23),
('mjSENS_TENDONLIMITFRC', 24),
('mjSENS_FRAMEPOS', 25),
('mjSENS_FRAMEQUAT', 26),
('mjSENS_FRAMEXAXIS', 27),
('mjSENS_FRAMEYAXIS', 28),
('mjSENS_FRAMEZAXIS', 29),
('mjSENS_FRAMELINVEL', 30),
('mjSENS_FRAMEANGVEL', 31),
('mjSENS_FRAMELINACC', 32),
('mjSENS_FRAMEANGACC', 33),
('mjSENS_SUBTREECOM', 34),
('mjSENS_SUBTREELINVEL', 35),
('mjSENS_SUBTREEANGMOM', 36),
('mjSENS_GEOMDIST', 37),
('mjSENS_GEOMNORMAL', 38),
('mjSENS_GEOMFROMTO', 39),
('mjSENS_E_POTENTIAL', 40),
('mjSENS_E_KINETIC', 41),
('mjSENS_CLOCK', 42),
('mjSENS_PLUGIN', 43),
('mjSENS_USER', 44),
('mjSENS_TENDONACTFRC', 17),
('mjSENS_BALLQUAT', 18),
('mjSENS_BALLANGVEL', 19),
('mjSENS_JOINTLIMITPOS', 20),
('mjSENS_JOINTLIMITVEL', 21),
('mjSENS_JOINTLIMITFRC', 22),
('mjSENS_TENDONLIMITPOS', 23),
('mjSENS_TENDONLIMITVEL', 24),
('mjSENS_TENDONLIMITFRC', 25),
('mjSENS_FRAMEPOS', 26),
('mjSENS_FRAMEQUAT', 27),
('mjSENS_FRAMEXAXIS', 28),
('mjSENS_FRAMEYAXIS', 29),
('mjSENS_FRAMEZAXIS', 30),
('mjSENS_FRAMELINVEL', 31),
('mjSENS_FRAMEANGVEL', 32),
('mjSENS_FRAMELINACC', 33),
('mjSENS_FRAMEANGACC', 34),
('mjSENS_SUBTREECOM', 35),
('mjSENS_SUBTREELINVEL', 36),
('mjSENS_SUBTREEANGMOM', 37),
('mjSENS_GEOMDIST', 38),
('mjSENS_GEOMNORMAL', 39),
('mjSENS_GEOMFROMTO', 40),
('mjSENS_E_POTENTIAL', 41),
('mjSENS_E_KINETIC', 42),
('mjSENS_CLOCK', 43),
('mjSENS_PLUGIN', 44),
('mjSENS_USER', 45),
]),
)),
('mjtStage',
+43
View File
@@ -3615,6 +3615,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([
doc='does tendon have length limits',
array_extent=('ntendon',),
),
StructFieldDecl(
name='tendon_actfrclimited',
type=PointerType(
inner_type=ValueType(name='mjtByte'),
),
doc='does tendon have actuator force limits',
array_extent=('ntendon',),
),
StructFieldDecl(
name='tendon_width',
type=PointerType(
@@ -3663,6 +3671,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([
doc='tendon length limits',
array_extent=('ntendon', 2),
),
StructFieldDecl(
name='tendon_actfrcrange',
type=PointerType(
inner_type=ValueType(name='mjtNum'),
),
doc='range of total actuator force',
array_extent=('ntendon', 2),
),
StructFieldDecl(
name='tendon_margin',
type=PointerType(
@@ -8135,6 +8151,13 @@ STRUCTS: Mapping[str, StructDecl] = dict([
),
doc='',
),
StructFieldDecl(
name='tendon_actfrclimited',
type=PointerType(
inner_type=ValueType(name='mjtByte'),
),
doc='',
),
StructFieldDecl(
name='tendon_width',
type=PointerType(
@@ -8149,6 +8172,13 @@ STRUCTS: Mapping[str, StructDecl] = dict([
),
doc='',
),
StructFieldDecl(
name='tendon_actfrcrange',
type=PointerType(
inner_type=ValueType(name='mjtNum'),
),
doc='',
),
StructFieldDecl(
name='tendon_stiffness',
type=PointerType(
@@ -11342,6 +11372,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'),
doc='does tendon have limits (mjtLimited)',
),
StructFieldDecl(
name='actfrclimited',
type=ValueType(name='int'),
doc='does tendon have actuator force limits',
),
StructFieldDecl(
name='range',
type=ArrayType(
@@ -11350,6 +11385,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([
),
doc='length limits',
),
StructFieldDecl(
name='actfrcrange',
type=ArrayType(
inner_type=ValueType(name='double'),
extents=(2,),
),
doc='actuator force limits',
),
StructFieldDecl(
name='margin',
type=ValueType(name='double'),
+41 -1
View File
@@ -276,7 +276,7 @@ static void clampVec(mjtNum* vec, const mjtNum* range, const mjtByte* limited, i
// (qpos, qvel, ctrl, act) => (qfrc_actuator, actuator_force, act_dot)
void mj_fwdActuation(const mjModel* m, mjData* d) {
TM_START;
int nv = m->nv, nu = m->nu;
int nv = m->nv, nu = m->nu, ntendon = m->ntendon;
mjtNum gain, bias, tau;
mjtNum *prm, *force = d->actuator_force;
@@ -289,6 +289,9 @@ void mj_fwdActuation(const mjModel* m, mjData* d) {
return;
}
// any tendon transmission targets with force limits
int tendon_frclimited = 0;
// local, clamped copy of ctrl
mj_markStack(d);
mjtNum *ctrl = mjSTACKALLOC(d, nu, mjtNum);
@@ -384,6 +387,11 @@ void mj_fwdActuation(const mjModel* m, mjData* d) {
continue;
}
// check for tendon transmission with force limits
if (ntendon && !tendon_frclimited && m->actuator_trntype[i] == mjTRN_TENDON) {
tendon_frclimited = m->tendon_actfrclimited[m->actuator_trnid[2*i]];
}
// extract gain info
prm = m->actuator_gainprm + mjNGAIN*i;
@@ -479,6 +487,38 @@ void mj_fwdActuation(const mjModel* m, mjData* d) {
}
}
// clamp tendon total actuator force
if (tendon_frclimited) {
// compute total force for each tendon
mjtNum* tendon_total_force = mjSTACKALLOC(d, ntendon, mjtNum);
mju_zero(tendon_total_force, ntendon);
for (int i=0; i < nu; i++) {
if (m->actuator_trntype[i] == mjTRN_TENDON) {
int tendon_id = m->actuator_trnid[2*i];
if (m->tendon_actfrclimited[tendon_id]) {
tendon_total_force[tendon_id] += force[i];
}
}
}
// scale tendon actuator forces if limited and outside range
for (int i=0; i < nu; i++) {
if (m->actuator_trntype[i] != mjTRN_TENDON) {
continue;
}
int tendon_id = m->actuator_trnid[2*i];
mjtNum tendon_force = tendon_total_force[tendon_id];
if (m->tendon_actfrclimited[tendon_id] && tendon_force) {
const mjtNum* range = m->tendon_actfrcrange + 2 * tendon_id;
if (tendon_force < range[0]) {
force[i] *= range[0] / tendon_force;
} else if (tendon_force > range[1]) {
force[i] *= range[1] / tendon_force;
}
}
}
}
// clamp actuator_force
clampVec(force, m->actuator_forcerange, m->actuator_forcelimited, nu, NULL);
+1
View File
@@ -2079,6 +2079,7 @@ static int sensorSize(mjtSensor sensor_type, int sensor_dim) {
case mjSENS_ACTUATORVEL:
case mjSENS_ACTUATORFRC:
case mjSENS_JOINTACTFRC:
case mjSENS_TENDONACTFRC:
case mjSENS_JOINTLIMITPOS:
case mjSENS_JOINTLIMITVEL:
case mjSENS_JOINTLIMITFRC:
+12 -2
View File
@@ -698,8 +698,8 @@ void mj_sensorVel(const mjModel* m, mjData* d) {
// acceleration/force-dependent sensors
void mj_sensorAcc(const mjModel* m, mjData* d) {
int rootid, bodyid, objtype, objid, adr, nusersensor = 0;
int ne = d->ne, nf = d->nf, nefc = d->nefc;
mjtNum tmp[6], conforce[6], conray[3];
int ne = d->ne, nf = d->nf, nefc = d->nefc, nu = m->nu;
mjtNum tmp[6], conforce[6], conray[3], frc;
mjContact* con;
// disabled sensors: return
@@ -825,6 +825,16 @@ void mj_sensorAcc(const mjModel* m, mjData* d) {
d->sensordata[adr] = d->qfrc_actuator[m->jnt_dofadr[objid]];
break;
case mjSENS_TENDONACTFRC: // tendonactfrc
frc = 0.0;
for (int j=0; j < nu; j++) {
if (m->actuator_trntype[j] == mjTRN_TENDON && m->actuator_trnid[2*j] == objid) {
frc += d->actuator_force[j];
}
}
d->sensordata[adr] = frc;
break;
case mjSENS_JOINTLIMITFRC: // jointlimitfrc
d->sensordata[adr] = 0;
for (int j=ne+nf; j < nefc; j++) {
+4
View File
@@ -3351,6 +3351,7 @@ void mjCModel::CopyObjects(mjModel* m) {
m->tendon_matid[i] = pte->matid;
m->tendon_group[i] = pte->group;
m->tendon_limited[i] = (mjtByte)pte->is_limited();
m->tendon_actfrclimited[i] = (mjtByte)pte->is_actfrclimited();
m->tendon_width[i] = (mjtNum)pte->width;
mjuu_copyvec(m->tendon_solref_lim+mjNREF*i, pte->solref_limit, mjNREF);
mjuu_copyvec(m->tendon_solimp_lim+mjNIMP*i, pte->solimp_limit, mjNIMP);
@@ -3358,6 +3359,8 @@ void mjCModel::CopyObjects(mjModel* m) {
mjuu_copyvec(m->tendon_solimp_fri+mjNIMP*i, pte->solimp_friction, mjNIMP);
m->tendon_range[2*i] = (mjtNum)pte->range[0];
m->tendon_range[2*i+1] = (mjtNum)pte->range[1];
m->tendon_actfrcrange[2*i] = (mjtNum)pte->actfrcrange[0];
m->tendon_actfrcrange[2*i+1] = (mjtNum)pte->actfrcrange[1];
m->tendon_margin[i] = (mjtNum)pte->margin;
m->tendon_stiffness[i] = (mjtNum)pte->stiffness;
m->tendon_damping[i] = (mjtNum)pte->damping;
@@ -5005,6 +5008,7 @@ bool mjCModel::CopyBack(const mjModel* m) {
// tendons
for (int i=0; i < ntendon; i++) {
mjuu_copyvec(tendons_[i]->range, m->tendon_range+2*i, 2);
mjuu_copyvec(tendons_[i]->actfrcrange, m->tendon_actfrcrange+2*i, 2);
mjuu_copyvec(tendons_[i]->solref_limit, m->tendon_solref_lim+mjNREF*i, mjNREF);
mjuu_copyvec(tendons_[i]->solimp_limit, m->tendon_solimp_lim+mjNIMP*i, mjNIMP);
mjuu_copyvec(tendons_[i]->solref_friction, m->tendon_solref_fri+mjNREF*i, mjNREF);
+30 -1
View File
@@ -5388,7 +5388,9 @@ mjCTendon& mjCTendon::operator=(const mjCTendon& other) {
bool mjCTendon::is_limited() const {
return islimited(limited, range);
}
bool mjCTendon::is_actfrclimited() const {
return islimited(actfrclimited, actfrcrange);
}
void mjCTendon::PointToLocal() {
spec.element = static_cast<mjsElement*>(this);
@@ -5686,6 +5688,21 @@ void mjCTendon::Compile(void) {
throw mjCError(this, "invalid limits in tendon");
}
// if limited is auto, set to 1 if range is specified, otherwise unlimited
if (actfrclimited == mjLIMITED_AUTO) {
bool hasactfrcrange = !(actfrcrange[0] == 0 && actfrcrange[1] == 0);
checklimited(this, compiler->autolimits, "tendon", "", actfrclimited,
hasactfrcrange);
}
// check actfrclimits
if (actfrcrange[0] >= actfrcrange[1] && is_actfrclimited()) {
throw mjCError(this, "invalid actuatorfrcrange in tendon");
}
if ((actfrcrange[0] > 0 || actfrcrange[1] < 0) && is_actfrclimited()) {
throw mjCError(this, "invalid actuatorfrcrange in tendon");
}
// check springlength
if (springlength[0] > springlength[1]) {
throw mjCError(this, "invalid springlength in tendon");
@@ -6479,6 +6496,18 @@ void mjCSensor::Compile(void) {
}
break;
case mjSENS_TENDONACTFRC:
// must be attached to tendon
if (objtype != mjOBJ_TENDON) {
throw mjCError(this, "sensor must be attached to tendon");
}
// set
dim = 1;
datatype = mjDATATYPE_REAL;
needstage = mjSTAGE_ACC;
break;
case mjSENS_TENDONPOS:
case mjSENS_TENDONVEL:
// must be attached to tendon
+1
View File
@@ -1523,6 +1523,7 @@ class mjCTendon : public mjCTendon_, private mjsTendon {
void SetModel(mjCModel* _model);
bool is_limited() const;
bool is_actfrclimited() const;
private:
void Compile(void); // compiler
+11 -4
View File
@@ -363,8 +363,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
{"tendon", "*", "0"},
{"<"},
{"spatial", "*", "19", "name", "class", "group", "limited", "range",
"solreflimit", "solimplimit", "solreffriction", "solimpfriction",
{"spatial", "*", "21", "name", "class", "group", "limited", "actuatorfrclimited", "range",
"actuatorfrcrange", "solreflimit", "solimplimit", "solreffriction", "solimpfriction",
"frictionloss", "springlength", "width", "material",
"margin", "stiffness", "damping", "armature", "rgba", "user"},
{"<"},
@@ -372,8 +372,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
{"geom", "*", "2", "geom", "sidesite"},
{"pulley", "*", "1", "divisor"},
{">"},
{"fixed", "*", "16", "name", "class", "group", "limited", "range",
"solreflimit", "solimplimit", "solreffriction", "solimpfriction",
{"fixed", "*", "18", "name", "class", "group", "limited", "actuatorfrclimited", "range",
"actuatorfrcrange","solreflimit", "solimplimit", "solreffriction", "solimpfriction",
"frictionloss", "springlength", "margin", "stiffness", "damping", "armature", "user"},
{"<"},
{"joint", "*", "2", "joint", "coef"},
@@ -455,6 +455,7 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
{"actuatorvel", "*", "5", "name", "actuator", "cutoff", "noise", "user"},
{"actuatorfrc", "*", "5", "name", "actuator", "cutoff", "noise", "user"},
{"jointactuatorfrc", "*", "5", "name", "joint", "cutoff", "noise", "user"},
{"tendonactuatorfrc", "*", "5", "name", "tendon", "cutoff", "noise", "user"},
{"ballquat", "*", "5", "name", "joint", "cutoff", "noise", "user"},
{"ballangvel", "*", "5", "name", "joint", "cutoff", "noise", "user"},
{"jointlimitpos", "*", "5", "name", "joint", "cutoff", "noise", "user"},
@@ -2052,12 +2053,14 @@ void mjXReader::OneTendon(XMLElement* elem, mjsTendon* tendon) {
mjs_setString(tendon->material, material.c_str());
}
MapValue(elem, "limited", &tendon->limited, TFAuto_map, 3);
MapValue(elem, "actuatorfrclimited", &tendon->actfrclimited, TFAuto_map, 3);
ReadAttr(elem, "width", 1, &tendon->width, text);
ReadAttr(elem, "solreflimit", mjNREF, tendon->solref_limit, text, false, false);
ReadAttr(elem, "solimplimit", mjNIMP, tendon->solimp_limit, text, false, false);
ReadAttr(elem, "solreffriction", mjNREF, tendon->solref_friction, text, false, false);
ReadAttr(elem, "solimpfriction", mjNIMP, tendon->solimp_friction, text, false, false);
ReadAttr(elem, "range", 2, tendon->range, text);
ReadAttr(elem, "actuatorfrcrange", 2, tendon->actfrcrange, text);
ReadAttr(elem, "margin", 1, &tendon->margin, text);
ReadAttr(elem, "stiffness", 1, &tendon->stiffness, text);
ReadAttr(elem, "damping", 1, &tendon->damping, text);
@@ -3973,6 +3976,10 @@ void mjXReader::Sensor(XMLElement* section) {
sensor->type = mjSENS_JOINTACTFRC;
sensor->objtype = mjOBJ_JOINT;
ReadAttrTxt(elem, "joint", objname, true);
} else if (type=="tendonactuatorfrc") {
sensor->type = mjSENS_TENDONACTFRC;
sensor->objtype = mjOBJ_TENDON;
ReadAttrTxt(elem, "tendon", objname, true);
}
// sensors related to ball joints
+1 -1
View File
@@ -102,7 +102,7 @@ class mjXReader : public mjXBase {
};
// MJCF schema
#define nMJCF 237
#define nMJCF 238
extern const char* MJCF[nMJCF][mjXATTRNUM];
#endif // MUJOCO_SRC_XML_XML_NATIVE_READER_H_
+6
View File
@@ -725,7 +725,9 @@ void mjXWriter::OneTendon(XMLElement* elem, const mjCTendon* tendon, mjCDef* def
WriteAttr(elem, "solimpfriction", mjNIMP, tendon->solimp_friction, def->Tendon().solimp_friction,
true);
WriteAttrKey(elem, "limited", TFAuto_map, 3, tendon->limited, def->Tendon().limited);
WriteAttrKey(elem, "actuatorfrclimited", TFAuto_map, 3, tendon->actfrclimited, def->Tendon().actfrclimited);
WriteAttr(elem, "range", 2, tendon->range, def->Tendon().range);
WriteAttr(elem, "actuatorfrcrange", 2, tendon->actfrcrange, def->Tendon().actfrcrange);
WriteAttr(elem, "margin", 1, &tendon->margin, &def->Tendon().margin);
WriteAttr(elem, "stiffness", 1, &tendon->stiffness, &def->Tendon().stiffness);
WriteAttr(elem, "damping", 1, &tendon->damping, &def->Tendon().damping);
@@ -2033,6 +2035,10 @@ void mjXWriter::Sensor(XMLElement* root) {
elem = InsertEnd(section, "jointactuatorfrc");
WriteAttrTxt(elem, "joint", sensor->get_objname());
break;
case mjSENS_TENDONACTFRC:
elem = InsertEnd(section, "tendonactuatorfrc");
WriteAttrTxt(elem, "tendon", sensor->get_objname());
break;
// sensors related to ball joints
case mjSENS_BALLQUAT:
+54
View File
@@ -46,6 +46,8 @@ static const char* const kDampedActuatorsPath =
"engine/testdata/derivative/damped_actuators.xml";
static const char* const kJointForceClamp =
"engine/testdata/actuation/joint_force_clamp.xml";
static const char* const kTendonForceClamp =
"engine/testdata/actuation/tendon_force_clamp.xml";
using ::testing::Pointwise;
using ::testing::DoubleNear;
@@ -1393,5 +1395,57 @@ TEST_F(ActuatorTest, DisableActuatorOutOfRange) {
mj_deleteModel(model);
}
TEST_F(ActuatorTest, TendonActuatorForceRange) {
const std::string xml_path = GetTestDataFilePath(kTendonForceClamp);
mjModel* model = mj_loadXML(xml_path.c_str(), nullptr, nullptr, 0);
mjData* data = mj_makeData(model);
EXPECT_EQ(model->tendon_actfrclimited[0], 0);
EXPECT_EQ(model->tendon_actfrcrange[0], 0);
EXPECT_EQ(model->tendon_actfrcrange[1], 0);
EXPECT_EQ(model->tendon_actfrclimited[1], 1);
EXPECT_EQ(model->tendon_actfrcrange[2], -1);
EXPECT_EQ(model->tendon_actfrcrange[3], 1);
EXPECT_EQ(model->tendon_actfrclimited[2], 1);
EXPECT_EQ(model->tendon_actfrcrange[4], -10);
EXPECT_EQ(model->tendon_actfrcrange[5], 10);
EXPECT_EQ(model->tendon_actfrclimited[3], 1);
EXPECT_EQ(model->tendon_actfrcrange[6], 0);
EXPECT_EQ(model->tendon_actfrcrange[7], 1);
data->ctrl[0] = 1;
data->ctrl[1] = 1;
data->ctrl[2] = 1;
data->ctrl[3] = -1;
data->ctrl[4] = 1;
data->ctrl[5] = -20;
data->ctrl[6] = 5;
data->ctrl[7] = -5;
mj_forward(model, data);
EXPECT_NEAR(data->actuator_force[0], 1, 1e-6);
EXPECT_NEAR(data->actuator_force[1], 1, 1e-6);
EXPECT_NEAR(data->actuator_force[2], 1, 1e-6);
EXPECT_NEAR(data->actuator_force[3], -1, 1e-6);
EXPECT_NEAR(data->actuator_force[4], 1, 1e-6);
EXPECT_NEAR(data->actuator_force[5], -10, 1e-6);
EXPECT_NEAR(data->actuator_force[6], 5, 1e-6);
EXPECT_NEAR(data->actuator_force[7], -5, 1e-6);
EXPECT_EQ(data->sensordata[0], 3);
EXPECT_EQ(data->sensordata[1], 0);
EXPECT_EQ(data->sensordata[2], -10);
EXPECT_EQ(data->sensordata[3], 0);
mj_deleteData(data);
mj_deleteModel(model);
}
} // namespace
} // namespace mujoco
+55
View File
@@ -0,0 +1,55 @@
<mujoco model="fixed_site">
<worldbody>
<body>
<joint name="joint0" type="hinge" axis="0 1 0"/>
<geom type="capsule" size="0.05 0.5" fromto="0 0 0 0.5 0 0"/>
<site name="site0" pos="0.25 0 0.1" size="0.025"/>
<body pos="0.5 0 0">
<joint name="joint1" type="hinge" axis="0 1 0"/>
<geom type="capsule" size="0.05 0.5" fromto="0 0 0 0.5 0 0"/>
<site name="site1" pos="0.25 0 0.1" size="0.025"/>
<body pos="0.5 0 0">
<joint name="joint2" type="hinge" axis="0 1 0"/>
<geom type="capsule" size="0.05 0.5" fromto="0 0 0 0.5 0 0"/>
<site name="site2" pos="0.25 0 0.1" size="0.025"/>
</body>
</body>
</body>
</worldbody>
<tendon>
<spatial name="spatial0" width="0.0125">
<site site="site0"/>
<site site="site1"/>
<site site="site2"/>
</spatial>
<spatial name="spatial1" width="0.0125" actuatorfrclimited="true" actuatorfrcrange="-1 1">
<site site="site1"/>
<site site="site2"/>
</spatial>
<fixed name="fixed0" actuatorfrclimited="true" actuatorfrcrange="-10 10">
<joint joint="joint0" coef=".1"/>
<joint joint="joint1" coef=".2"/>
<joint joint="joint2" coef=".3"/>
</fixed>
<fixed name="fixed1" actuatorfrclimited="true" actuatorfrcrange="0 1">
<joint joint="joint0" coef=".1"/>
<joint joint="joint2" coef=".3"/>
</fixed>
</tendon>
<actuator>
<motor tendon="spatial0"/>
<motor tendon="spatial0"/>
<motor tendon="spatial0"/>
<motor tendon="spatial1"/>
<motor tendon="spatial1"/>
<motor tendon="fixed0"/>
<motor tendon="fixed1"/>
<motor tendon="fixed1"/>
</actuator>
<sensor>
<tendonactuatorfrc tendon="spatial0"/>
<tendonactuatorfrc tendon="spatial1"/>
<tendonactuatorfrc tendon="fixed0"/>
<tendonactuatorfrc tendon="fixed1"/>
</sensor>
</mujoco>
+45
View File
@@ -2070,6 +2070,51 @@ TEST_F(TendonTest, SiteBetweenPulleyNotAllowed) {
EXPECT_THAT(error.data(), HasSubstr("line 9"));
}
TEST_F(TendonTest, ActuatorForceRangeNotAllowed) {
std::string xml = R"(
<mujoco>
<worldbody>
<site name="site0"/>
<site name="site1"/>
</worldbody>
<tendon>
<spatial name="spatial" actuatorfrclimited="true" actuatorfrcrange="{}">
<site site="site0"/>
<site site="site1"/>
</spatial>
</tendon>
<actuator>
<motor tendon="spatial"/>
</actuator>
</mujoco>
)";
std::array<char, 1024> error;
std::string str_replace = "{}";
size_t rng_ind = xml.find(str_replace);
std::string xml0 = xml;
std::string range0 = "-2 -1";
xml0.replace(rng_ind, str_replace.length(), range0);
mjModel* m0 = LoadModelFromString(xml0.c_str(), error.data(), error.size());
EXPECT_THAT(m0, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid actuatorfrcrange in tendon"));
std::string xml1 = xml;
std::string range1 = "1 2";
xml1.replace(rng_ind, str_replace.length(), range1);
mjModel* m1 = LoadModelFromString(xml1.c_str(), error.data(), error.size());
EXPECT_THAT(m1, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid actuatorfrcrange in tendon"));
std::string xml2 = xml;
std::string range2 = "1 0";
xml2.replace(rng_ind, str_replace.length(), range2);
mjModel* m2 = LoadModelFromString(xml2.c_str(), error.data(), error.size());
EXPECT_THAT(m2, IsNull());
EXPECT_THAT(error.data(), HasSubstr("invalid actuatorfrcrange in tendon"));
}
// ------------- tests for tendon springrange ----------------------------------
using SpringrangeTest = MujocoTest;
+33 -28
View File
@@ -357,34 +357,35 @@ public enum mjtSensor : int{
mjSENS_ACTUATORVEL = 14,
mjSENS_ACTUATORFRC = 15,
mjSENS_JOINTACTFRC = 16,
mjSENS_BALLQUAT = 17,
mjSENS_BALLANGVEL = 18,
mjSENS_JOINTLIMITPOS = 19,
mjSENS_JOINTLIMITVEL = 20,
mjSENS_JOINTLIMITFRC = 21,
mjSENS_TENDONLIMITPOS = 22,
mjSENS_TENDONLIMITVEL = 23,
mjSENS_TENDONLIMITFRC = 24,
mjSENS_FRAMEPOS = 25,
mjSENS_FRAMEQUAT = 26,
mjSENS_FRAMEXAXIS = 27,
mjSENS_FRAMEYAXIS = 28,
mjSENS_FRAMEZAXIS = 29,
mjSENS_FRAMELINVEL = 30,
mjSENS_FRAMEANGVEL = 31,
mjSENS_FRAMELINACC = 32,
mjSENS_FRAMEANGACC = 33,
mjSENS_SUBTREECOM = 34,
mjSENS_SUBTREELINVEL = 35,
mjSENS_SUBTREEANGMOM = 36,
mjSENS_GEOMDIST = 37,
mjSENS_GEOMNORMAL = 38,
mjSENS_GEOMFROMTO = 39,
mjSENS_E_POTENTIAL = 40,
mjSENS_E_KINETIC = 41,
mjSENS_CLOCK = 42,
mjSENS_PLUGIN = 43,
mjSENS_USER = 44,
mjSENS_TENDONACTFRC = 17,
mjSENS_BALLQUAT = 18,
mjSENS_BALLANGVEL = 19,
mjSENS_JOINTLIMITPOS = 20,
mjSENS_JOINTLIMITVEL = 21,
mjSENS_JOINTLIMITFRC = 22,
mjSENS_TENDONLIMITPOS = 23,
mjSENS_TENDONLIMITVEL = 24,
mjSENS_TENDONLIMITFRC = 25,
mjSENS_FRAMEPOS = 26,
mjSENS_FRAMEQUAT = 27,
mjSENS_FRAMEXAXIS = 28,
mjSENS_FRAMEYAXIS = 29,
mjSENS_FRAMEZAXIS = 30,
mjSENS_FRAMELINVEL = 31,
mjSENS_FRAMEANGVEL = 32,
mjSENS_FRAMELINACC = 33,
mjSENS_FRAMEANGACC = 34,
mjSENS_SUBTREECOM = 35,
mjSENS_SUBTREELINVEL = 36,
mjSENS_SUBTREEANGMOM = 37,
mjSENS_GEOMDIST = 38,
mjSENS_GEOMNORMAL = 39,
mjSENS_GEOMFROMTO = 40,
mjSENS_E_POTENTIAL = 41,
mjSENS_E_KINETIC = 42,
mjSENS_CLOCK = 43,
mjSENS_PLUGIN = 44,
mjSENS_USER = 45,
}
public enum mjtStage : int{
mjSTAGE_NONE = 0,
@@ -5569,12 +5570,14 @@ public unsafe struct mjModel_ {
public int* tendon_matid;
public int* tendon_group;
public byte* tendon_limited;
public byte* tendon_actfrclimited;
public double* tendon_width;
public double* tendon_solref_lim;
public double* tendon_solimp_lim;
public double* tendon_solref_fri;
public double* tendon_solimp_fri;
public double* tendon_range;
public double* tendon_actfrcrange;
public double* tendon_margin;
public double* tendon_stiffness;
public double* tendon_damping;
@@ -6398,8 +6401,10 @@ public unsafe struct model {
public int* tendon_matid;
public int* tendon_group;
public byte* tendon_limited;
public byte* tendon_actfrclimited;
public double* tendon_width;
public double* tendon_range;
public double* tendon_actfrcrange;
public double* tendon_stiffness;
public double* tendon_damping;
public double* tendon_frictionloss;