Repository navigation
Support impedance control on MuJoCo POSITION actuators - #9
Merged
lgulich merged 5 commits intoOct 5, 2026
Merged
Conversation
Impedance mode assumed the target actuator interprets ctrl as a torque, which
holds for MOTOR actuators but not for POSITION ones. A MuJoCo position actuator
applies
force = gainprm[0]*ctrl + biasprm[0] + biasprm[1]*q + biasprm[2]*v
so ctrl is a position setpoint. Summing kp*position_error + kd*velocity_error
into it is a unit mismatch: the resulting error is non-monotonic in kp, so no
choice of gains recovers correct behaviour, and any model whose actuators use
biastype="affine" silently misbehaves under a controller that claims kp/kd.
Drive those actuators through their own gains instead. Programming
gainprm[0] = kp
biasprm[0] = effort_ff + kd*v_target
biasprm[1] = -kp
biasprm[2] = -kd
and passing the target through as ctrl makes the actuator apply
effort_ff + kp*(q_target - q) + kd*(v_target - v)
which is the same expression the MOTOR path computes by hand -- verified equal
to machine precision against MuJoCo's actuator_force across random states, with
forcerange clamping still applied as authored.
The MJCF gains become defaults rather than fixed values, and are captured at
registration and restored when the joint is released. mjModel is shared with
the physics loop, so unlike ctrl -- which is staged -- gain writes take the sim
mutex and happen only when a commanded gain actually changes, keeping the lock
off the steady-state control path.
Also add the <limits> include data.hpp already relied on transitively.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The package builds as C++17 in some environments (e.g. pixi), where a defaulted operator== and std::erase_if are unavailable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lgulich
force-pushed
the
nvidia/position-actuator-impedance
branch
from
October 5, 2026 21:29
0b6d70d to
db41de2
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ported from the GitLab mirror MR (Isaac/github/mujoco_ros2_control!2, by @somudrog), rebased onto current
impedence-control-support.Summary
gainprm/biasprmso MuJoCo applieseffort_ff + kp*(q_target - q) + kd*(v_target - v)natively, instead of writing the computed PD torque intoctrl(which a position actuator interprets as a position setpoint).Needed for Sharpa hand fingers on Unitree H2 (position-servo actuators) driven by the impedance-style ForwardJointCommandController.
🤖 Generated with Claude Code