Skip to content

Fix Unitree Go2 calf actuator limits - #7562

Closed
sylvesterkaczmarek wants to merge 3 commits into
isaac-sim:developfrom
sylvesterkaczmarek:fix/go2-calf-reduction
Closed

Fix Unitree Go2 calf actuator limits#7562
sylvesterkaczmarek wants to merge 3 commits into
isaac-sim:developfrom
sylvesterkaczmarek:fix/go2-calf-reduction

Conversation

@sylvesterkaczmarek

Copy link
Copy Markdown

Description

Fixes #7479.

UNITREE_GO2_CFG currently applies the same DC-motor effort and velocity limits to the hip, thigh, and calf joints. The Go2 calf sits behind an additional knee reduction, so using the hip/thigh limits underestimates calf torque and allows an unrealistically high motor-curve velocity.

This change keeps the existing hip/thigh actuator settings and gives the calf joints their own actuator group with reduction-adjusted limits:

  • effort / saturation effort: 45.05 N·m
  • velocity limit: 15.65 rad/s

The stiffness, damping, and friction settings are unchanged.

Tests

Adds a configuration regression test verifying the calf group and its reduced joint-side limits.

Changelog

Adds the required isaaclab_assets changelog fragment.

@sylvesterkaczmarek
sylvesterkaczmarek requested a review from a team September 4, 2026 06:34
@github-actions github-actions Bot added bug Something isn't working asset New asset feature or request labels Sep 4, 2026

@isaaclab-review-bot isaaclab-review-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isaac Lab Review Bot

The Go2 calf joints are correctly split into a dedicated DC-motor group with reduction-adjusted effort and velocity limits, while existing gains and friction are preserved. The changelog should also document the changed actuator-group layout and migration impact for downstream overrides.

  • Design and architecture: Using a separate DCMotorCfg group is appropriate because the calf joints require different effort and velocity limits from the hip and thigh joints. The group split preserves the previous stiffness, damping, and friction values.
  • API: UNITREE_GO2_CFG.actuators now narrows base_legs to hip and thigh joints and introduces the calves key. Because downstream configurations overriding actuators["base_legs"] will no longer affect calves, the changelog must identify the new group and provide migration guidance for that changed behavior.
  • Implementation: The calf joint expression and reduction-adjusted limits are applied consistently, and the regression test directly checks the new group boundaries and limit values. The remaining fix is limited to documenting the actuator-group restructuring in the changelog fragment.

Minor fixes needed. Posted 1 actionable finding inline.

Automated review; human maintainers own approval decisions.

Fixed
^^^^^

* Fixed the Unitree Go2 calf actuator limits to reflect the knee reduction instead of sharing the hip/thigh limits.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Warning · Api — Changelog omits actuator group restructure guidance

The fragment only mentions limit values, but the public config layout also changed: UNITREE_GO2_CFG.actuators["base_legs"] no longer matches .*_calf_joint, and a new "calves" group was added. Downstream configs that override actuators["base_legs"] (stiffness, damping, limits, joint expressions) now silently skip calf joints. Repository rules require migration guidance for changed behavior; state the narrowed base_legs scope and the new group name.

@greptile-apps

greptile-apps Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR separates Unitree Go2 calf joints into their own DC-motor actuator group so their effort and velocity limits account for the knee reduction, and adds a configuration regression test and changelog entry.

  • Preserves the existing hip and thigh motor limits.
  • Assigns reduction-adjusted effort, saturation-effort, and velocity limits to calf joints.
  • Adds direct assertions for the new actuator-group layout and limits.

Confidence Score: 4/5

The PR should not merge until the new calf actuator group receives the existing Go2 backend-specific armature preset.

The limit conversion is internally consistent, but splitting the actuator group causes current rough and flat Go2 environments to leave calf armature at the USD value while applying their configured preset only to hip and thigh joints.

Files Needing Attention: source/isaaclab_assets/isaaclab_assets/robots/unitree.py and source/isaaclab_tasks/isaaclab_tasks/core/velocity/config/go2/rough_env_cfg.py

Important Files Changed

Filename Overview
source/isaaclab_assets/isaaclab_assets/robots/unitree.py Correctly separates the calf motor limits, but the new group no longer receives the Go2 environments' existing backend-specific armature preset.
source/isaaclab_assets/test/test_unitree.py Covers the group split and numeric limits but does not cover inherited actuator properties such as backend-specific armature overrides.
source/isaaclab_assets/changelog.d/fix-go2-calf-reduction.rst Accurately documents the intended actuator-limit correction.

Reviews (1): Last reviewed commit: "docs: add Go2 actuator changelog fragmen..." | Re-trigger Greptile

