Skip to content

Commit c614587

Browse files
committed
Updated the docstring for mjcf.Physics.bind
PiperOrigin-RevId: 217200519
1 parent 980e020 commit c614587

1 file changed

Lines changed: 34 additions & 14 deletions

File tree

dm_control/mjcf/physics.py

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -519,8 +519,8 @@ def bind(self, mjcf_elements):
519519
```
520520
521521
Note that the binding takes into account the type of element. This allows us
522-
to remove prefixes for from certain common attributes in order to unify
523-
access. For example, we can use:
522+
to remove prefixes from certain common attributes in order to unify access.
523+
For example, we can use:
524524
525525
```python
526526
physics.bind(geom_element).pos = [1, 2, 3]
@@ -544,22 +544,42 @@ def bind(self, mjcf_elements):
544544
done lazily when an updated value is required, so repeated value
545545
modifications do not incur a performance penalty.
546546
547-
It is also possible to bind a sequence containing multiple elements,
548-
provided they are all of the same type. However, note that for a sequence of
549-
elements the returned array will always be a copy, so writing into it will
550-
not affect the underlying `Physics` instance:
547+
It is also possible to bind a sequence containing one or more elements,
548+
provided they are all of the same type. In this case the binding exposes
549+
`_SynchronizingArrayWrapper`s, which are array-like objects that provide
550+
writeable views onto the corresponding memory addresses in MuJoCo. Writing
551+
into a `_SynchronizingArrayWrapper` causes the underlying values in MuJoCo
552+
to be updated, and if necessary causes derived values to be recalculated.
553+
Note that in order to trigger recalculation it is necessary to reference a
554+
derived attribute of a binding.
551555
552556
```python
553-
physics.bind([geom1, geom2]).pos # Returns a copy.
554-
physics.bind([geom1, geom2]).pos[:] = [[1, 2, 3], [4, 5, 6]] # No effect!
557+
bound_joints = physics.bind([joint1, joint2])
558+
bound_bodies = physics.bind([body1, body2])
559+
# `qpos_view` and `xpos_view` are `_SynchronizingArrayWrapper`s providing
560+
# views onto `physics.data.qpos` and `physics.data.xpos` respectively.
561+
qpos_view = bound_joints.qpos
562+
xpos_view = bound_bodies.xpos
563+
# This updates the corresponding values in `physics.data.qpos`, and marks
564+
# derived values (such as `physics.data.xpos`) as needing recalculation.
565+
qpos_view[0] += 1.
566+
# Note: at this point `xpos_view` still contains the old values, since we
567+
# need to actually read the value of a derived attribute in order to
568+
# trigger recalculation.
569+
another_xpos_view = bound_bodies.xpos # Triggers recalculation of `xpos`.
570+
# Now both `xpos_view` and `another_xpos_view` will contain the updated
571+
# values.
555572
```
556573
557-
To allow for assignment into multiple elements, bindings also support
558-
numpy-style square bracket indexing. The first element in the indexing
559-
expression should be an attribute name, and the second element (if present)
560-
is used to index into the columns of the underlying array. Named indexing
561-
into columns is also allowed, provided that the corresponding field in
562-
`physics.named` supports it.
574+
Warning: it is unsafe to copy or serialize a `_SynchronizingArrayWrapper`.
575+
We also do not recommend holding references to them - instead hold a
576+
reference to the binding object, or call `physics.bind` again.
577+
578+
Bindings also support numpy-style square bracket indexing. The first element
579+
in the indexing expression should be an attribute name, and the second
580+
element (if present) is used to index into the columns of the underlying
581+
array. Named indexing into columns is also allowed, provided that the
582+
corresponding field in `physics.named` supports it.
563583
564584
```python
565585
physics.bind([geom1, geom2])['pos'] = [[1, 2, 3], [4, 5, 6]]

0 commit comments

Comments
 (0)