Skip to content

Commit d4595d0

Browse files
yuvaltassacopybara-github
authored andcommitted
Save actuators and actuator defaults with their shortcut tags.
Shortcut actuators were always saved as <general>, which loses the author's notation and the per-shortcut defaults inheritance introduced in the parent CL. The writer now simulates reading the actuator back with its shortcut tag over its class default, and uses the tag when that gives the same actuator; otherwise it falls back to <general> as before. The canonical notation (savecanonical, which compiled values are always saved in) keeps writing every actuator as <general>. - xml_base: shared mjXShortcut representation with per-type defaults, extraction from an mjsActuator and application via mjs_setTo*. - schema/generator: shortcut-specific attributes marked reading=custom; per-tag attribute tables and a kActuatorDispatch table are generated. - reader: OneActuator dispatches on the generated tables and mjXShortcut. - writer: OneActuator picks the tag, writes the tag's mechanical rows and shortcut parameters relative to the class; defaults sections drop an element which only repeats the parent's tag; in the canonical notation every actuator is general. - tests, changelog, modeling.rst, XMLreference.rst (savecanonical). PiperOrigin-RevId: 995215676 Change-Id: I4867d7824cf970b581c25faf5201771046782793
1 parent ab7f005 commit d4595d0

13 files changed

Lines changed: 1251 additions & 396 deletions

‎doc/XMLreference.rst‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,10 +1016,10 @@ has any effect. The settings here are global and apply to the entire model.
10161016

10171017
:at:`savecanonical`: :at-val:`[false, true], "true"`
10181018
If "true", orientations are saved as quaternions, angles in radians, sizes and poses which were given with
1019-
:at:`fromto` as :at:`size`, :at:`pos` and :at:`quat`, and a :at:`fullinertia` as :at:`diaginertia` and
1020-
:at:`quat`. If "false", they are saved in the notation in which they were written. This attribute has an effect
1021-
only if :ref:`savecompiled<compiler-savecompiled>` is "false": compiled values are always saved in the canonical
1022-
notation.
1019+
:at:`fromto` as :at:`size`, :at:`pos` and :at:`quat`, a :at:`fullinertia` as :at:`diaginertia` and :at:`quat`, and
1020+
every actuator as :el:`general`. If "false", they are saved in the notation in which they were written. This
1021+
attribute has an effect only if :ref:`savecompiled<compiler-savecompiled>` is "false": compiled values are always
1022+
saved in the canonical notation.
10231023

10241024
.. _compiler-conflict:
10251025

‎doc/changelog.rst‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ Actuation
151151
full documented table, including its dynamics and activation layout, and a :ref:`pid<actuator-pid>` without ``kp``
152152
has the documented gain of 1, not 0. Added ``mjsActuator.type`` (:ref:`mjtActuator`), the element an actuator is
153153
written with.
154+
- A model saved in the notation it was written in (:ref:`savecanonical<compiler-savecanonical>` "false") now writes
155+
each actuator, and each actuator default, with the shortcut it was written with (``<position kp="10"/>``), with its
156+
own attributes, whenever reading the shortcut back gives the same actuator; otherwise it is written as
157+
:ref:`general<actuator-general>`. The canonical notation writes every actuator as general, as before.
154158
- A :ref:`pid<actuator-pid>` actuator with both :ref:`ki<actuator-pid-ki>` and :ref:`slewmax<actuator-pid-slewmax>`
155159
now compiles; its two activation states were rejected.
156160

‎doc/generate/generate_read_table.py‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@
5151
# If you add a new schema element with a bound spec, either migrate its
5252
# reader to ReadAttrTable (it will be auto-included) or add it here.
5353
NOT_TABLE_DRIVEN = {
54-
# actuator shorthands: read shared rows + per-tag remappings
55-
'motor', 'position', 'velocity', 'intvelocity', 'orientation',
56-
'pid', 'damper', 'cylinder', 'muscle', 'adhesion', 'dcmotor',
54+
# plugin actuator: shared rows + plugin config
5755
'actuator_plugin',
5856
# equality subtypes: read shared equality_base + per-type refs
5957
'connect', 'weld', 'equality_joint', 'equality_tendon',
@@ -65,6 +63,10 @@
6563
'frame', 'plugin', 'numeric', 'text', 'tuple',
6664
}
6765

66+
# actuator tags whose mechanical rows are collected into kActuatorDispatch,
67+
# keyed by the actuatortype enum; shortcut parameters are reading=custom
68+
ACTUATOR_DISPATCH_ENUM = 'actuatortype'
69+
6870
# sensors whose whole branch derives from the schema (identity constants +
6971
# references); their arrays are also collected into kSensorDispatch
7072
SENSOR_DISPATCH = [
@@ -403,6 +405,17 @@ def generate():
403405
out.append('inline constexpr int kSensorDispatchN = '
404406
'sizeof(kSensorDispatch) / sizeof(kSensorDispatch[0]);')
405407
out.append('')
408+
out.append('// actuator tags and their mechanical rows: dispatch by tag or type')
409+
out.append('struct mjXActuatorEntry { const char* tag; int type;'
410+
' const mjXAttr* rows; int n; };')
411+
out.append('inline constexpr mjXActuatorEntry kActuatorDispatch[] = {')
412+
for tag, const in schema.enums[ACTUATOR_DISPATCH_ENUM].items:
413+
array = array_name(tag)
414+
out.append(f' {{"{tag}", {const}, {array}, {array}N}},')
415+
out.append('};')
416+
out.append('inline constexpr int kActuatorDispatchN = '
417+
'sizeof(kActuatorDispatch) / sizeof(kActuatorDispatch[0]);')
418+
out.append('')
406419
for gname, (struct, array) in EMIT_GROUPS.items():
407420
rows = rows_for_group(schema, structs, gname, struct)
408421
out.append(f'// group {gname} ({struct})')

‎doc/modeling.rst‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -632,9 +632,11 @@ This is done via the XML elements :ref:`motor <actuator-motor>`, :ref:`position
632632
<actuator-velocity>`, :ref:`intvelocity <actuator-intvelocity>`, :ref:`orientation<actuator-orientation>`,
633633
:ref:`pid<actuator-pid>`, :ref:`damper<actuator-damper>`, :ref:`cylinder<actuator-cylinder>`,
634634
:ref:`muscle <actuator-muscle>`, :ref:`adhesion <actuator-adhesion>`, and :ref:`dcmotor<actuator-dcmotor>`. These are
635-
*not* separate model elements. Internally MuJoCo supports only one actuator type -which is why when an MJCF model is
636-
saved all actuators are written as :el:`general`. Shortcuts create general actuators implicitly, set their attributes to
637-
suitable values, and expose a subset of attributes with possibly different names. For example, :el:`position` creates a
635+
*not* separate model elements. Internally MuJoCo supports only one actuator type. Shortcuts create general actuators
636+
implicitly, set their attributes to suitable values, and expose a subset of attributes with possibly different names.
637+
When a model is saved in the notation it was written in, an actuator is written with its shortcut if reading the
638+
shortcut back gives the same actuator, and as :el:`general` otherwise; in the canonical notation every actuator is
639+
:el:`general`. For example, :el:`position` creates a
638640
position servo with attribute :at:`kp` which is the servo gain. However :el:`general` does not have an attribute
639641
:at:`kp`. Instead the parser adjusts the gain and bias parameters of the general actuator in a coordinated way so as to
640642
mimic a position servo. The same effect could have been achieved by using :el:`general` directly, and setting its

0 commit comments

Comments
 (0)
⌂ 换网址