damping=0.5,
friction=0.0,
),
"calves": DCMotorCfg(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Calves lose armature presets

When Go2 rough or flat velocity environments initialize, their backend-specific armature preset updates only base_legs; moving the calf joints into calves leaves them at the USD-authored armature instead of the configured 0.0 or 0.02 value, unintentionally changing calf dynamics.

@AntoineRichard

Copy link
Copy Markdown
Collaborator

Thanks for the PR @sylvesterkaczmarek I think we want to go a slightly different route by avoiding the creation of two actuator groups, it can be a bit slower. Also looks like Go1 is affected by similar issues. Some other unitree assets are also affected (like G1 or H1) but for this we likely need new assets. #7564 to replace

kellyguo11 pushed a commit that referenced this pull request Sep 4, 2026
…ion (#7564)

# Description

Fixes #7479.

`UNITREE_GO1_CFG` and `UNITREE_GO2_CFG` apply one set of DC-motor limits
to all twelve leg joints, but on both robots the calf sits behind an
extra knee reduction. The calf was capped at roughly half its rated
torque, while the torque-speed curve kept producing motoring torque up
to a no-load speed the hardware cannot reach.

The values are not a guess — they are already authored in the USD assets
we ship, and the Python configs were discarding them. Dumping the joint
drives from the configured asset root:

| joint | `go2.usd` `maxForce` | `go2.usd` `maxJointVelocity` | old
config |
| --- | --- | --- | --- |
| hip / thigh | 23.7 N·m | 1724.6 °/s = 30.1 rad/s | 23.5 / 30.0 |
| calf | **45.43 N·m** | 899.54 °/s = **15.70 rad/s** | 23.5 / 30.0 |

| joint | `go1.usd` `maxForce` | `go1.usd` `maxJointVelocity` | old
config |
| --- | --- | --- | --- |
| hip / thigh | 23.7 N·m | 1724.6 °/s = 30.1 rad/s | 23.7 / 30.0 |
| calf | **35.55 N·m** | 1149.35 °/s = **20.06 rad/s** | 23.7 / 30.0 |

Both match the official Unitree URDFs exactly
([go2](https://github.com/unitreerobotics/unitree_ros/blob/master/robots/go2_description/urdf/go2_description.urdf),
[go1](https://github.com/unitreerobotics/unitree_ros/blob/master/robots/go1_description/urdf/go1.urdf)),
giving reductions of 1.9169 and 1.5000.

Go1 is affected for the same reason even though it uses an actuator net:
`ActuatorNetMLP` subclasses `DCMotor`, so the network output goes
through the same envelope.

`UNITREE_A1_CFG` was checked and needs no change — `a1.urdf` and
`a1.usd` are both flat at 33.5 N·m / 21.0 rad/s, matching the config.

## Why `saturation_effort` had to change

The calf needs its own *stall* torque, not just its own effort and
velocity limits. `saturation_effort` was the one actuator limit typed as
a bare `float`, so expressing this previously required splitting the
legs into two actuator groups — which changes the `actuators` dict keys
that `go1/rough_env_cfg.py`, `go2/rough_env_cfg.py` and `test_hydra.py`
index by name, and adds a second group to iterate every step.

The first commit resolves it through `resolve_joint_parameter` like
every other limit, so it accepts a joint-name-pattern dict. This is not
a new concept in the codebase: `sim/schemas/schemas_actuators.py`
already expands dict-shaped `saturation_effort` when authoring
`NewtonActuator` prims, so the config type was simply narrower than the
machinery behind it. Scalar configurations are unaffected.

## Note on #7562

@sylvesterkaczmarek filed #7479 and opened #7562 for the Go2 half of
this. That PR takes the second-actuator-group route and derives the calf
values from the reduction ratio (45.05 / 15.65) rather than reading them
off the asset. This PR covers Go1 as well, keeps a single actuator
group, and uses the values already in the USD. Happy to defer if
maintainers prefer the other shape.

## Type of change

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)

Simulated Go1 and Go2 behavior changes: the calf now produces up to
1.92x more torque and stops motoring at roughly half the previous speed.
Policies trained against the old configuration should be retrained
rather than reused. This is called out in the `isaaclab_assets`
changelog fragment.

## Tests

- `source/isaaclab/test/actuators/test_dc_motor.py` gains
`test_dc_motor_clip_with_per_joint_saturation_effort`, which checks that
a dict-configured two-joint group reproduces, column by column, what a
scalar-configured actuator produces for the same joint. Verified failing
before the fix (`TypeError: unsupported operand type(s) for /: 'Tensor'
and 'dict'`) and passing after.
- `source/isaaclab/test/actuators/test_dc_motor.py` — 170 passed.
- `source/isaaclab/test/actuators/test_actuator_collection.py` — 30
passed.
- `source/isaaclab_assets/test/test_valid_configs.py -k cpu` — 1 passed
(spawns every registered asset, including both Go configs).
- Confirmed the patterns resolve against the real joint names: all four
calf joints get 45.43 / 15.70 (Go2) and 35.55 / 20.06 (Go1); hips and
thighs get 23.7 / 30.1.

No config-literal assertion test was added for `unitree.py` — it would
restate the constants without checking behavior. The behavioral contract
is covered by the DC-motor test above.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there
isaaclab-bot Bot pushed a commit that referenced this pull request Sep 4, 2026
…ion (#7564)

# Description

Fixes #7479.

`UNITREE_GO1_CFG` and `UNITREE_GO2_CFG` apply one set of DC-motor limits
to all twelve leg joints, but on both robots the calf sits behind an
extra knee reduction. The calf was capped at roughly half its rated
torque, while the torque-speed curve kept producing motoring torque up
to a no-load speed the hardware cannot reach.

The values are not a guess — they are already authored in the USD assets
we ship, and the Python configs were discarding them. Dumping the joint
drives from the configured asset root:

| joint | `go2.usd` `maxForce` | `go2.usd` `maxJointVelocity` | old
config |
| --- | --- | --- | --- |
| hip / thigh | 23.7 N·m | 1724.6 °/s = 30.1 rad/s | 23.5 / 30.0 |
| calf | **45.43 N·m** | 899.54 °/s = **15.70 rad/s** | 23.5 / 30.0 |

| joint | `go1.usd` `maxForce` | `go1.usd` `maxJointVelocity` | old
config |
| --- | --- | --- | --- |
| hip / thigh | 23.7 N·m | 1724.6 °/s = 30.1 rad/s | 23.7 / 30.0 |
| calf | **35.55 N·m** | 1149.35 °/s = **20.06 rad/s** | 23.7 / 30.0 |

Both match the official Unitree URDFs exactly
([go2](https://github.com/unitreerobotics/unitree_ros/blob/master/robots/go2_description/urdf/go2_description.urdf),
[go1](https://github.com/unitreerobotics/unitree_ros/blob/master/robots/go1_description/urdf/go1.urdf)),
giving reductions of 1.9169 and 1.5000.

Go1 is affected for the same reason even though it uses an actuator net:
`ActuatorNetMLP` subclasses `DCMotor`, so the network output goes
through the same envelope.

`UNITREE_A1_CFG` was checked and needs no change — `a1.urdf` and
`a1.usd` are both flat at 33.5 N·m / 21.0 rad/s, matching the config.

## Why `saturation_effort` had to change

The calf needs its own *stall* torque, not just its own effort and
velocity limits. `saturation_effort` was the one actuator limit typed as
a bare `float`, so expressing this previously required splitting the
legs into two actuator groups — which changes the `actuators` dict keys
that `go1/rough_env_cfg.py`, `go2/rough_env_cfg.py` and `test_hydra.py`
index by name, and adds a second group to iterate every step.

The first commit resolves it through `resolve_joint_parameter` like
every other limit, so it accepts a joint-name-pattern dict. This is not
a new concept in the codebase: `sim/schemas/schemas_actuators.py`
already expands dict-shaped `saturation_effort` when authoring
`NewtonActuator` prims, so the config type was simply narrower than the
machinery behind it. Scalar configurations are unaffected.

## Note on #7562

@sylvesterkaczmarek filed #7479 and opened #7562 for the Go2 half of
this. That PR takes the second-actuator-group route and derives the calf
values from the reduction ratio (45.05 / 15.65) rather than reading them
off the asset. This PR covers Go1 as well, keeps a single actuator
group, and uses the values already in the USD. Happy to defer if
maintainers prefer the other shape.

## Type of change

- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)

Simulated Go1 and Go2 behavior changes: the calf now produces up to
1.92x more torque and stops motoring at roughly half the previous speed.
Policies trained against the old configuration should be retrained
rather than reused. This is called out in the `isaaclab_assets`
changelog fragment.

## Tests

- `source/isaaclab/test/actuators/test_dc_motor.py` gains
`test_dc_motor_clip_with_per_joint_saturation_effort`, which checks that
a dict-configured two-joint group reproduces, column by column, what a
scalar-configured actuator produces for the same joint. Verified failing
before the fix (`TypeError: unsupported operand type(s) for /: 'Tensor'
and 'dict'`) and passing after.
- `source/isaaclab/test/actuators/test_dc_motor.py` — 170 passed.
- `source/isaaclab/test/actuators/test_actuator_collection.py` — 30
passed.
- `source/isaaclab_assets/test/test_valid_configs.py -k cpu` — 1 passed
(spawns every registered asset, including both Go configs).
- Confirmed the patterns resolve against the real joint names: all four
calf joints get 45.43 / 15.70 (Go2) and 35.55 / 20.06 (Go1); hips and
thighs get 23.7 / 30.1.

No config-literal assertion test was added for `unitree.py` — it would
restate the constants without checking behavior. The behavioral contract
is covered by the DC-motor test above.

## Release backport

- [x] <!-- backport-active-release --> Backport this pull request to the
active release branch after it merges into `develop`

## Checklist

- [x] I have read and understood the [contribution
guidelines](https://isaac-sim.github.io/IsaacLab/main/source/refs/contributing.html)
- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have added a changelog fragment under
`source/<pkg>/changelog.d/` for every touched package
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

(cherry picked from commit 5c78379)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

asset New asset feature or request bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants