Skip to content

Commit d507e92

Browse files
yuvaltassacopybara-github
authored andcommitted
Preparation for MIMO actuators: split actuator counts: nu (inputs), nactuator (objects), nout (outputs).
An actuator now owns a block of consecutive controls (actuator_ctrladr/ctrlnum, width defined by the actuator type) and a block of consecutive force outputs (actuator_outadr/outnum, width defined by the transmission type). Force outputs are the scalars of actuation space: one force, length, velocity and moment row each. nout = dim(actuator_force) is derived from transmission types; all current types have width 1, so all three counts coincide for every existing model and behavior is bit-exact. Array re-keying: ctrlrange/ctrllimited by nu; forcerange/forcelimited/gear/ acc0/length0/lengthrange and the moment row structure by nout; everything else per actuator. The mjModel actuator block is re-sorted by size key. Layout-breaking, not behavior-breaking: saved .mjb files are invalidated (size list changed) and recompilation is required. PiperOrigin-RevId: 948351772 Change-Id: Icbc196ffa083cb1eaa6f1a3710869c89d8f62540
1 parent 06f12a9 commit d507e92

27 files changed

Lines changed: 726 additions & 514 deletions

File tree

‎doc/changelog.rst‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ General
3131
error instead of the generic "could not decode content" message.
3232
- Added support for resource writing via :ref:`mju_writeResource` and the ``write`` callback in :ref:`mjpResourceProvider`.
3333
- Added support for :ref:`multiccd <coMultiCCD>` with arbitrarily large meshes.
34+
- Refactored actuator infrastructure in preparation for MIMO (multi-input multi-output) actuator support. Each actuator
35+
now has ``ctrlnum`` (number of controls) and ``outnum`` (number of force outputs). The total counts
36+
``nu = sum(ctrlnum)`` and ``nout = sum(outnum)`` dimension ``mjData.ctrl`` and ``mjData.actuator_force``,
37+
respectively, ``nactuator`` is the number of actuators. For existing actuators ``ctrnum = outnum = 1``, so
38+
``nactuator == nu == nout`` and existing code is unaffected.
3439

3540
.. admonition:: Breaking API changes
3641
:class: attention

‎doc/computation/index.rst‎

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,21 @@ detailed summary of the :ref:`simulation pipeline <Pipeline>` is given at the en
262262
Actuation model
263263
~~~~~~~~~~~~~~~
264264

265-
MuJoCo provides a flexible actuator model. All actuators are single-input-single-output (SISO). The input to actuator
266-
:math:`i` is a scalar control :math:`u_i` specified by the user. The output is a scalar force :math:`p_i` which is
267-
mapped to joint coordinates by a vector of moment arms determined by the transmission. An actuator can also have
268-
activation state :math:`w_i` with its own dynamics. The control inputs for all actuators are stored in ``mjData.ctrl``,
269-
the force outputs are stored in ``mjData.actuator_force``, and the activation states (if any) are stored in
270-
``mjData.act``.
265+
MuJoCo provides a flexible actuator model. Most actuators are single-input-single-output (SISO): the input to
266+
actuator :math:`i` is a scalar control :math:`u_i` specified by the user, and the output is a scalar force
267+
:math:`p_i`, which is mapped to joint coordinates by a vector of moment arms determined by the transmission. An
268+
actuator can also have activation state :math:`w_i` with its own dynamics. The control inputs for all actuators are
269+
stored in ``mjData.ctrl``, the force outputs are stored in ``mjData.actuator_force``, and the activation states (if
270+
any) are stored in ``mjData.act``.
271+
272+
More generally, an actuator can have several control inputs, several force outputs, or both. For example, a servo
273+
which accepts both a position setpoint and a velocity setpoint has two inputs and one output. The number of inputs
274+
is a property of the actuator type, and the number of outputs is a property of its transmission; neither is
275+
specified directly by the user. Since the number of inputs and the number of outputs can vary per actuator, the model
276+
has three separate counts: the number of actuators ``nactuator``, the total number of controls ``nu``, and the total
277+
number of force outputs ``nout``. In a model where all actuators are SISO, all three are equal. Note that outputs are
278+
counted in actuation space, before the mapping to joint coordinates: a tendon actuator with a single force output can
279+
move many joints.
271280

272281
These three components of an actuator -- transmission, activation dynamics, and force generation -- determine how the
273282
actuator works. The user can set them independently for maximum flexibility, or use :ref:`Actuator shortcuts
@@ -278,11 +287,13 @@ actuator works. The user can set them independently for maximum flexibility, or
278287
Transmission
279288
^^^^^^^^^^^^
280289

281-
Each actuator has a scalar length :math:`l_i(q)` defined by the type of transmission and its parameters. The gradient
282-
:math:`\nabla l_i` is an :math:`\nv`-dimensional vector of moment arms. It determines the mapping from scalar
283-
actuator force to joint force. The transmission properties are determined by the MuJoCo object to which the actuator
284-
is attached; the possible attachment object types are :at:`joint`, :at:`tendon`, :at:`jointinparent`,
285-
:at:`slider-crank`, :at:`site`, and :at:`body`.
290+
The transmission attaches the actuator to the rest of the system. Each force output of the actuator has a scalar
291+
length :math:`l_k(q)`, defined by the type of transmission and its parameters, for example the
292+
:ref:`gear<actuator-general-gear>` vector. The gradient :math:`\nabla l_k` is an :math:`\nv`-dimensional vector of
293+
moment arms; it determines the mapping from the scalar output force to joint forces. The number of force outputs is
294+
likewise determined by the transmission; all the types listed below define a single output. The transmission
295+
properties are determined by the MuJoCo object to which the actuator is attached; the possible attachment object
296+
types are :at:`joint`, :at:`tendon`, :at:`jointinparent`, :at:`slider-crank`, :at:`site`, and :at:`body`.
286297

287298
:at:`joint` and :at:`tendon`
288299
The :at:`joint` and :at:`tendon` transmission types act as expected and correspond to the actuator applying forces or
@@ -369,32 +380,28 @@ diverge for :math:`\texttt{t} < h`, while exactly-integrated filters are stable
369380
Force generation
370381
^^^^^^^^^^^^^^^^
371382

372-
Each actuator generates a scalar force :math:`p_i` which is some function
373-
374-
.. math::
375-
p_i \left( u_i, w_i, l_i, \dot{l}_i \right)
376-
377-
Similarly to activation dynamics, the force generation mechanism is actuator-specific and cannot interact with the
378-
other actuators in the model. Currently the force is affine in the activation state when present, and in the control
379-
otherwise:
383+
Each actuator generates a scalar force for each of its outputs, as a function of its controls, activation states,
384+
and lengths and velocities. Similarly to activation dynamics, force generation is actuator-specific: the inputs and
385+
outputs of a single actuator can interact, but different actuators cannot affect each other. For SISO actuators the
386+
force is affine in the activation state when present, and in the control otherwise:
380387

381388
.. math::
382389
p_i = (a w_i \; \text{or} \; a u_i) + b_0 + b_1 l_i + b_2 \dot{l}_i
383390
384391
Here :math:`a` is an actuator-specific gain parameter and :math:`b_0, b_1, b_2` are actuator-specific bias
385392
parameters, stored in ``mjModel.actuator_gainprm`` and ``mjModel.actuator_biasprm`` respectively. Different settings
386393
of the gain and bias parameters can be used to model direct force control as well as position and velocity servos -in
387-
which case the control/activation has the meaning of reference position or velocity. One can also compute custom gain
388-
and bias terms by installing the callbacks :ref:`mjcb_act_gain` and :ref:`mjcb_act_bias` and setting the gain and
389-
bias type to "user". Note that affine force generation makes it possible to infer the controls/activations from the
390-
applied force computed in inverse dynamics, using the pseudo-inverse of the matrix of moment arms. However some of
391-
the actuators used in the real world are not affine (especially those that have embedded low-level controllers), so
392-
we are considering extensions to the above model.
394+
which case the control/activation has the meaning of reference position or velocity. Multi-input actuator types
395+
define their own force laws. One can also compute custom gain and bias terms for SISO actuators by installing the
396+
callbacks :ref:`mjcb_act_gain` and :ref:`mjcb_act_bias` and setting the gain and bias type to "user". Note that
397+
affine force generation makes it possible to infer the controls/activations from the applied force computed in
398+
inverse dynamics, using the pseudo-inverse of the matrix of moment arms.
393399

394-
Putting all this together, the net force in generalized coordinates contributed by all actuators is
400+
Putting all this together, the net force in generalized coordinates contributed by all actuators is the sum over all
401+
force outputs
395402

396403
.. math::
397-
\sum_i \nabla l_i(q) \; p_i \left(u_i, w_i, l_i(q), \dot{l}_i(q, v) \right)
404+
\sum_k \nabla l_k(q) \; p_k
398405
399406
This quantity is stored in ``mjData.qfrc_actuator``. It is added to the applied force vector :math:`\tau`, together
400407
with any user-defined forces in joint or Cartesian coordinates (which are stored in ``mjData.qfrc_applied`` and

‎doc/includes/references.h‎

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,9 @@ typedef struct mjData_ {
215215
mjtNum* wrap_xpos; // Cartesian 3D points in all paths (nwrap x 6)
216216

217217
// computed by mj_fwdPosition/mj_transmission
218-
mjtNum* actuator_length; // actuator lengths (nu x 1)
219-
int* moment_rownnz; // number of non-zeros in actuator_moment row (nu x 1)
220-
int* moment_rowadr; // row start address in colind array (nu x 1)
218+
mjtNum* actuator_length; // actuator lengths, one per force output (nout x 1)
219+
int* moment_rownnz; // number of non-zeros in actuator_moment row (nout x 1)
220+
int* moment_rowadr; // row start address in colind array (nout x 1)
221221
int* moment_colind; // column indices in sparse Jacobian (nJmom x 1)
222222
mjtNum* actuator_moment; // actuator moments (nJmom x 1)
223223

@@ -244,7 +244,7 @@ typedef struct mjData_ {
244244
// computed by mj_fwdVelocity
245245
mjtNum* flexedge_velocity; // flex edge velocities (nflexedge x 1)
246246
mjtNum* ten_velocity; // tendon velocities (ntendon x 1)
247-
mjtNum* actuator_velocity; // actuator velocities (nu x 1)
247+
mjtNum* actuator_velocity; // actuator velocities, one per force output (nout x 1)
248248

249249
// computed by mj_fwdVelocity/mj_comVel
250250
mjtNum* cvel; // com-based velocity (rot:lin) (nbody x 6)
@@ -277,8 +277,8 @@ typedef struct mjData_ {
277277
//-------------------- POSITION, VELOCITY, CONTROL/ACCELERATION dependent
278278

279279
// computed by mj_fwdActuation
280-
mjtNum* actuator_force; // actuator force in actuation space (nu x 1)
281-
mjtNum* qfrc_actuator; // actuator force (nv x 1)
280+
mjtNum* actuator_force; // actuator force in actuation space (nout x 1)
281+
mjtNum* qfrc_actuator; // actuator force in joint space (nv x 1)
282282

283283
// computed by mj_fwdAcceleration
284284
mjtNum* qfrc_smooth; // net unconstrained force (nv x 1)
@@ -557,7 +557,9 @@ typedef struct mjModel_ {
557557
// sizes needed at mjModel construction
558558
mjtSize nq; // number of generalized coordinates = dim(qpos)
559559
mjtSize nv; // number of degrees of freedom = dim(qvel)
560-
mjtSize nu; // number of actuators/controls = dim(ctrl)
560+
mjtSize nu; // number of scalar controls = dim(ctrl)
561+
mjtSize nactuator; // number of actuators
562+
mjtSize nout; // number of force outputs, derived from transmission type
561563
mjtSize na; // number of activation states = dim(act)
562564
mjtSize nbody; // number of bodies
563565
mjtSize nbvh; // number of total bounding volumes in all bodies
@@ -1072,37 +1074,41 @@ typedef struct mjModel_ {
10721074
mjtNum* wrap_prm; // divisor, joint coef, or site id (nwrap x 1)
10731075

10741076
// actuators
1075-
int* actuator_trntype; // transmission type (mjtTrn) (nu x 1)
1076-
int* actuator_dyntype; // dynamics type (mjtDyn) (nu x 1)
1077-
int* actuator_gaintype; // gain type (mjtGain) (nu x 1)
1078-
int* actuator_biastype; // bias type (mjtBias) (nu x 1)
1079-
int* actuator_trnid; // transmission id: joint, tendon, site (nu x 2)
1080-
mjtNum* actuator_damping; // linear damping coefficient (nu x 1)
1081-
mjtNum* actuator_dampingpoly; // high-order damping coefficients (nu x mjNPOLY)
1082-
mjtNum* actuator_armature; // armature added to target (joint, tendon) (nu x 1)
1083-
int* actuator_actadr; // first activation address; -1: stateless (nu x 1)
1084-
int* actuator_actnum; // number of activation variables (nu x 1)
1085-
int* actuator_group; // group for visibility (nu x 1)
1086-
int* actuator_history; // history buffer: [nsample, interp] (nu x 2)
1087-
int* actuator_historyadr; // address in history buffer; -1: none (nu x 1)
1088-
mjtNum* actuator_delay; // delay time in seconds; 0: no delay (nu x 1)
1077+
int* actuator_trntype; // transmission type (mjtTrn) (nactuator x 1)
1078+
int* actuator_dyntype; // dynamics type (mjtDyn) (nactuator x 1)
1079+
int* actuator_gaintype; // gain type (mjtGain) (nactuator x 1)
1080+
int* actuator_biastype; // bias type (mjtBias) (nactuator x 1)
1081+
int* actuator_ctrladr; // address of first control (nactuator x 1)
1082+
int* actuator_ctrlnum; // number of controls (nactuator x 1)
1083+
int* actuator_outadr; // address of first force output (nactuator x 1)
1084+
int* actuator_outnum; // number of force outputs, from trntype (nactuator x 1)
1085+
int* actuator_actadr; // first activation address; -1: stateless (nactuator x 1)
1086+
int* actuator_actnum; // number of activation variables (nactuator x 1)
1087+
int* actuator_trnid; // transmission id: joint, tendon, site (nactuator x 2)
1088+
mjtNum* actuator_cranklength; // crank length for slider-crank (nactuator x 1)
1089+
mjtNum* actuator_dynprm; // dynamics parameters (nactuator x mjNDYN)
1090+
mjtNum* actuator_gainprm; // gain parameters (nactuator x mjNGAIN)
1091+
mjtNum* actuator_biasprm; // bias parameters (nactuator x mjNBIAS)
1092+
mjtBool* actuator_actlimited; // is activation limited (nactuator x 1)
1093+
mjtNum* actuator_actrange; // range of activations (nactuator x 2)
1094+
mjtBool* actuator_actearly; // step activation before force (nactuator x 1)
1095+
int* actuator_history; // history buffer: [nsample, interp] (nactuator x 2)
1096+
int* actuator_historyadr; // address in history buffer; -1: none (nactuator x 1)
1097+
mjtNum* actuator_delay; // delay time; 0: no delay (nactuator x 1)
1098+
mjtNum* actuator_damping; // linear damping coefficient (nactuator x 1)
1099+
mjtNum* actuator_dampingpoly; // high-order damping coefficients (nactuator x mjNPOLY)
1100+
mjtNum* actuator_armature; // armature added to target (joint, tendon) (nactuator x 1)
1101+
int* actuator_group; // group for visibility (nactuator x 1)
1102+
mjtNum* actuator_user; // user data (nactuator x nuser_actuator)
1103+
int* actuator_plugin; // plugin instance id; -1: not a plugin (nactuator x 1)
10891104
mjtBool* actuator_ctrllimited; // is control limited (nu x 1)
1090-
mjtBool* actuator_forcelimited;// is force limited (nu x 1)
1091-
mjtBool* actuator_actlimited; // is activation limited (nu x 1)
1092-
mjtNum* actuator_dynprm; // dynamics parameters (nu x mjNDYN)
1093-
mjtNum* actuator_gainprm; // gain parameters (nu x mjNGAIN)
1094-
mjtNum* actuator_biasprm; // bias parameters (nu x mjNBIAS)
1095-
mjtBool* actuator_actearly; // step activation before force (nu x 1)
10961105
mjtNum* actuator_ctrlrange; // range of controls (nu x 2)
1097-
mjtNum* actuator_forcerange; // range of forces (nu x 2)
1098-
mjtNum* actuator_actrange; // range of activations (nu x 2)
1099-
mjtNum* actuator_gear; // scale length and transmitted force (nu x 6)
1100-
mjtNum* actuator_cranklength; // crank length for slider-crank (nu x 1)
1101-
mjtNum* actuator_acc0; // acceleration from unit force in qpos0 (nu x 1)
1102-
mjtNum* actuator_length0; // actuator length in qpos0 (nu x 1)
1103-
mjtNum* actuator_lengthrange; // feasible actuator length range (nu x 2)
1104-
mjtNum* actuator_user; // user data (nu x nuser_actuator)
1105-
int* actuator_plugin; // plugin instance id; -1: not a plugin (nu x 1)
1106+
mjtNum* actuator_gear; // scale length and transmitted force (nout x 6)
1107+
mjtBool* actuator_forcelimited;// is force limited (nout x 1)
1108+
mjtNum* actuator_forcerange; // range of forces (nout x 2)
1109+
mjtNum* actuator_acc0; // acceleration from unit force in qpos0 (nout x 1)
1110+
mjtNum* actuator_length0; // actuator length in qpos0 (nout x 1)
1111+
mjtNum* actuator_lengthrange; // feasible actuator length range (nout x 2)
11061112

11071113
// sensors
11081114
int* sensor_type; // sensor type (mjtSensor) (nsensor x 1)
@@ -1174,7 +1180,7 @@ typedef struct mjModel_ {
11741180
int* name_excludeadr; // exclude name pointers (nexclude x 1)
11751181
int* name_eqadr; // equality constraint name pointers (neq x 1)
11761182
int* name_tendonadr; // tendon name pointers (ntendon x 1)
1177-
int* name_actuatoradr; // actuator name pointers (nu x 1)
1183+
int* name_actuatoradr; // actuator name pointers (nactuator x 1)
11781184
int* name_sensoradr; // sensor name pointers (nsensor x 1)
11791185
int* name_numericadr; // numeric name pointers (nnumeric x 1)
11801186
int* name_textadr; // text name pointers (ntext x 1)

‎include/mujoco/mjdata.h‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,9 @@ typedef struct mjData_ {
239239
mjtNum* wrap_xpos; // Cartesian 3D points in all paths (nwrap x 6)
240240

241241
// computed by mj_fwdPosition/mj_transmission
242-
mjtNum* actuator_length; // actuator lengths (nu x 1)
243-
int* moment_rownnz; // number of non-zeros in actuator_moment row (nu x 1)
244-
int* moment_rowadr; // row start address in colind array (nu x 1)
242+
mjtNum* actuator_length; // actuator lengths, one per force output (nout x 1)
243+
int* moment_rownnz; // number of non-zeros in actuator_moment row (nout x 1)
244+
int* moment_rowadr; // row start address in colind array (nout x 1)
245245
int* moment_colind; // column indices in sparse Jacobian (nJmom x 1)
246246
mjtNum* actuator_moment; // actuator moments (nJmom x 1)
247247

@@ -268,7 +268,7 @@ typedef struct mjData_ {
268268
// computed by mj_fwdVelocity
269269
mjtNum* flexedge_velocity; // flex edge velocities (nflexedge x 1)
270270
mjtNum* ten_velocity; // tendon velocities (ntendon x 1)
271-
mjtNum* actuator_velocity; // actuator velocities (nu x 1)
271+
mjtNum* actuator_velocity; // actuator velocities, one per force output (nout x 1)
272272

273273
// computed by mj_fwdVelocity/mj_comVel
274274
mjtNum* cvel; // com-based velocity (rot:lin) (nbody x 6)
@@ -301,8 +301,8 @@ typedef struct mjData_ {
301301
//-------------------- POSITION, VELOCITY, CONTROL/ACCELERATION dependent
302302

303303
// computed by mj_fwdActuation
304-
mjtNum* actuator_force; // actuator force in actuation space (nu x 1)
305-
mjtNum* qfrc_actuator; // actuator force (nv x 1)
304+
mjtNum* actuator_force; // actuator force in actuation space (nout x 1)
305+
mjtNum* qfrc_actuator; // actuator force in joint space (nv x 1)
306306

307307
// computed by mj_fwdAcceleration
308308
mjtNum* qfrc_smooth; // net unconstrained force (nv x 1)

0 commit comments

Comments
 (0)
⌂ 换网址