Skip to content

Commit

Permalink
Disable tendon catenary visualization when tendon is actuated. Add no…
Browse files Browse the repository at this point in the history
…te about catenary visualization.

PiperOrigin-RevId: 706161179
Change-Id: Ifaf571e039306309869078d1a0bcf9a69f1fe9de
  • Loading branch information
yuvaltassa authored and copybara-github committed Dec 14, 2024
1 parent ec230fa commit b26d6f0
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 2 deletions.
12 changes: 12 additions & 0 deletions doc/XMLreference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4661,6 +4661,18 @@ A second form of wrapping is where the tendon is constrained to pass *through* a
wrap around it. This is enabled automatically when a sidesite is specified and its position is inside the volume of
the obstacle geom.

.. youtube:: I2q7D0Vda-A
:width: 300px
:align: right

**Visualization:** Tendon paths are visualized as in the image above, respecting the :ref:`width<tendon-spatial-width>`,
:ref:`material<tendon-spatial-material>` and :ref:`rgba<tendon-spatial-rgba>` attributes below. A special kind of
visualization is used for unactuated 2-point tendons with :ref:`range<tendon-spatial-range>` or
:ref:`springlength<tendon-spatial-springlength>` of the form :at-val:`[0 X]`, with positive X. Such tendons act like a
cable, applying force only when stretched. Therefore when not stretched, they are drawn as a catenary of
length X, as in the clip on the right of `this example model
<https://github.com/google-deepmind/mujoco/blob/main/test/engine/testdata/catenary.xml>`__.

.. _tendon-spatial-name:

:at:`name`: :at-val:`string, optional`
Expand Down
15 changes: 13 additions & 2 deletions src/engine/engine_vis_visualize.c
Original file line number Diff line number Diff line change
Expand Up @@ -1729,6 +1729,16 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
objtype = mjOBJ_TENDON;
category = mjCAT_DYNAMIC;
if (vopt->flags[mjVIS_TENDON] && (category & catmask)) {
// mark actuated tendons
int* tendon_actuated = mjSTACKALLOC(d, m->ntendon, int);
mju_zeroInt(tendon_actuated, m->ntendon);
for (int i=0; i < m->nu; i++) {
if (m->actuator_trntype[i] == mjTRN_TENDON) {
tendon_actuated[m->actuator_trnid[2*i]] = 1;
}
}

// draw tendons
for (int i=0; i < m->ntendon; i++) {
if (vopt->tendongroup[mjMAX(0, mjMIN(mjNGROUP-1, m->tendon_group[i]))]) {
// tendon has a deadband spring
Expand All @@ -1752,9 +1762,10 @@ void mjv_addGeoms(const mjModel* m, mjData* d, const mjvOption* vopt,
!mjDISABLED(mjDSBL_GRAVITY) && // gravity enabled
mju_norm3(m->opt.gravity) > mjMINVAL && // gravity strictly nonzero
m->tendon_num[i] == 2 && // only two sites on the tendon
(limitedspring || limitedconstraint) && // either spring or constraint length limits
(limitedspring != limitedconstraint) && // either spring or constraint length limits
m->tendon_damping[i] == 0 && // no damping
m->tendon_frictionloss[i] == 0; // no frictionloss
m->tendon_frictionloss[i] == 0 && // no frictionloss
tendon_actuated[i] == 0; // no actuator

// conditions not met: draw straight lines
if (!draw_catenary) {
Expand Down

0 comments on commit b26d6f0

Please sign in to comment.