Runtime disabling of actuators according to group.
Added `option-actuatorgroupdisable` attribute and associated `mjOption.disableactuator` integer bitfield, used to disable sets of actuators at runtime according to their group. - The first 6 actuator groups are toggleable in the `simulate` viewer. - Minor refactor and cleanup of actuator documentation. https://youtu.be/H9qG9Zf2W44 Fixes #1092. PiperOrigin-RevId: 578335600 Change-Id: I4cf663b90ea768e4380acfa2fe3b8c15c7cbb568
This commit is contained in:
committed by
Copybara-Service
parent
45878b7eef
commit
893c404230
@@ -498,7 +498,7 @@ shown in the table below. Their names are in the format ``mjKEY_XXX``. They corr
|
|||||||
- Maximum number of UI sections.
|
- Maximum number of UI sections.
|
||||||
Defined in `mjui.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`_.
|
Defined in `mjui.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`_.
|
||||||
* - ``mjMAXUIITEM``
|
* - ``mjMAXUIITEM``
|
||||||
- 80
|
- 200
|
||||||
- Maximum number of items per UI section.
|
- Maximum number of items per UI section.
|
||||||
Defined in `mjui.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`_.
|
Defined in `mjui.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjui.h>`_.
|
||||||
* - ``mjMAXUITEXT``
|
* - ``mjMAXUITEXT``
|
||||||
|
|||||||
@@ -1879,6 +1879,12 @@ adjust it properly through the XML.
|
|||||||
:at:`sdf_initpoints`: :at-val:`int, "40"`
|
:at:`sdf_initpoints`: :at-val:`int, "40"`
|
||||||
Number of starting points used for fining contacts with Signed Distance Field collisions.
|
Number of starting points used for fining contacts with Signed Distance Field collisions.
|
||||||
|
|
||||||
|
.. _option-actuatorgroupdisable:
|
||||||
|
|
||||||
|
:at:`actuatorgroupdisable`: :at-val:`int(30), ""`
|
||||||
|
List of actuator groups to disable. Actuators whose :ref:`group<actuator-general-group>` is in this list will produce
|
||||||
|
no force. If they are stateful, their activation states will not be integrated. Internally this list is
|
||||||
|
implemented as an integer bitfield, so values must be in the range ``0 <= group <= 30``.
|
||||||
|
|
||||||
.. _option-flag:
|
.. _option-flag:
|
||||||
|
|
||||||
@@ -4883,7 +4889,7 @@ multiplied by the corresponding coef value, and added up to obtain the tendon le
|
|||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
This is a grouping element for actuator definitions. Recall the discussion of MuJoCo's :ref:`Actuation model
|
This is a grouping element for actuator definitions. Recall the discussion of MuJoCo's :ref:`Actuation model
|
||||||
<geActuation>` in the Computation chapter, and the :ref:`Actuator shortcuts <CActuator>` discussed earlier in this
|
<geActuation>` in the Computation chapter, and the :ref:`Actuator shortcuts <CActShortcuts>` discussed earlier in this
|
||||||
chapter. The first 13 attributes of all actuator-related elements below are the same, so we document them only once,
|
chapter. The first 13 attributes of all actuator-related elements below are the same, so we document them only once,
|
||||||
under the :el:`general` actuator.
|
under the :el:`general` actuator.
|
||||||
|
|
||||||
@@ -5156,7 +5162,7 @@ specify them independently.
|
|||||||
:el-prefix:`actuator/` |-| **motor** (*)
|
:el-prefix:`actuator/` |-| **motor** (*)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This and the next three elements are the :ref:`Actuator shortcuts <CActuator>` discussed earlier. When a
|
This and the next three elements are the :ref:`Actuator shortcuts <CActShortcuts>` discussed earlier. When a
|
||||||
such shortcut is encountered, the parser creates a :el:`general` actuator and sets its dynprm, gainprm and biasprm
|
such shortcut is encountered, the parser creates a :el:`general` actuator and sets its dynprm, gainprm and biasprm
|
||||||
attributes to the internal defaults shown above, regardless of any default settings. It then adjusts dyntype, gaintype
|
attributes to the internal defaults shown above, regardless of any default settings. It then adjusts dyntype, gaintype
|
||||||
and biastype depending on the shortcut, parses any custom attributes (beyond the common ones), and translates them
|
and biastype depending on the shortcut, parses any custom attributes (beyond the common ones), and translates them
|
||||||
@@ -7526,7 +7532,7 @@ if omitted.
|
|||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This and the next three elements set the attributes of the :ref:`general <actuator-general>` element using
|
This and the next three elements set the attributes of the :ref:`general <actuator-general>` element using
|
||||||
:ref:`Actuator shortcuts <CActuator>`. It does not make sense to use more than one such shortcut in the same defaults
|
:ref:`Actuator shortcuts <CActShortcuts>`. It does not make sense to use more than one such shortcut in the same defaults
|
||||||
class, because they set the same underlying attributes, replacing any previous settings. All
|
class, because they set the same underlying attributes, replacing any previous settings. All
|
||||||
:ref:`motor <actuator-motor>` attributes are available here except: name, class, joint, jointinparent, site, tendon,
|
:ref:`motor <actuator-motor>` attributes are available here except: name, class, joint, jointinparent, site, tendon,
|
||||||
slidersite, cranksite.
|
slidersite, cranksite.
|
||||||
|
|||||||
+1
-1
@@ -230,7 +230,7 @@
|
|||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`iterations<option-iterations>` | :ref:`ls_iterations<option-ls_iterations>` | :ref:`noslip_iterations<option-noslip_iterations>` | :ref:`mpr_iterations<option-mpr_iterations>` | |
|
| | | | :ref:`iterations<option-iterations>` | :ref:`ls_iterations<option-ls_iterations>` | :ref:`noslip_iterations<option-noslip_iterations>` | :ref:`mpr_iterations<option-mpr_iterations>` | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
| | | | :ref:`sdf_iterations<option-sdf_iterations>` | :ref:`sdf_initpoints<option-sdf_initpoints>` | | | |
|
| | | | :ref:`sdf_iterations<option-sdf_iterations>` | :ref:`sdf_initpoints<option-sdf_initpoints>` | :ref:`actuatorgroupdisable<option-actuatorgroupdisable>` | | |
|
||||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
| |_| option |br| |_| |L| | | .. table:: |
|
| |_| option |br| |_| |L| | | .. table:: |
|
||||||
|
|||||||
+30
-17
@@ -7,41 +7,54 @@ Upcoming version (not yet released)
|
|||||||
|
|
||||||
General
|
General
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
|
- Added sub-terms of total passive forces in ``mjData.qfrc_passive`` to :ref:`mjData`:
|
||||||
|
``qfrc_{spring, damper, gravcomp, fluid}``. The sum of these vectors equals ``qfrc_passive``.
|
||||||
|
|
||||||
1. Added sub-terms of total passive forces in ``mjData.qfrc_passive`` to :ref:`mjData`:
|
.. youtube:: H9qG9Zf2W44
|
||||||
``qfrc_{spring, damper, gravcomp, fluid}``. The sum of these vectors equals ``qfrc_passive``.
|
:align: right
|
||||||
2. Increased ``mjMAXUIITEM`` (maximum number of UI elements per section in Simulate) to 200.
|
:width: 240px
|
||||||
|
|
||||||
|
- Added :ref:`actuatorgroupdisable<option-actuatorgroupdisable>` attribute and associated
|
||||||
|
:ref:`mjOption.disableactuator<mjOption>` integer bitfield, which can be used to disable sets of actuators at runtime
|
||||||
|
according to their :ref:`group<actuator-general-group>`. Fixes :github:issue:`1092`. See :ref:`CActDisable`.
|
||||||
|
|
||||||
|
- The first 6 actuator groups are toggleable in the :ref:`simulate<saSimulate>` viewer. See `example model
|
||||||
|
<https://github.com/google-deepmind/mujoco/blob/main/test/engine/testdata/actuation/actuator_group_disable.xml>`__
|
||||||
|
and associated screen-capture on the right.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Increased ``mjMAXUIITEM`` (maximum number of UI elements per section in Simulate) to 200.
|
||||||
|
|
||||||
MJX
|
MJX
|
||||||
^^^
|
^^^
|
||||||
2. Added support for joint equality constraints (``mjEQ_JOINT`` in :ref:`mjtEq`).
|
- Added support for joint equality constraints (``mjEQ_JOINT`` in :ref:`mjtEq`).
|
||||||
3. Fixed bug where mixed ``jnt_limited`` joints were not being constrained correctly.
|
- Fixed bug where mixed ``jnt_limited`` joints were not being constrained correctly.
|
||||||
4. Made ``device_put`` type validation more verbose (fixes :github:issue:`1113`).
|
- Made ``device_put`` type validation more verbose (fixes :github:issue:`1113`).
|
||||||
5. Removed empty EFC rows from `MJX`, for joints with no limits (fixes :github:issue:`1117`).
|
- Removed empty EFC rows from `MJX`, for joints with no limits (fixes :github:issue:`1117`).
|
||||||
6. Fixed bug where equality constraints became inactive (fixes :github:issue:`1129`).
|
- Fixed bug where equality constraints became inactive (fixes :github:issue:`1129`).
|
||||||
7. Added an error when loading a model with tendons (fixes :github:issue:`1149`).
|
- Added an error when loading a model with tendons (fixes :github:issue:`1149`).
|
||||||
|
|
||||||
Python bindings
|
Python bindings
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
6. Fix the macOS ``mjpython`` launcher to work with the Python interpreter from Apple Command Line
|
- Fix the macOS ``mjpython`` launcher to work with the Python interpreter from Apple Command Line Tools.
|
||||||
Tools.
|
- Fixed a crash when copying instances of ``mujoco.MjData`` for models that use plugins. Introduced a ``model``
|
||||||
7. Fixed a crash when copying instances of ``mujoco.MjData`` for models that use plugins. Introduced a ``model``
|
attribute to ``MjData`` which is reference to the model that was used to create that ``MjData`` instance.
|
||||||
attribute to ``MjData`` which is reference to the model that was used to create that ``MjData`` instance.
|
|
||||||
|
|
||||||
Simulate
|
Simulate
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
8. :ref:`simulate<saSimulate>`: correct handling of "Pause update", "Fullscreen" and "VSync" buttons.
|
- :ref:`simulate<saSimulate>`: correct handling of "Pause update", "Fullscreen" and "VSync" buttons.
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
9. Added documentation for the :ref:`UI` framework.
|
- Added documentation for the :ref:`UI` framework.
|
||||||
10. Fixed typos and supported fields in docs (fixes :github:issue:`1105` and :github:issue:`1106`).
|
- Fixed typos and supported fields in docs (fixes :github:issue:`1105` and :github:issue:`1106`).
|
||||||
|
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
11. Fixed bug relating to welds modified with :ref:`torquescale<equality-weld-torquescale>`.
|
- Fixed bug relating to welds modified with :ref:`torquescale<equality-weld-torquescale>`.
|
||||||
|
|
||||||
Version 3.0.0 (October 18, 2023)
|
Version 3.0.0 (October 18, 2023)
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|||||||
+19
-17
@@ -271,7 +271,7 @@ the force outputs are stored in ``mjData.actuator_force``, and the activation st
|
|||||||
|
|
||||||
These three components of an actuator - transmission, activation dynamics, and force generation - determine how the
|
These three components of an actuator - transmission, activation dynamics, and force generation - determine how the
|
||||||
actuator works. The user can set them independently for maximum flexibility, or use :ref:`Actuator shortcuts
|
actuator works. The user can set them independently for maximum flexibility, or use :ref:`Actuator shortcuts
|
||||||
<CActuator>` which instantiate common actuator types.
|
<CActShortcuts>` which instantiate common actuator types.
|
||||||
|
|
||||||
.. _geTransmission:
|
.. _geTransmission:
|
||||||
|
|
||||||
@@ -316,8 +316,8 @@ is attached; the possible attachment object types are :at:`joint`, :at:`tendon`,
|
|||||||
|
|
||||||
.. _geActivation:
|
.. _geActivation:
|
||||||
|
|
||||||
Activation dynamics
|
Stateful actuators
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Some actuators such as pneumatic and hydraulic cylinders as well as biological muscles have an internal state called
|
Some actuators such as pneumatic and hydraulic cylinders as well as biological muscles have an internal state called
|
||||||
"activation". This is a true dynamic state, beyond the joint positions :math:`q` and velocities :math:`v`. Including
|
"activation". This is a true dynamic state, beyond the joint positions :math:`q` and velocities :math:`v`. Including
|
||||||
@@ -333,27 +333,33 @@ independent of the other actuators. The activation types currently implemented a
|
|||||||
.. math::
|
.. math::
|
||||||
\begin{aligned}
|
\begin{aligned}
|
||||||
\text{integrator}: & & \dot{w}_i &= u_i \\
|
\text{integrator}: & & \dot{w}_i &= u_i \\
|
||||||
\text{filter}: & & \dot{w}_i &= (u_i - w_i) / t \\
|
\text{filter}: & & \dot{w}_i &= (u_i - w_i) / \texttt{t} \\
|
||||||
\text{filterexact}: & & \dot{w}_i &= (u_i - w_i) / t \\
|
\text{filterexact}: & & \dot{w}_i &= (u_i - w_i) / \texttt{t} \\
|
||||||
|
\text{muscle}: & & \dot{w}_i &= \textrm{muscle}(u_i, w_i, l_i, \dot{l}_i)
|
||||||
\end{aligned}
|
\end{aligned}
|
||||||
|
|
||||||
where :math:`t` is an actuator-specific time constant stored in ``mjModel.actuator_dynprm``. In addition the type can
|
where :math:`\texttt{t}` is an actuator-specific time-constant stored in ``mjModel.actuator_dynprm``. In addition, the
|
||||||
be "user", in which case :math:`w_i` is computed by the user-defined callback :ref:`mjcb_act_dyn`. The type can also
|
type can be "user", in which case :math:`w_i` is computed by the user-defined callback :ref:`mjcb_act_dyn`. The type can
|
||||||
be "none" which corresponds to a regular actuator with no activation state. The dimensionality of :math:`w` equals
|
also be "none" which corresponds to a regular actuator with no activation state. The dimensionality of :math:`w` equals
|
||||||
the number of actuators whose activation type is different from "none".
|
the number of actuators whose activation type is different from "none".
|
||||||
|
|
||||||
|
For more information regarding muscle activation dynamics, see :ref:`CMuscle`.
|
||||||
|
|
||||||
For ``filterexact`` activation dynamics, Euler integration of :math:`\dot{w}` is replaced with the analytic integral:
|
For ``filterexact`` activation dynamics, Euler integration of :math:`\dot{w}` is replaced with the analytic integral:
|
||||||
|
|
||||||
.. math::
|
.. math::
|
||||||
\begin{aligned}
|
\begin{aligned}
|
||||||
\text{filter}: & & w_{i+1} &= w_i + h (u_i - w_i) / t \\
|
\text{filter}: & & w_{i+1} &= w_i + h (u_i - w_i) / \texttt{t} \\
|
||||||
\text{filterexact}: & & w_{i+1} &= w_i + (u_i - w_i) (1 - e^{-h / t}) \\
|
\text{filterexact}: & & w_{i+1} &= w_i + (u_i - w_i) (1 - e^{-h / \texttt{t}}) \\
|
||||||
\end{aligned}
|
\end{aligned}
|
||||||
|
|
||||||
The two expressions converge to the same value in the :math:`h \rightarrow 0` limit.
|
The two expressions converge to the same value in the :math:`h \rightarrow 0` limit. Note that Euler-integrated filters
|
||||||
|
diverge for :math:`\texttt{t} < h`, while exactly-integrated filters are stable for any positive :math:`\texttt{t}`.
|
||||||
|
|
||||||
Note that Euler-integrated filters diverge for :math:`t < h`, while exactly-integrated filters are stable for any
|
:ref:`actearly<actuator-general-actearly>`:
|
||||||
:math:`t > 0`.
|
If the :ref:`actearly<actuator-general-actearly>` attribute is set to "true", ``mjData.actuator_force`` is computed
|
||||||
|
based on :math:`w_{i+1}` (the next activation), reducing the delay between changes to :math:`u` and their effects on
|
||||||
|
the acceleration by one time step (so the total dynamics are second-order rather than third order).
|
||||||
|
|
||||||
.. _geActuatorForce:
|
.. _geActuatorForce:
|
||||||
|
|
||||||
@@ -391,10 +397,6 @@ This quantity is stored in ``mjData.qfrc_actuator``. It is added to the applied
|
|||||||
with any user-defined forces in joint or Cartesian coordinates (which are stored in ``mjData.qfrc_applied`` and
|
with any user-defined forces in joint or Cartesian coordinates (which are stored in ``mjData.qfrc_applied`` and
|
||||||
``mjData.xfrc_applied`` respectively).
|
``mjData.xfrc_applied`` respectively).
|
||||||
|
|
||||||
Optionally, the :ref:`actearly<actuator-general-actearly>` attribute on an actuator computes ``mjData.qfrc_actuator``
|
|
||||||
based on the value of :math:`w_{i+1}` after integration, reducing the delay between changes to :math:`u` and
|
|
||||||
:math:`t`.
|
|
||||||
|
|
||||||
.. _gePassive:
|
.. _gePassive:
|
||||||
|
|
||||||
Passive forces
|
Passive forces
|
||||||
|
|||||||
@@ -732,6 +732,7 @@ struct mjOption_ { // physics options
|
|||||||
int mpr_iterations; // maximum number of MPR solver iterations
|
int mpr_iterations; // maximum number of MPR solver iterations
|
||||||
int disableflags; // bit flags for disabling standard features
|
int disableflags; // bit flags for disabling standard features
|
||||||
int enableflags; // bit flags for enabling optional features
|
int enableflags; // bit flags for enabling optional features
|
||||||
|
int disableactuator; // bit flags for disabling actuators by group id
|
||||||
|
|
||||||
// sdf collision settings
|
// sdf collision settings
|
||||||
int sdf_initpoints; // number of starting points for gradient descent
|
int sdf_initpoints; // number of starting points for gradient descent
|
||||||
|
|||||||
+105
-62
@@ -190,7 +190,7 @@ element, it must be undefined in the active defaults class.
|
|||||||
|
|
||||||
A final twist here is actuators. They are different because some of the actuator-related elements are actually
|
A final twist here is actuators. They are different because some of the actuator-related elements are actually
|
||||||
shortcuts, and shortcuts interact with the defaults setting mechanism in a non-obvious way. This is explained in the
|
shortcuts, and shortcuts interact with the defaults setting mechanism in a non-obvious way. This is explained in the
|
||||||
:ref:`Actuator shortcuts <CActuator>` section below.
|
:ref:`Actuator shortcuts <CActShortcuts>` section below.
|
||||||
|
|
||||||
.. _CFrame:
|
.. _CFrame:
|
||||||
|
|
||||||
@@ -567,10 +567,44 @@ general guidelines and observations:
|
|||||||
setup operation for the main PGS and Noslip PGS is the same, thus the setup cost is paid only once when both are
|
setup operation for the main PGS and Noslip PGS is the same, thus the setup cost is paid only once when both are
|
||||||
enabled.
|
enabled.
|
||||||
|
|
||||||
.. _CActuator:
|
.. _CActuators:
|
||||||
|
|
||||||
Actuator shortcuts
|
Actuators
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
|
This section describes various aspects of using actuators in MuJoCo. See the :ref:`Actuation model <geActuation>`
|
||||||
|
regarding the computational model.
|
||||||
|
|
||||||
|
.. _CActDisable:
|
||||||
|
|
||||||
|
Group disable
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The :ref:`actuatorgroupdisable<option-actuatorgroupdisable>` attribute, which can be changed at runtime by setting the
|
||||||
|
:ref:`mjOption.disableactuator<mjOption>` integer bitfield, allows the user to disable sets of actuators according to
|
||||||
|
their :ref:`group<actuator-general-group>`. This feature is convenient when one would like to use multiple types of
|
||||||
|
actuators for the same kinematic tree. For example consider a robot with firmware that supports mutiple control modes
|
||||||
|
e.g., torque-control and position-control. In this case, one can define both types of actuators in the same MJCF
|
||||||
|
model, assigning one type of actuator to group 0 and the other to group 1.
|
||||||
|
|
||||||
|
.. youtube:: H9qG9Zf2W44
|
||||||
|
:align: right
|
||||||
|
:width: 40%
|
||||||
|
|
||||||
|
The :ref:`actuatorgroupdisable<option-actuatorgroupdisable>` MJCF attribute selects which groups are disabled by
|
||||||
|
default, and :ref:`mjOption.disableactuator<mjOption>` can be set at runtime to switch the active set. Note that the
|
||||||
|
total number of actuators ``mjModel.nu`` remains unchanged, as do the actuator indices, so it is up to the user to know
|
||||||
|
that the respective ``mjData.ctrl`` values of disabled actuators will be ignored and produce no force. `This example
|
||||||
|
model <https://github.com/google-deepmind/mujoco/blob/main/test/engine/testdata/actuation/actuator_group_disable.xml>`__
|
||||||
|
has three actuator groups which can be toggled at runtime in the :ref:`simulate<saSimulate>` interactive viewer.
|
||||||
|
See `example model
|
||||||
|
<https://github.com/google-deepmind/mujoco/blob/main/test/engine/testdata/actuation/actuator_group_disable.xml>`__
|
||||||
|
and associated screen-capture on the right.
|
||||||
|
|
||||||
|
.. _CActShortcuts:
|
||||||
|
|
||||||
|
Shortcuts
|
||||||
|
^^^^^^^^^
|
||||||
|
|
||||||
As explained in the :ref:`Actuation model <geActuation>` section of the Computation chapter, MuJoCo offers a flexible
|
As explained in the :ref:`Actuation model <geActuation>` section of the Computation chapter, MuJoCo offers a flexible
|
||||||
actuator model with transmission, activation dynamics and force generation components that can be specified
|
actuator model with transmission, activation dynamics and force generation components that can be specified
|
||||||
@@ -605,8 +639,8 @@ explicitly.
|
|||||||
|
|
||||||
.. _CForceRange:
|
.. _CForceRange:
|
||||||
|
|
||||||
Actuator force clamping
|
Force limits
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
Actuator forces are usually limited between lower and upper bounds. These limits can be enforced in three ways:
|
Actuator forces are usually limited between lower and upper bounds. These limits can be enforced in three ways:
|
||||||
|
|
||||||
@@ -645,62 +679,14 @@ Force clamping at joint input with :ref:`joint/actuatorfrcrange<body-joint-actua
|
|||||||
|
|
||||||
The three clamping options above are non-exclusive and can be combined as required.
|
The three clamping options above are non-exclusive and can be combined as required.
|
||||||
|
|
||||||
.. _CActRange:
|
|
||||||
|
|
||||||
Activation clamping
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
As described in the :ref:`Actuation model <geActuation>` section of the Computation chapter, MuJoCo supports actuators
|
|
||||||
with internal dynamics whose states are called "activations". One useful application of these stateful actuators is the
|
|
||||||
"integrated-velocity" actuator, implemented by the :ref:`intvelocity<actuator-intvelocity>` shortcut. Different from the
|
|
||||||
:ref:`pure velocity<actuator-velocity>` actuators, which implement direct feedback on transmission target's velocity,
|
|
||||||
*integrated-velocity* actuators couple an *integrator* with a *position-feedback* actuator. In this case the semantics
|
|
||||||
of the activation state are "the setpoint of the position actuator", and the semantics of the control signal are "the
|
|
||||||
velocity of the setpoint of the position actuator". Note that in real robotic systems this integrated-velocity actuator
|
|
||||||
is the most common implementation of actuators with velocity semantics, rather than pure feedback on velocity which is
|
|
||||||
often quite unstable (both in real life and in simulation).
|
|
||||||
|
|
||||||
In the case of integrated-velocity actuators, it is often desirable to *clamp* the activation state, since otherwise the
|
|
||||||
position target would keep integrating beyond the joint limits, leading to loss of controllabillity. To see the effect
|
|
||||||
of activation clamping, load the example model below:
|
|
||||||
|
|
||||||
.. code-block:: xml
|
|
||||||
|
|
||||||
<mujoco>
|
|
||||||
<default>
|
|
||||||
<joint axis="0 0 1" limited="true" range="-90 90" damping="0.3"/>
|
|
||||||
<geom size=".1 .1 .1" type="box"/>
|
|
||||||
</default>
|
|
||||||
|
|
||||||
<worldbody>
|
|
||||||
<body>
|
|
||||||
<joint name="joint1"/>
|
|
||||||
<geom/>
|
|
||||||
</body>
|
|
||||||
<body pos=".3 0 0">
|
|
||||||
<joint name="joint2"/>
|
|
||||||
<geom/>
|
|
||||||
</body>
|
|
||||||
</worldbody>
|
|
||||||
|
|
||||||
<actuator>
|
|
||||||
<general name="unclamped" joint="joint1" gainprm="1" biastype="affine"
|
|
||||||
biasprm="0 -1" dyntype="integrator"/>
|
|
||||||
<intvelocity name="clamped" joint="joint2" actrange="-1.57 1.57"/>
|
|
||||||
</actuator>
|
|
||||||
</mujoco>
|
|
||||||
|
|
||||||
Note that the :at:`actrange` attribute is always specified in native units (radians), even though the joint range
|
|
||||||
can be either in degrees (the default) or radians, depending on the :ref:`compiler/angle <compiler>` attribute.
|
|
||||||
|
|
||||||
.. _CLengthRange:
|
.. _CLengthRange:
|
||||||
|
|
||||||
Actuator length range
|
Length range
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
As of MuJoCo 2.0, the field mjModel.actuator_lengthrange contains the range of feasible actuator lengths (or more
|
The field ``mjModel.actuator_lengthrange`` contains the range of feasible actuator lengths (or more
|
||||||
precisely, lengths of the actuator's transmission). This is needed to simulate :ref:`muscle actuators <CMuscle>` as
|
precisely, lengths of the actuator's transmission). This is needed to simulate :ref:`muscle actuators <CMuscle>`.
|
||||||
explained below. Here we focus on what actuator_lengthrange means and how to set it.
|
Here we focus on what actuator_lengthrange means and how to set it.
|
||||||
|
|
||||||
Unlike all other fields of mjModel which are exact physical or geometric quantities, actuator_lengthrange is an
|
Unlike all other fields of mjModel which are exact physical or geometric quantities, actuator_lengthrange is an
|
||||||
approximation. Intuitively it corresponds to the minimum and maximum length that the actuator's transmission can reach
|
approximation. Intuitively it corresponds to the minimum and maximum length that the actuator's transmission can reach
|
||||||
@@ -744,12 +730,69 @@ practice length ranges will almost always be used with muscle actuators attached
|
|||||||
joint limits defined in the model, effectively limiting the lengths of the muscle actuators. If you get a convergence
|
joint limits defined in the model, effectively limiting the lengths of the muscle actuators. If you get a convergence
|
||||||
error in such a model, the most likely explanation is that you forgot to include joint limits.
|
error in such a model, the most likely explanation is that you forgot to include joint limits.
|
||||||
|
|
||||||
|
.. _CActivation:
|
||||||
|
|
||||||
|
Stateful actuators
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
As described in the :ref:`Actuation model <geActuation>` section of the Computation chapter, MuJoCo supports actuators
|
||||||
|
with internal dynamics whose states are called "activations".
|
||||||
|
|
||||||
|
.. _CActRange:
|
||||||
|
|
||||||
|
Activation limits
|
||||||
|
'''''''''''''''''
|
||||||
|
|
||||||
|
One useful application of stateful actuators is the
|
||||||
|
"integrated-velocity" actuator, implemented by the :ref:`intvelocity<actuator-intvelocity>` shortcut. Different from the
|
||||||
|
:ref:`pure velocity<actuator-velocity>` actuators, which implement direct feedback on transmission target's velocity,
|
||||||
|
*integrated-velocity* actuators couple an *integrator* with a *position-feedback* actuator. In this case the semantics
|
||||||
|
of the activation state are "the setpoint of the position actuator", and the semantics of the control signal are "the
|
||||||
|
velocity of the setpoint of the position actuator". Note that in real robotic systems this integrated-velocity actuator
|
||||||
|
is the most common implementation of actuators with velocity semantics, rather than pure feedback on velocity which is
|
||||||
|
often quite unstable (both in real life and in simulation).
|
||||||
|
|
||||||
|
In the case of integrated-velocity actuators, it is often desirable to *clamp* the activation state, since otherwise the
|
||||||
|
position target would keep integrating beyond the joint limits, leading to loss of controllabillity. To see the effect
|
||||||
|
of activation clamping, load the example model below:
|
||||||
|
|
||||||
|
.. collapse:: Example model with activation limits
|
||||||
|
|
||||||
|
.. code-block:: xml
|
||||||
|
|
||||||
|
<mujoco>
|
||||||
|
<default>
|
||||||
|
<joint axis="0 0 1" limited="true" range="-90 90" damping="0.3"/>
|
||||||
|
<geom size=".1 .1 .1" type="box"/>
|
||||||
|
</default>
|
||||||
|
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<joint name="joint1"/>
|
||||||
|
<geom/>
|
||||||
|
</body>
|
||||||
|
<body pos=".3 0 0">
|
||||||
|
<joint name="joint2"/>
|
||||||
|
<geom/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
|
||||||
|
<actuator>
|
||||||
|
<general name="unclamped" joint="joint1" gainprm="1" biastype="affine"
|
||||||
|
biasprm="0 -1" dyntype="integrator"/>
|
||||||
|
<intvelocity name="clamped" joint="joint2" actrange="-1.57 1.57"/>
|
||||||
|
</actuator>
|
||||||
|
</mujoco>
|
||||||
|
|
||||||
|
Note that the :at:`actrange` attribute is always specified in native units (radians), even though the joint range
|
||||||
|
can be either in degrees (the default) or radians, depending on the :ref:`compiler/angle <compiler>` attribute.
|
||||||
|
|
||||||
.. _CMuscle:
|
.. _CMuscle:
|
||||||
|
|
||||||
Muscle actuators
|
Muscles
|
||||||
~~~~~~~~~~~~~~~~
|
'''''''
|
||||||
|
|
||||||
As of MuJoCo 2.0, we provide a set of tools for modeling biological muscles. Users who want to add muscles with minimum
|
MuJoCo 2.0 provides a set of tools for modeling biological muscles. Users who want to add muscles with minimum
|
||||||
effort can do so with a single line of XML in the actuator section:
|
effort can do so with a single line of XML in the actuator section:
|
||||||
|
|
||||||
.. code-block:: xml
|
.. code-block:: xml
|
||||||
|
|||||||
@@ -34,6 +34,9 @@
|
|||||||
#define mjDISABLED(x) (m->opt.disableflags & (x))
|
#define mjDISABLED(x) (m->opt.disableflags & (x))
|
||||||
#define mjENABLED(x) (m->opt.enableflags & (x))
|
#define mjENABLED(x) (m->opt.enableflags & (x))
|
||||||
|
|
||||||
|
// is actuator disabled
|
||||||
|
#define mjACTUATORDISABLED(i) (m->opt.disableactuator & (1 << m->actuator_group[i]))
|
||||||
|
|
||||||
// annotation for functions that accept printf-like variadic arguments
|
// annotation for functions that accept printf-like variadic arguments
|
||||||
#ifndef mjPRINTFLIKE
|
#ifndef mjPRINTFLIKE
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
|
|||||||
@@ -433,6 +433,7 @@ struct mjOption_ { // physics options
|
|||||||
int mpr_iterations; // maximum number of MPR solver iterations
|
int mpr_iterations; // maximum number of MPR solver iterations
|
||||||
int disableflags; // bit flags for disabling standard features
|
int disableflags; // bit flags for disabling standard features
|
||||||
int enableflags; // bit flags for enabling optional features
|
int enableflags; // bit flags for enabling optional features
|
||||||
|
int disableactuator; // bit flags for disabling actuators by group id
|
||||||
|
|
||||||
// sdf collision settings
|
// sdf collision settings
|
||||||
int sdf_initpoints; // number of starting points for gradient descent
|
int sdf_initpoints; // number of starting points for gradient descent
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
X( int, mpr_iterations ) \
|
X( int, mpr_iterations ) \
|
||||||
X( int, disableflags ) \
|
X( int, disableflags ) \
|
||||||
X( int, enableflags ) \
|
X( int, enableflags ) \
|
||||||
|
X( int, disableactuator ) \
|
||||||
X( int, sdf_initpoints ) \
|
X( int, sdf_initpoints ) \
|
||||||
X( int, sdf_iterations )
|
X( int, sdf_iterations )
|
||||||
|
|
||||||
|
|||||||
@@ -276,6 +276,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='int'),
|
type=ValueType(name='int'),
|
||||||
doc='bit flags for enabling optional features',
|
doc='bit flags for enabling optional features',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='disableactuator',
|
||||||
|
type=ValueType(name='int'),
|
||||||
|
doc='bit flags for disabling actuators by group id',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='sdf_initpoints',
|
name='sdf_initpoints',
|
||||||
type=ValueType(name='int'),
|
type=ValueType(name='int'),
|
||||||
|
|||||||
+71
-14
@@ -716,6 +716,16 @@ void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
|
|||||||
{mjITEM_EDITNUM, "Friction", 2, &(opt->o_friction), "5"},
|
{mjITEM_EDITNUM, "Friction", 2, &(opt->o_friction), "5"},
|
||||||
{mjITEM_END}
|
{mjITEM_END}
|
||||||
};
|
};
|
||||||
|
mjuiDef defDisableActuator[] = {
|
||||||
|
{mjITEM_SEPARATOR, "Actuator Group Enable", 1},
|
||||||
|
{mjITEM_CHECKBYTE, "Act Group 0", 2, sim->enableactuator+0, " 0"},
|
||||||
|
{mjITEM_CHECKBYTE, "Act Group 1", 2, sim->enableactuator+1, " 1"},
|
||||||
|
{mjITEM_CHECKBYTE, "Act Group 2", 2, sim->enableactuator+2, " 2"},
|
||||||
|
{mjITEM_CHECKBYTE, "Act Group 3", 2, sim->enableactuator+3, " 3"},
|
||||||
|
{mjITEM_CHECKBYTE, "Act Group 4", 2, sim->enableactuator+4, " 4"},
|
||||||
|
{mjITEM_CHECKBYTE, "Act Group 5", 2, sim->enableactuator+5, " 5"},
|
||||||
|
{mjITEM_END}
|
||||||
|
};
|
||||||
|
|
||||||
// add physics
|
// add physics
|
||||||
mjui_add(&sim->ui0, defPhysics);
|
mjui_add(&sim->ui0, defPhysics);
|
||||||
@@ -736,9 +746,11 @@ void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
|
|||||||
defFlag[0].pdata = sim->enable + i;
|
defFlag[0].pdata = sim->enable + i;
|
||||||
mjui_add(&sim->ui0, defFlag);
|
mjui_add(&sim->ui0, defFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add contact override
|
// add contact override
|
||||||
mjui_add(&sim->ui0, defOverride);
|
mjui_add(&sim->ui0, defOverride);
|
||||||
|
|
||||||
|
// add actuator group enable/disable
|
||||||
|
mjui_add(&sim->ui0, defDisableActuator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1002,7 +1014,7 @@ void MakeJointSection(mj::Simulate* sim, int oldstate) {
|
|||||||
|
|
||||||
// add scalar joints, exit if UI limit reached
|
// add scalar joints, exit if UI limit reached
|
||||||
int itemcnt = 0;
|
int itemcnt = 0;
|
||||||
for (int i=0; i < sim->jnt_type_.size() && itemcnt<mjMAXUIITEM; i++)
|
for (int i=0; i < sim->jnt_type_.size() && itemcnt<mjMAXUIITEM; i++) {
|
||||||
if ((sim->jnt_type_[i]==mjJNT_HINGE || sim->jnt_type_[i]==mjJNT_SLIDE)) {
|
if ((sim->jnt_type_[i]==mjJNT_HINGE || sim->jnt_type_[i]==mjJNT_SLIDE)) {
|
||||||
// skip if joint group is disabled
|
// skip if joint group is disabled
|
||||||
if (!sim->opt.jointgroup[mjMAX(0, mjMIN(mjNGROUP-1, sim->jnt_group_[i]))]) {
|
if (!sim->opt.jointgroup[mjMAX(0, mjMIN(mjNGROUP-1, sim->jnt_group_[i]))]) {
|
||||||
@@ -1035,6 +1047,7 @@ void MakeJointSection(mj::Simulate* sim, int oldstate) {
|
|||||||
mjui_add(&sim->ui1, defSlider);
|
mjui_add(&sim->ui1, defSlider);
|
||||||
itemcnt++;
|
itemcnt++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make control section of UI
|
// make control section of UI
|
||||||
@@ -1051,15 +1064,21 @@ void MakeControlSection(mj::Simulate* sim, int oldstate) {
|
|||||||
|
|
||||||
// add section
|
// add section
|
||||||
mjui_add(&sim->ui1, defControl);
|
mjui_add(&sim->ui1, defControl);
|
||||||
defSlider[0].state = 2;
|
|
||||||
|
|
||||||
// add controls, exit if UI limit reached (Clear button already added)
|
// add controls, exit if UI limit reached (Clear button already added)
|
||||||
int itemcnt = 1;
|
int itemcnt = 1;
|
||||||
for (int i=0; i < sim->actuator_ctrlrange_.size() && itemcnt<mjMAXUIITEM; i++) {
|
for (int i=0; i < sim->actuator_ctrlrange_.size() && itemcnt<mjMAXUIITEM; i++) {
|
||||||
// skip if actuator group is disabled
|
// skip if actuator vis group is disabled
|
||||||
if (!sim->opt.actuatorgroup[mjMAX(0, mjMIN(mjNGROUP-1, sim->actuator_group_[i]))]) {
|
int group = sim->actuator_group_[i];
|
||||||
|
if (!sim->opt.actuatorgroup[mjMAX(0, mjMIN(mjNGROUP-1, group))]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// grey out if actuator group is disabled
|
||||||
|
if (group >= 0 && group <= 30 && sim->m_->opt.disableactuator & (1 << group)) {
|
||||||
|
defSlider[0].state = 0;
|
||||||
|
} else {
|
||||||
|
defSlider[0].state = 2;
|
||||||
|
}
|
||||||
|
|
||||||
// set data and name
|
// set data and name
|
||||||
if (!sim->is_passive_) {
|
if (!sim->is_passive_) {
|
||||||
@@ -1189,19 +1208,27 @@ void CopyCamera(mj::Simulate* sim) {
|
|||||||
void UpdateSettings(mj::Simulate* sim, const mjModel* m) {
|
void UpdateSettings(mj::Simulate* sim, const mjModel* m) {
|
||||||
// physics flags
|
// physics flags
|
||||||
for (int i=0; i<mjNDISABLE; i++) {
|
for (int i=0; i<mjNDISABLE; i++) {
|
||||||
int new_value = ((m->opt.disableflags & (1<<i)) !=0);
|
int new_value = ((m->opt.disableflags & (1<<i)) != 0);
|
||||||
if (sim->disable[i] != new_value) {
|
if (sim->disable[i] != new_value) {
|
||||||
sim->disable[i] = new_value;
|
sim->disable[i] = new_value;
|
||||||
sim->pending_.ui_update_physics = true;
|
sim->pending_.ui_update_physics = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i=0; i<mjNENABLE; i++) {
|
for (int i=0; i<mjNENABLE; i++) {
|
||||||
int new_value = ((m->opt.enableflags & (1<<i)) !=0);
|
int new_value = ((m->opt.enableflags & (1<<i)) != 0);
|
||||||
if (sim->enable[i] != new_value) {
|
if (sim->enable[i] != new_value) {
|
||||||
sim->enable[i] = new_value;
|
sim->enable[i] = new_value;
|
||||||
sim->pending_.ui_update_physics = true;
|
sim->pending_.ui_update_physics = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (int i=0; i<mjNGROUP; i++) {
|
||||||
|
int enabled = ((m->opt.disableactuator & (1<<i)) == 0);
|
||||||
|
if (sim->enableactuator[i] != enabled) {
|
||||||
|
sim->enableactuator[i] = enabled;
|
||||||
|
sim->pending_.ui_update_physics = true;
|
||||||
|
sim->pending_.ui_remake_ctrl = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// camera
|
// camera
|
||||||
int old_camera = sim->camera;
|
int old_camera = sim->camera;
|
||||||
@@ -1404,17 +1431,39 @@ void UiEvent(mjuiState* state) {
|
|||||||
|
|
||||||
// update disable flags in mjOption
|
// update disable flags in mjOption
|
||||||
opt->disableflags = 0;
|
opt->disableflags = 0;
|
||||||
for (int i=0; i<mjNDISABLE; i++)
|
for (int i=0; i<mjNDISABLE; i++) {
|
||||||
if (sim->disable[i]) {
|
if (sim->disable[i]) {
|
||||||
opt->disableflags |= (1<<i);
|
opt->disableflags |= (1<<i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update enable flags in mjOption
|
// update enable flags in mjOption
|
||||||
opt->enableflags = 0;
|
opt->enableflags = 0;
|
||||||
for (int i=0; i<mjNENABLE; i++)
|
for (int i=0; i<mjNENABLE; i++) {
|
||||||
if (sim->enable[i]) {
|
if (sim->enable[i]) {
|
||||||
opt->enableflags |= (1<<i);
|
opt->enableflags |= (1<<i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update disableactuator bitflag in mjOption
|
||||||
|
bool group_changed = false;
|
||||||
|
for (int i=0; i<mjNGROUP; i++) {
|
||||||
|
if ((!sim->enableactuator[i]) != (opt->disableactuator & (1<<i))) {
|
||||||
|
group_changed = true;
|
||||||
|
if (!sim->enableactuator[i]) {
|
||||||
|
// disable actuator group i
|
||||||
|
opt->disableactuator |= (1<<i);
|
||||||
|
} else {
|
||||||
|
// enable actuator group i
|
||||||
|
opt->disableactuator &= ~(1<<i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remake control section if actuator disable group changed
|
||||||
|
if (group_changed) {
|
||||||
|
sim->pending_.ui_remake_ctrl = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rendering section
|
// rendering section
|
||||||
@@ -1461,10 +1510,7 @@ void UiEvent(mjuiState* state) {
|
|||||||
|
|
||||||
// remake control section if actuator group changed
|
// remake control section if actuator group changed
|
||||||
if (it->name[0]=='A' && it->name[1]=='c') {
|
if (it->name[0]=='A' && it->name[1]=='c') {
|
||||||
sim->ui1.nsect = SECT_CONTROL;
|
sim->pending_.ui_remake_ctrl = true;
|
||||||
MakeControlSection(sim, sim->ui1.sect[SECT_CONTROL].state);
|
|
||||||
sim->ui1.nsect = NSECT1;
|
|
||||||
UiModify(&sim->ui1, state, &sim->platform_ui->mjr_context());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1790,7 +1836,7 @@ void Simulate::Sync() {
|
|||||||
range.emplace(m_->actuator_ctrlrange[2*i], m_->actuator_ctrlrange[2*i + 1]);
|
range.emplace(m_->actuator_ctrlrange[2*i], m_->actuator_ctrlrange[2*i + 1]);
|
||||||
}
|
}
|
||||||
if (actuator_ctrlrange_[i] != range) {
|
if (actuator_ctrlrange_[i] != range) {
|
||||||
pending_.ui_update_ctrl = true;
|
pending_.ui_remake_ctrl = true;
|
||||||
actuator_ctrlrange_[i].swap(range);
|
actuator_ctrlrange_[i].swap(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1851,6 +1897,7 @@ void Simulate::Sync() {
|
|||||||
X(mpr_iterations);
|
X(mpr_iterations);
|
||||||
X(disableflags);
|
X(disableflags);
|
||||||
X(enableflags);
|
X(enableflags);
|
||||||
|
X(disableactuator);
|
||||||
X(sdf_initpoints);
|
X(sdf_initpoints);
|
||||||
X(sdf_iterations);
|
X(sdf_iterations);
|
||||||
|
|
||||||
@@ -2399,6 +2446,16 @@ void Simulate::Render() {
|
|||||||
pending_.ui_update_joint = false;
|
pending_.ui_update_joint = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pending_.ui_remake_ctrl) {
|
||||||
|
if (this->ui1_enable && this->ui1.sect[SECT_CONTROL].state) {
|
||||||
|
this->ui1.nsect = SECT_CONTROL;
|
||||||
|
MakeControlSection(this, this->ui1.sect[SECT_CONTROL].state);
|
||||||
|
this->ui1.nsect = NSECT1;
|
||||||
|
UiModify(&this->ui1, &this->uistate, &this->platform_ui->mjr_context());
|
||||||
|
}
|
||||||
|
pending_.ui_remake_ctrl = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (pending_.ui_update_ctrl) {
|
if (pending_.ui_update_ctrl) {
|
||||||
if (this->ui1_enable && this->ui1.sect[SECT_CONTROL].state) {
|
if (this->ui1_enable && this->ui1.sect[SECT_CONTROL].state) {
|
||||||
mjui_update(SECT_CONTROL, -1, &this->ui1, &this->uistate, &this->platform_ui->mjr_context());
|
mjui_update(SECT_CONTROL, -1, &this->ui1, &this->uistate, &this->platform_ui->mjr_context());
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ class Simulate {
|
|||||||
bool ui_update_rendering;
|
bool ui_update_rendering;
|
||||||
bool ui_update_joint;
|
bool ui_update_joint;
|
||||||
bool ui_update_ctrl;
|
bool ui_update_ctrl;
|
||||||
|
bool ui_remake_ctrl;
|
||||||
} pending_ = {};
|
} pending_ = {};
|
||||||
|
|
||||||
SimulateMutex mtx;
|
SimulateMutex mtx;
|
||||||
@@ -228,6 +229,7 @@ class Simulate {
|
|||||||
// physics: need sync
|
// physics: need sync
|
||||||
int disable[mjNDISABLE] = {0};
|
int disable[mjNDISABLE] = {0};
|
||||||
int enable[mjNENABLE] = {0};
|
int enable[mjNENABLE] = {0};
|
||||||
|
int enableactuator[mjNGROUP] = {0};
|
||||||
|
|
||||||
// rendering: need sync
|
// rendering: need sync
|
||||||
int camera = 0;
|
int camera = 0;
|
||||||
|
|||||||
@@ -213,6 +213,8 @@ void mj_fwdVelocity(const mjModel* m, mjData* d) {
|
|||||||
TM_END(mjTIMER_VELOCITY);
|
TM_END(mjTIMER_VELOCITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// returns the next act given the current act_dot, after clamping
|
// returns the next act given the current act_dot, after clamping
|
||||||
static mjtNum nextActivation(const mjModel* m, const mjData* d,
|
static mjtNum nextActivation(const mjModel* m, const mjData* d,
|
||||||
int actuator_id, int act_adr, mjtNum act_dot) {
|
int actuator_id, int act_adr, mjtNum act_dot) {
|
||||||
@@ -239,6 +241,8 @@ static mjtNum nextActivation(const mjModel* m, const mjData* d,
|
|||||||
return act;
|
return act;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// (qpos, qvel, ctrl, act) => (qfrc_actuator, actuator_force, act_dot)
|
// (qpos, qvel, ctrl, act) => (qfrc_actuator, actuator_force, act_dot)
|
||||||
void mj_fwdActuation(const mjModel* m, mjData* d) {
|
void mj_fwdActuation(const mjModel* m, mjData* d) {
|
||||||
TM_START;
|
TM_START;
|
||||||
@@ -246,12 +250,12 @@ void mj_fwdActuation(const mjModel* m, mjData* d) {
|
|||||||
mjtNum gain, bias, tau;
|
mjtNum gain, bias, tau;
|
||||||
mjtNum *prm, *moment = d->actuator_moment, *force = d->actuator_force;
|
mjtNum *prm, *moment = d->actuator_moment, *force = d->actuator_force;
|
||||||
|
|
||||||
// clear outputs
|
// clear actuator_force
|
||||||
mju_zero(d->qfrc_actuator, nv);
|
mju_zero(force, nu);
|
||||||
mju_zero(d->actuator_force, nu);
|
|
||||||
|
|
||||||
// disabled or no actuation: return
|
// disabled or no actuation: return
|
||||||
if (nu == 0 || mjDISABLED(mjDSBL_ACTUATION)) {
|
if (nu == 0 || mjDISABLED(mjDSBL_ACTUATION)) {
|
||||||
|
mju_zero(d->qfrc_actuator, nv);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,6 +332,11 @@ void mj_fwdActuation(const mjModel* m, mjData* d) {
|
|||||||
|
|
||||||
// force = gain .* [ctrl/act] + bias
|
// force = gain .* [ctrl/act] + bias
|
||||||
for (int i=0; i < nu; i++) {
|
for (int i=0; i < nu; i++) {
|
||||||
|
// skip if disabled
|
||||||
|
if (mj_actuatorDisabled(m, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// skip actuator plugins -- these are handled after builtin actuator types
|
// skip actuator plugins -- these are handled after builtin actuator types
|
||||||
if (m->actuator_plugin[i] >= 0) {
|
if (m->actuator_plugin[i] >= 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -457,7 +466,6 @@ void mj_fwdActuation(const mjModel* m, mjData* d) {
|
|||||||
|
|
||||||
// add up all non-constraint forces, compute qacc_smooth
|
// add up all non-constraint forces, compute qacc_smooth
|
||||||
void mj_fwdAcceleration(const mjModel* m, mjData* d) {
|
void mj_fwdAcceleration(const mjModel* m, mjData* d) {
|
||||||
mj_markStack(d);
|
|
||||||
int nv = m->nv;
|
int nv = m->nv;
|
||||||
|
|
||||||
// qforce = sum of all non-constraint forces
|
// qforce = sum of all non-constraint forces
|
||||||
@@ -468,8 +476,6 @@ void mj_fwdAcceleration(const mjModel* m, mjData* d) {
|
|||||||
|
|
||||||
// qacc_smooth = M \ qfr_smooth
|
// qacc_smooth = M \ qfr_smooth
|
||||||
mj_solveM(m, d, d->qacc_smooth, d->qfrc_smooth, 1);
|
mj_solveM(m, d, d->qacc_smooth, d->qfrc_smooth, 1);
|
||||||
|
|
||||||
mj_freeStack(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -685,7 +691,8 @@ static void mj_advance(const mjModel* m, mjData* d,
|
|||||||
int actadr = m->actuator_actadr[i];
|
int actadr = m->actuator_actadr[i];
|
||||||
int actadr_end = actadr + m->actuator_actnum[i];
|
int actadr_end = actadr + m->actuator_actnum[i];
|
||||||
for (int j=actadr; j < actadr_end; j++) {
|
for (int j=actadr; j < actadr_end; j++) {
|
||||||
d->act[j] = nextActivation(m, d, i, j, act_dot[j]);
|
// if disabled, set act_dot to 0
|
||||||
|
d->act[j] = nextActivation(m, d, i, j, mj_actuatorDisabled(m, i) ? 0 : act_dot[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ void mj_defaultOption(mjOption* opt) {
|
|||||||
opt->mpr_iterations = 50;
|
opt->mpr_iterations = 50;
|
||||||
opt->disableflags = 0;
|
opt->disableflags = 0;
|
||||||
opt->enableflags = 0;
|
opt->enableflags = 0;
|
||||||
|
opt->disableactuator = 0;
|
||||||
|
|
||||||
// sdf collisions
|
// sdf collisions
|
||||||
opt->sdf_initpoints = 40;
|
opt->sdf_initpoints = 40;
|
||||||
|
|||||||
@@ -1784,7 +1784,15 @@ void mj_local2Global(mjData* d, mjtNum xpos[3], mjtNum xmat[9],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return 1 if actuator i is disabled, 0 otherwise
|
||||||
|
int mj_actuatorDisabled(const mjModel* m, int i) {
|
||||||
|
int group = m->actuator_group[i];
|
||||||
|
if (group < 0 || group > 30) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return m->opt.disableactuator & (1 << group) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sum all body masses
|
// sum all body masses
|
||||||
mjtNum mj_getTotalmass(const mjModel* m) {
|
mjtNum mj_getTotalmass(const mjModel* m) {
|
||||||
|
|||||||
@@ -204,6 +204,9 @@ MJAPI void mj_local2Global(mjData* d, mjtNum xpos[3], mjtNum xmat[9],
|
|||||||
const mjtNum pos[3], const mjtNum quat[4],
|
const mjtNum pos[3], const mjtNum quat[4],
|
||||||
int body, mjtByte sameframe);
|
int body, mjtByte sameframe);
|
||||||
|
|
||||||
|
// return 1 if actuator i is disabled, 0 otherwise
|
||||||
|
MJAPI int mj_actuatorDisabled(const mjModel* m, int i);
|
||||||
|
|
||||||
// sum all body masses
|
// sum all body masses
|
||||||
MJAPI mjtNum mj_getTotalmass(const mjModel* m);
|
MJAPI mjtNum mj_getTotalmass(const mjModel* m);
|
||||||
|
|
||||||
|
|||||||
@@ -1072,6 +1072,11 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
|
|||||||
if (vopt->flags[mjVIS_ACTUATOR] && (category & catmask)) {
|
if (vopt->flags[mjVIS_ACTUATOR] && (category & catmask)) {
|
||||||
for (int i=0; i < m->nu; i++) {
|
for (int i=0; i < m->nu; i++) {
|
||||||
if (vopt->actuatorgroup[mjMAX(0, mjMIN(mjNGROUP-1, m->actuator_group[i]))]) {
|
if (vopt->actuatorgroup[mjMAX(0, mjMIN(mjNGROUP-1, m->actuator_group[i]))]) {
|
||||||
|
// skip if disabled
|
||||||
|
if (mj_actuatorDisabled(m, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// determine extended range
|
// determine extended range
|
||||||
mjtNum rng[3] = {-1, 0, +1};
|
mjtNum rng[3] = {-1, 0, +1};
|
||||||
mjtNum rmin = -1, rmax = 1, act = 0;
|
mjtNum rmin = -1, rmax = 1, act = 0;
|
||||||
|
|||||||
@@ -93,13 +93,13 @@ static const char* MJCF[nMJCF][mjXATTRNUM] = {
|
|||||||
"inttotal", "interval", "tolrange"},
|
"inttotal", "interval", "tolrange"},
|
||||||
{">"},
|
{">"},
|
||||||
|
|
||||||
{"option", "*", "26",
|
{"option", "*", "27",
|
||||||
"timestep", "apirate", "impratio", "tolerance", "ls_tolerance", "noslip_tolerance",
|
"timestep", "apirate", "impratio", "tolerance", "ls_tolerance", "noslip_tolerance",
|
||||||
"mpr_tolerance", "gravity", "wind", "magnetic", "density", "viscosity",
|
"mpr_tolerance", "gravity", "wind", "magnetic", "density", "viscosity",
|
||||||
"o_margin", "o_solref", "o_solimp", "o_friction",
|
"o_margin", "o_solref", "o_solimp", "o_friction",
|
||||||
"integrator", "cone", "jacobian",
|
"integrator", "cone", "jacobian",
|
||||||
"solver", "iterations", "ls_iterations", "noslip_iterations", "mpr_iterations",
|
"solver", "iterations", "ls_iterations", "noslip_iterations", "mpr_iterations",
|
||||||
"sdf_iterations", "sdf_initpoints"},
|
"sdf_iterations", "sdf_initpoints", "actuatorgroupdisable"},
|
||||||
{"<"},
|
{"<"},
|
||||||
{"flag", "?", "22", "constraint", "equality", "frictionloss", "limit", "contact",
|
{"flag", "?", "22", "constraint", "equality", "frictionloss", "limit", "contact",
|
||||||
"passive", "gravity", "clampctrl", "warmstart",
|
"passive", "gravity", "clampctrl", "warmstart",
|
||||||
@@ -1036,6 +1036,22 @@ void mjXReader::Option(XMLElement* section, mjOption* opt) {
|
|||||||
ReadAttrInt(section, "sdf_iterations", &opt->sdf_iterations);
|
ReadAttrInt(section, "sdf_iterations", &opt->sdf_iterations);
|
||||||
ReadAttrInt(section, "sdf_initpoints", &opt->sdf_initpoints);
|
ReadAttrInt(section, "sdf_initpoints", &opt->sdf_initpoints);
|
||||||
|
|
||||||
|
// actuatorgroupdisable
|
||||||
|
constexpr int num_bitflags = 31;
|
||||||
|
int disabled_act_groups[num_bitflags];
|
||||||
|
int num_found = ReadAttr(section, "actuatorgroupdisable", num_bitflags, disabled_act_groups,
|
||||||
|
text, false, false);
|
||||||
|
for (int i=0; i < num_found; i++) {
|
||||||
|
int group = disabled_act_groups[i];
|
||||||
|
if (group < 0 ) {
|
||||||
|
throw mjXError(section, "disabled actuator group value must be non-negative");
|
||||||
|
}
|
||||||
|
if (group > num_bitflags - 1) {
|
||||||
|
throw mjXError(section, "disabled actuator group value cannot exceed 30");
|
||||||
|
}
|
||||||
|
opt->disableactuator |= (1 << group);
|
||||||
|
}
|
||||||
|
|
||||||
// read disable sub-element
|
// read disable sub-element
|
||||||
XMLElement* elem = FindSubElem(section, "flag");
|
XMLElement* elem = FindSubElem(section, "flag");
|
||||||
if (elem) {
|
if (elem) {
|
||||||
|
|||||||
@@ -909,6 +909,16 @@ void mjXWriter::Option(XMLElement* root) {
|
|||||||
WriteAttrInt(section, "sdf_iterations", model->option.sdf_iterations, opt.sdf_iterations);
|
WriteAttrInt(section, "sdf_iterations", model->option.sdf_iterations, opt.sdf_iterations);
|
||||||
WriteAttrInt(section, "sdf_initpoints", model->option.sdf_initpoints, opt.sdf_initpoints);
|
WriteAttrInt(section, "sdf_initpoints", model->option.sdf_initpoints, opt.sdf_initpoints);
|
||||||
|
|
||||||
|
// actuator group disable
|
||||||
|
int disabled_groups[31];
|
||||||
|
int ndisabled = 0;
|
||||||
|
for (int i = 0; i < 31; ++i) {
|
||||||
|
if (model->option.disableactuator & (1 << i)) {
|
||||||
|
disabled_groups[ndisabled++] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WriteAttr(section, "actuatorgroupdisable", ndisabled, disabled_groups);
|
||||||
|
|
||||||
// write disable/enable flags if any of them are set; invert while writing
|
// write disable/enable flags if any of them are set; invert while writing
|
||||||
if (model->option.disableflags || model->option.enableflags) {
|
if (model->option.disableflags || model->option.enableflags) {
|
||||||
XMLElement* sub = InsertEnd(section, "flag");
|
XMLElement* sub = InsertEnd(section, "flag");
|
||||||
|
|||||||
@@ -984,5 +984,79 @@ TEST_F(ActEarlyTest, DoesntChangeStateInMjForward) {
|
|||||||
mj_deleteModel(model);
|
mj_deleteModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ActuatorTest, DisableActuator) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<joint name="slide" type="slide" axis="1 0 0"/>
|
||||||
|
<geom size="1" mass="1"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
|
||||||
|
<actuator>
|
||||||
|
<motor joint="slide" gear="2" group="0"/>
|
||||||
|
<position joint="slide" kp="1" group="1"/>
|
||||||
|
</actuator>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
mjModel* model = LoadModelFromString(xml);
|
||||||
|
mjData* data = mj_makeData(model);
|
||||||
|
|
||||||
|
data->ctrl[0] = 1.0;
|
||||||
|
data->ctrl[1] = 1.0;
|
||||||
|
|
||||||
|
mj_forward(model, data);
|
||||||
|
EXPECT_EQ(data->qfrc_actuator[0], 3.0);
|
||||||
|
|
||||||
|
model->opt.disableactuator = 1 << 0;
|
||||||
|
mj_forward(model, data);
|
||||||
|
EXPECT_EQ(data->qfrc_actuator[0], 1.0);
|
||||||
|
|
||||||
|
model->opt.disableactuator = 1 << 1;
|
||||||
|
mj_forward(model, data);
|
||||||
|
EXPECT_EQ(data->qfrc_actuator[0], 2.0);
|
||||||
|
|
||||||
|
mj_deleteData(data);
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ActuatorTest, DisableActuatorOutOfRange) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<joint name="slide" type="slide" axis="1 0 0"/>
|
||||||
|
<geom size="1" mass="1"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
|
||||||
|
<actuator>
|
||||||
|
<motor joint="slide" gear="-1" group="-1"/>
|
||||||
|
<motor joint="slide" gear="5" group="0"/>
|
||||||
|
<motor joint="slide" gear="31" group="31"/>
|
||||||
|
</actuator>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
mjModel* model = LoadModelFromString(xml);
|
||||||
|
mjData* data = mj_makeData(model);
|
||||||
|
|
||||||
|
data->ctrl[0] = 1.0;
|
||||||
|
data->ctrl[1] = 1.0;
|
||||||
|
data->ctrl[2] = 1.0;
|
||||||
|
|
||||||
|
// all actuators active
|
||||||
|
mj_forward(model, data);
|
||||||
|
EXPECT_EQ(data->qfrc_actuator[0], 35.0);
|
||||||
|
|
||||||
|
// set all bits of disableactuator, only group 1 is disabled
|
||||||
|
model->opt.disableactuator = ~0;
|
||||||
|
mj_forward(model, data);
|
||||||
|
EXPECT_EQ(data->qfrc_actuator[0], 30.0);
|
||||||
|
|
||||||
|
mj_deleteData(data);
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace mujoco
|
} // namespace mujoco
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
<mujoco>
|
||||||
|
<visual>
|
||||||
|
<global elevation="-10"/>
|
||||||
|
</visual>
|
||||||
|
|
||||||
|
<compiler angle="radian"/>
|
||||||
|
|
||||||
|
<!-- Note: actuator groups 1, 2, are disabled by default -->
|
||||||
|
<option actuatorgroupdisable="1 2" cone="elliptic"/>
|
||||||
|
|
||||||
|
<asset>
|
||||||
|
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="32" height="512"/>
|
||||||
|
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128" rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1" random="0.01"/>
|
||||||
|
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
|
||||||
|
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
|
||||||
|
<material name="grid" texture="grid" texrepeat="6 2" texuniform="false" reflectance=".2"/>
|
||||||
|
</asset>
|
||||||
|
|
||||||
|
<default>
|
||||||
|
<general ctrlrange="-1 1"/>
|
||||||
|
<geom friction=".4"/>
|
||||||
|
<default class="decor">
|
||||||
|
<geom type="cylinder" size=".03" fromto="0 -.03 0 0 .03 0" rgba="1 1 1 1"/>
|
||||||
|
</default>
|
||||||
|
<default class="arm">
|
||||||
|
<joint damping="5" axis="0 -1 0"/>
|
||||||
|
<geom type="capsule" size=".02" material="body"/>
|
||||||
|
</default>
|
||||||
|
<default class="object">
|
||||||
|
<geom type="cylinder" size="0.1" rgba="0 .9 0 1" fromto="0 -.03 0 0 .03 0"
|
||||||
|
solref="-10000 -10" priority="1"/>
|
||||||
|
<joint group="3"/>
|
||||||
|
</default>
|
||||||
|
|
||||||
|
<!-- Note: motors, position, intvelocity actuators are in groups 0, 1, 2, respectively -->
|
||||||
|
<default class="motor">
|
||||||
|
<motor group="0" gear="30" ctrlrange="-1 1"/>
|
||||||
|
</default>
|
||||||
|
<default class="position">
|
||||||
|
<position group="1" kp="60"/>
|
||||||
|
</default>
|
||||||
|
<default class="intvelocity">
|
||||||
|
<intvelocity group="2" kp="60" ctrlrange="-.5 .5"/>
|
||||||
|
</default>
|
||||||
|
</default>
|
||||||
|
|
||||||
|
<worldbody>
|
||||||
|
<geom name="floor" type="plane" size=".6 .2 0.01" material="grid"/>
|
||||||
|
<geom name="wall0" type="plane" size=".4 .2 0.01" material="grid" pos="-.6 0 .4" zaxis="1 0 0"/>
|
||||||
|
<geom name="wall1" type="plane" size=".4 .2 0.01" material="grid" pos=".6 0 .4" zaxis="-1 0 0"/>
|
||||||
|
<light pos="-.6 0 3" mode="targetbody" target="hand"/>
|
||||||
|
<light pos=".6 0 3" mode="targetbody" target="hand"/>
|
||||||
|
<body name="arm" pos="-.6 0 .6" childclass="arm">
|
||||||
|
<joint name="arm" range="-1.5 1.5"/>
|
||||||
|
<geom class="decor"/>
|
||||||
|
<geom name="arm" fromto="0 0 0 .7 0 0"/>
|
||||||
|
<body pos=".7 0 0">
|
||||||
|
<joint name="hand" range="-4.65 1.5"/>
|
||||||
|
<geom class="decor"/>
|
||||||
|
<geom fromto="0 0 0 0 0 0.4"/>
|
||||||
|
<body name="hand" pos="0 0 0.4">
|
||||||
|
<geom name="hand" type="sphere" size=".06" mass="0"/>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body childclass="object" pos="-.3 0 .2">
|
||||||
|
<joint axis="1 0 0" type="slide"/>
|
||||||
|
<joint axis="0 0 1" type="slide"/>
|
||||||
|
<joint axis="0 1 0"/>
|
||||||
|
<geom/>
|
||||||
|
</body>
|
||||||
|
<body childclass="object" pos="-.2 0 .4">
|
||||||
|
<joint axis="1 0 0" type="slide"/>
|
||||||
|
<joint axis="0 0 1" type="slide"/>
|
||||||
|
<joint axis="0 1 0"/>
|
||||||
|
<geom/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
|
||||||
|
<contact>
|
||||||
|
<exclude body1="world" body2="arm"/>
|
||||||
|
<pair geom1="arm" geom2="hand"/>
|
||||||
|
</contact>
|
||||||
|
|
||||||
|
<actuator>
|
||||||
|
<motor class="motor" name="arm torque" joint="arm"/>
|
||||||
|
<motor class="motor" name="hand torque" joint="hand"/>
|
||||||
|
<position class="position" name="arm position" joint="arm" ctrlrange="-1.5 1.5"/>
|
||||||
|
<position class="position" name="hand position" joint="hand" ctrlrange="-1.5 4.65"/>
|
||||||
|
<intvelocity class="intvelocity" name="arm velocity" joint="arm" actrange="-1.5 1.5"/>
|
||||||
|
<intvelocity class="intvelocity" name="hand velocity" joint="hand" actrange="-1.5 4.65"/>
|
||||||
|
</actuator>
|
||||||
|
</mujoco>
|
||||||
@@ -31,6 +31,15 @@ namespace {
|
|||||||
|
|
||||||
using HeaderTest = MujocoTest;
|
using HeaderTest = MujocoTest;
|
||||||
|
|
||||||
|
TEST_F(HeaderTest, IntsHave4Bytes) {
|
||||||
|
EXPECT_EQ(4, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(HeaderTest, IntsHaveAtLeast31Bits) {
|
||||||
|
int shift_left_30 = 1 << 30;
|
||||||
|
EXPECT_GT(shift_left_30, 0);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(HeaderTest, EnumsAreInts) {
|
TEST_F(HeaderTest, EnumsAreInts) {
|
||||||
EXPECT_EQ(sizeof(mjtDisableBit), sizeof(int));
|
EXPECT_EQ(sizeof(mjtDisableBit), sizeof(int));
|
||||||
EXPECT_EQ(sizeof(mjtEnableBit), sizeof(int));
|
EXPECT_EQ(sizeof(mjtEnableBit), sizeof(int));
|
||||||
|
|||||||
@@ -1049,6 +1049,44 @@ TEST_F(ActuatorParseTest, MusclesSmoothdynNegative) {
|
|||||||
EXPECT_THAT(error.data(), HasSubstr("muscle tausmooth cannot be negative"));
|
EXPECT_THAT(error.data(), HasSubstr("muscle tausmooth cannot be negative"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ActuatorParseTest, GroupDisable) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<option actuatorgroupdisable="0 3 8 3"/>
|
||||||
|
<!-- note: repeated numbers are okay -->
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
ASSERT_THAT(model, NotNull());
|
||||||
|
EXPECT_EQ(model->opt.disableactuator, (1<<0) + (1<<3) + (1<<8));
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ActuatorParseTest, GroupDisableNegative) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<option actuatorgroupdisable="0 -3 5"/>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
ASSERT_THAT(model, IsNull());
|
||||||
|
EXPECT_THAT(error.data(), HasSubstr("must be non-negative"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ActuatorParseTest, GroupDisableTooBig) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<option actuatorgroupdisable="0 31"/>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
ASSERT_THAT(model, IsNull());
|
||||||
|
EXPECT_THAT(error.data(), HasSubstr("cannot exceed 30"));
|
||||||
|
}
|
||||||
|
|
||||||
// ------------- test sensor parsing -------------------------------------------
|
// ------------- test sensor parsing -------------------------------------------
|
||||||
|
|
||||||
using SensorParseTest = MujocoTest;
|
using SensorParseTest = MujocoTest;
|
||||||
|
|||||||
@@ -4968,6 +4968,7 @@ public unsafe struct mjOption_ {
|
|||||||
public int mpr_iterations;
|
public int mpr_iterations;
|
||||||
public int disableflags;
|
public int disableflags;
|
||||||
public int enableflags;
|
public int enableflags;
|
||||||
|
public int disableactuator;
|
||||||
public int sdf_initpoints;
|
public int sdf_initpoints;
|
||||||
public int sdf_iterations;
|
public int sdf_iterations;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user