Physics-rate PD actuators, named collision geoms, lite_biped_debug variant - #13
Merged
Merged
Conversation
Three related changes to the MJCF generator and one new variant. 1. <position> actuators instead of <motor> The joint-level PD belongs inside the physics step. MuJoCo evaluates actuators every mj_step, which mirrors the real RobStride drive closing its onboard loop at ~1 kHz independently of the host rate, and lets implicitfast integrate the damping term implicitly -- the reason a stiff PD stays stable at a coarse timestep, and how mjlab trains. A <motor> makes ctrl a raw torque, forcing the host to sample the PD once per controller_manager tick, which made the sim's PD rate an artifact of the CM rate. Measured downstream in the arms sim (worst-joint peak-to-peak after standby settles): 0.00065 rad at 200 Hz with the PD in mj_step, vs 0.0371 rad of 25-37 Hz wrist chatter when that same 200 Hz loop computed the PD itself, and 0.0024 rad at 400 Hz that way. So it is both chatter-free and 3.6x quieter than the previous best arrangement. kp/kv are left at MuJoCo's defaults on purpose: the operative gains are mode-dependent and arrive over ros2_control's stiffness/damping command interfaces, so MujocoSystem overwrites gainprm/biasprm every tick. No ctrlrange/ctrllimited is emitted, and that is load-bearing: an RL policy is allowed to command a position setpoint beyond the mechanical joint limit to hold a saturating torque, so clamping the setpoint would silently cap the achievable torque. forcerange still bounds the output. 2. Name collision geoms <body>_collision_<i> MuJoCo leaves URDF-imported geoms anonymous, but the training env selects them BY NAME -- mjlab's friction DR matches r"^(left|right)_foot_collision_\d+$" -- and an unnamed geom can never match, so that randomization was silently doing nothing. Only fills blanks; an explicit name in the MJCF still wins. 3. New variant: lite_biped_debug Identical to lite_biped except for a deliberately simplified foot collider: one 70x130x20 mm box per foot, replacing 11 spheres. Verified flush with the sole (gap 0.0 mm with the origin rpy applied) and covering the full 130 mm mesh length. Note the debug foot is much smaller than lite_biped's (130 mm vs 213 mm long), so its support polygon is roughly a third of the area -- a policy will not transfer between the two variants unchanged. Link and joint names match lite_biped exactly (the three new CAD parts merge into the existing left_foot/right_foot links), so ros2_control.json, the MJCF body list and the training-side tracked-body list all still resolve. physics .json is byte-identical, keeping timestep 0.005 and the solver settings matched to mjlab's training config. Regenerated every variant's MJCF. 1531 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012QKJQ9hze1hMWXJpdPcjp3
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.
Three related changes to the MJCF generator plus one new variant. Every variant's MJCF is regenerated; 1531 tests pass.
1.
<position>actuators instead of<motor>The joint-level PD belongs inside the physics step. MuJoCo evaluates actuators every
mj_step, which mirrors the real RobStride drive closing its onboard loop at ~1 kHz independently of the host rate, and letsimplicitfastintegrate the damping term implicitly — the reason a stiff PD stays stable at a coarse timestep, and how mjlab trains. A<motor>makesctrla raw torque, forcing the host to sample the PD once percontroller_managertick, which made the sim's PD rate an artifact of the CM rate.Measured downstream in the arms sim (worst-joint peak-to-peak after standby settles):
mj_stepwrite()write()Both chatter-free and 3.6× quieter than the previous best arrangement.
kp/kvare left at MuJoCo's defaults deliberately: the operative gains are mode-dependent (standby, policy, damping all differ) and arrive over ros2_control's stiffness/damping command interfaces, soMujocoSystemoverwritesgainprm/biasprmevery tick. Baked values would only mislead.No
ctrlrange/ctrllimitedis emitted, and that is load-bearing: an RL policy is allowed to command a position setpoint beyond the mechanical joint limit in order to hold a saturating torque, so clamping the setpoint would silently cap the achievable torque.forcerangestill bounds the output, which is the limit that is physically real.2. Name collision geoms
<body>_collision_<i>MuJoCo leaves URDF-imported geoms anonymous, but the training env selects them by name — mjlab's friction DR matches
r"^(left|right)_foot_collision_\d+$"— and an unnamed geom can never match, so that randomization was silently doing nothing. Only fills blanks; an explicit name in the MJCF still wins.Result:
left_foot_collision_0..10onlite_biped(11 spheres),left_foot_collision_0onlite_biped_debug(1 box). Variants with no scad colliders are unaffected.3. New variant:
lite_biped_debugIdentical to
lite_bipedexcept for a deliberately simplified foot collider — one 70×130×20 mm box per foot, replacing 11 spheres. Verified flush with the sole (gap 0.0 mm, with the originrpyapplied) and covering the full 130 mm mesh length at 70 mm wide vs 72 mm mesh.Parity that matters for downstream configs: link and joint names match
lite_bipedexactly (the three new CAD parts —foot_palm_debug,foot_front,foot_rear— merge into the existingleft_foot/right_footlinks), soros2_control.json, the MJCF body list and the training-side tracked-body list all still resolve.physics.jsonis byte-identical, keepingtimestep 0.005and the solver settings matched to mjlab's training config. The four-bar ankle linkage params carry through to the ros2_control xacro.lite_biped's (130 mm vs 213 mm long, no toe upturn) — roughly a third of the contact area. A policy will not transfer between the two variants unchanged; that is the point of the variant, but worth stating.Companion changes in other repos
A PR cannot span repos, so the rest of this work lands separately:
mujoco_ros2_control—MujocoSystemmust drivectrl+gainprm/biasprminstead of computing the PD intoqfrc_applied; without it the<position>actuators here are inert. Still uncommitted.humanoid_control— the 200 Hz CM rate and the sim/real rate unification that the measurements above come from: Berkeley-Humanoids/humanoid_control_ros2#24.🤖 Generated with Claude Code
https://claude.ai/code/session_012QKJQ9hze1hMWXJpdPcjp3