Skip to content

[Newton] Add Ackermann steering controller and action term - #6654

Draft
hujc7 wants to merge 2 commits into
isaac-sim:developfrom
hujc7:jichuanh/newton-controllers-integration-codex
Draft

hujc7 wants to merge 2 commits into
isaac-sim:developfrom
hujc7:jichuanh/newton-controllers-integration-codex

Conversation

@hujc7

@hujc7 hujc7 commented Jul 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Keep Ackermann steering integration in a separate draft pending a public Newton Ackermann controller.

Description

This draft contains only the Ackermann controller, configuration, action term, documentation, and tests from the original proposal. Differential IK moved to the consolidated Newton controller PR #7854.

Blocked: the adapter still depends on the unpublished newton_controllers.ControllerAckermann API. Released Newton does not provide it; this draft is not ready to merge.

Type of change

  • New feature

Release backport

  • Backport to the active release branch

Screenshots

Not applicable.

Validation

Formatting and changelog checks passed. Runtime tests were not rerun because the required unpublished controller dependency is unavailable in the supported environment.

Checklist

  • Documentation and package changelog fragment included
  • Existing Ackermann tests retained
  • Pre-commit checks passed with uv run isaaclab -f
  • Public Newton implementation available and runtime tests passing

Delegate DifferentialIKController inverse-kinematics solves to
Newton's model-free differential-kinematics controller while keeping
the public configuration, command, output-shape, and output-dtype
contracts. Task-error and task-Jacobian assembly stay in Isaac Lab so
subclasses such as the SO-101 pose IK controller can still shape the
task before Newton solves it.

Add AckermannController and the AckermannAction manager term to drive
physical Ackermann-steered vehicles through Newton's batched steering
kinematics, with vehicle-geometry validation and command clamping.

Enable MuJoCo-native gravity compensation for the Franka
differential-IK reach tasks under the newton_mjwarp preset, and fix
the SO-101 pose IK action to construct its controller through the
configured class type.
@hujc7
hujc7 requested a review from a team July 21, 2026 21:12
@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team labels Jul 21, 2026
@greptile-apps

greptile-apps Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR integrates Newton's controller library (newton_controllers) into Isaac Lab by replacing the pure-PyTorch DifferentialIKController solve path with Newton's ControllerDifferentialKinematicsModelFree, and by adding a new AckermannController/AckermannAction pair for Ackermann-steered vehicles. It also fixes the SO-101 pose-IK action to use class_type dispatch instead of a hardwired controller swap, and enables MuJoCo-native gravity compensation for Franka reach tasks under the newton_mjwarp preset.

  • DifferentialIKController now lazily initializes a Newton/Warp solver bridge on the first compute() call, preserving the public API (shape, dtype, out parameter) while adding input validation and a float32 internal buffer; the prior pure-Torch implementation is removed.
  • AckermannController / AckermannAction are new additions that delegate batched Ackermann kinematics to Newton's ControllerAckermann, with vehicle-geometry validation in the config, direction-multiplier support, and a non-finite command safety policy.
  • SO-101 and Franka reach fixes are small, targeted corrections enabled by the class_type dispatch refactor in DifferentialInverseKinematicsAction.

Confidence Score: 3/5

The Ackermann additions and the SO-101/Franka fixes are ready to merge. The DifferentialIKController rewrite introduces an undeclared hard dependency: existing users of that controller who haven't installed newton_controllers will encounter an ImportError the moment they access the class, with no helpful diagnostic.

The DifferentialIKController is one of the most commonly used controllers in Isaac Lab. Replacing its implementation with one that hard-imports newton_controllers without a try/except will break any environment or downstream package that imports DifferentialIKController without the new dependency present. The missing .view() reshape for _joint_pos_des also couples correctness silently to Newton's internal storage choices.

source/isaaclab/isaaclab/controllers/differential_ik.py — the hard newton_controllers import and the unguarded _joint_pos_des shape assumption both live here.

Important Files Changed

Filename Overview
source/isaaclab/isaaclab/controllers/differential_ik.py Core change: rewrites DifferentialIKController to delegate all IK solves to Newton's ControllerDifferentialKinematicsModelFree via a lazily-initialized Warp bridge. Introduces hard top-level import of newton_controllers (P1), missing .view() reshape for _joint_pos_des (P2), and new input validation stricter than the historical contract.
source/isaaclab/isaaclab/controllers/ackermann.py New AckermannController wrapping Newton's ControllerAckermann with Torch/Warp zero-copy bridge. Logic is sound; reset() uses unconventional tensor[None]=0.0 idiom (P2) but is functionally correct.
source/isaaclab/isaaclab/controllers/ackermann_cfg.py New AckermannControllerCfg with thorough post_init validation of vehicle geometry and command limits. Float32 bridge edge case for max_steering_angle near pi/2 is handled correctly.
source/isaaclab/isaaclab/envs/mdp/actions/ackermann_actions.py New AckermannAction MDP term. Joint validation, direction multipliers, scale/offset/clip processing, and non-finite command zeroing are all implemented correctly. reset() shares the tensor[None] idiom (P2).
source/isaaclab/isaaclab/envs/mdp/actions/task_space_actions.py DifferentialInverseKinematicsAction updated to instantiate the IK controller via class_type, detect the out parameter, and use a pre-allocated _joint_pos_des buffer. Jacobian aliasing fix is correct and well-commented.
source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/so101/pose_ik_action_term.py Removes the manual controller swap; now relies on class_type dispatch in the base DifferentialInverseKinematicsAction. Fix is correct and matches the test assertion in test_so101_pose_ik.py.
source/isaaclab_tasks/isaaclab_tasks/contrib/stack/config/so101/pose_ik_controller.py Adds class_type field to SO101PoseIKControllerCfg so the base action term can instantiate SO101PoseIKController directly through class_type dispatch.
source/isaaclab_tasks/isaaclab_tasks/contrib/reach/config/franka/robot_cfg.py New task-owned robot config that enables MuJoCo actuatorgravcomp under the newton_mjwarp preset via the preset() helper. Clean separation from PhysX default (None).

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant ActionTerm as DifferentialInverseKinematicsAction
    participant IKCtrl as DifferentialIKController
    participant Newton as Newton ControllerDifferentialKinematicsModelFree
    participant Warp as Warp bridge buffers

    ActionTerm->>IKCtrl: set_command(command, ee_pos, ee_quat)
    IKCtrl->>IKCtrl: validate + store ee_pos_des / ee_quat_des

    ActionTerm->>IKCtrl: compute(ee_pos, ee_quat, jacobian, joint_pos, out)
    IKCtrl->>IKCtrl: validate inputs and cast to float32
    IKCtrl->>IKCtrl: assemble task_jacobian and task_error
    IKCtrl->>IKCtrl: _initialize_controller on first call
    IKCtrl->>Warp: copy task_error, task_jacobian, joint_pos into bridge buffers
    IKCtrl->>Newton: compute(input, output, None, None, time_step)
    Newton-->>Warp: writes joint_target_q
    Warp-->>IKCtrl: _joint_pos_des zero-copy view
    IKCtrl-->>ActionTerm: return joint_pos_des snapshot or out buffer

    ActionTerm->>ActionTerm: set_joint_position_target_index
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant ActionTerm as DifferentialInverseKinematicsAction
    participant IKCtrl as DifferentialIKController
    participant Newton as Newton ControllerDifferentialKinematicsModelFree
    participant Warp as Warp bridge buffers

    ActionTerm->>IKCtrl: set_command(command, ee_pos, ee_quat)
    IKCtrl->>IKCtrl: validate + store ee_pos_des / ee_quat_des

    ActionTerm->>IKCtrl: compute(ee_pos, ee_quat, jacobian, joint_pos, out)
    IKCtrl->>IKCtrl: validate inputs and cast to float32
    IKCtrl->>IKCtrl: assemble task_jacobian and task_error
    IKCtrl->>IKCtrl: _initialize_controller on first call
    IKCtrl->>Warp: copy task_error, task_jacobian, joint_pos into bridge buffers
    IKCtrl->>Newton: compute(input, output, None, None, time_step)
    Newton-->>Warp: writes joint_target_q
    Warp-->>IKCtrl: _joint_pos_des zero-copy view
    IKCtrl-->>ActionTerm: return joint_pos_des snapshot or out buffer

    ActionTerm->>ActionTerm: set_joint_position_target_index
Loading

Comments Outside Diff (1)

  1. source/isaaclab/isaaclab/controllers/ackermann.py, line 218-226 (link)

    P2 tensor[None] = 0.0 is a correct but non-obvious reset idiom

    When env_ids=None, each of self._command[None] = 0.0, self._linear_speed_input[None] = 0.0, and self._steering_angle_input[None] = 0.0 does zero all elements — None creates an unsqueeze view and the assignment broadcasts back to the original storage. However, this is a NumPy/PyTorch trick that is easy to misread as a no-op. The rest of the Isaac Lab codebase typically handles this via tensor[:] = 0.0, tensor.zero_(), or an explicit if env_ids is None: env_ids = slice(None) guard. The same idiom appears in AckermannAction.reset().

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "Integrate Newton controllers for DiffIK ..." | Re-trigger Greptile


import torch
import warp as wp
from newton_controllers import ControllerDifferentialKinematicsModelFree

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 Hard import of newton_controllers at module level

from newton_controllers import ControllerDifferentialKinematicsModelFree is a top-level unconditional import. While isaaclab.controllers.__init__.py uses lazy_export() to defer submodule loading, that only delays the import until DifferentialIKController is first accessed — it doesn't skip it. Any existing Isaac Lab user who accesses DifferentialIKController without newton_controllers installed will immediately receive an unhelpful ModuleNotFoundError: No module named 'newton_controllers' instead of a diagnostic that explains what is missing and why.

A try/except at import time with an explanatory ImportError (re-raised from _initialize_controller) would make the dependency explicit and actionable, without requiring Newton for users who import the module at all.

self._controller_input.task_error = wp.from_torch(self._task_error)
self._controller_input.jacobian = wp.from_torch(self._task_jacobian)
self._controller_input.joint_q = wp.from_torch(self._joint_pos)
self._joint_pos_des = wp.to_torch(self._controller_output.joint_target_q)

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.

P2 Missing explicit .view(num_envs, num_joints) reshape for _joint_pos_des

The Ackermann controller calls .view(num_envs, 2) and .view(num_envs, self._num_wheels) after wp.to_torch because Newton's Ackermann output arrays are 1-D flat buffers. Here, no reshape is applied to joint_target_q, which means correctness relies on Newton's ControllerDifferentialKinematicsModelFree storing its output as a 2-D (num_envs, num_joints) array. If Newton ever normalises its storage to match the Ackermann convention, out.copy_(self._joint_pos_des) will silently fail with a shape mismatch at runtime. Adding .view(num_envs, num_joints) after the wp.to_torch call here would make the expected shape explicit and defensive against future Newton changes.

@hujc7
hujc7 marked this pull request as draft July 22, 2026 04:32
@hujc7 hujc7 changed the title Integrate Newton controllers for differential IK and Ackermann steering [Newton] Add Ackermann steering controller and action term Sep 16, 2026
@github-actions github-actions Bot added asset New asset feature or request isaac-sim Related to Isaac Sim team isaac-mimic Related to Isaac Mimic team infrastructure labels Sep 16, 2026
ooctipus pushed a commit that referenced this pull request Sep 24, 2026
…llers (#7854)

# Description

Added Newton 1.6 model-free differential IK, joint impedance, and OSC
through `cfg.use_newton=True`; the original Lab controllers remain the
default. Consolidates #6693, #7482, and the differential-IK portion of
#6654. Ackermann remains in its separate draft.

Both paths share constructor, command, and compute signatures and return
independent results. Controller selection is independent of the physics
backend. Newton initializes from compute inputs, or from supplied DiffIK
limits when avoidance is enabled. Existing callers and tutorials retain
their setup; SO101 retains its wrist-orientation mask through a
Newton-only Jacobian adaptation.

Newton uses float32 computation. Its OSC selects motion before inertia
decoupling, requires at least six joints for decoupling, and retains
motion-force coupling that fails three hybrid force-tracking cases.
Those Newton cases run as strict expected failures; Lab cases remain
active, and thresholds are unchanged. Convergence checks now apply masks
in the actual control frame.

Newton DiffIK requires joint limits before the first compute when
avoidance is enabled; later limit updates retain its buffers. Its `pinv`
also rejects fewer controlled joints than active task axes. These
differences prevent blanket replacement of the Lab path. Joint impedance
retains the same control law, subject to Newton's precision boundary.
Includes the position-only SVD and joint-impedance
gain-clamping/batched-inertia fixes.

## Type of change
- New feature, bug fix, documentation update

## Release backport
- [ ] <!-- backport-active-release --> Backport to the active release
branch

## Validation
- Post-merge CPU controller suite: **204 passed, 3 CUDA capture tests
skipped**. Formatting and changelog checks passed.
- Focused GPU hybrid simulation with current controller/test overlays,
16 environments: **3 Lab passed, 3 Newton xfailed**. This was not a
full-repository run of the final head.
- Warning-free current documentation build passed.
- Matched full-policy Lab/Newton videos were recorded for
Reach-Franka-OSC on PhysX/MJWarp and Drawer DiffIK on MJWarp. SO101
keyboard rollout and training equivalence remain unverified.
- Fresh Docker/GPU CI requested for the updated head; results pending.

## Checklist
- [x] Contribution guidelines followed; contributor already listed
- [x] Pre-commit checks run with `uv run isaaclab -f`
- [x] Documentation and package changelog fragments updated
- [x] Both-backend and regression tests added
- [ ] Newton hybrid force-tracking limitations resolved
- [ ] Changes generate no new warnings

---------

Co-authored-by: Mustafa H <34825877+StafaH@users.noreply.github.com>
Co-authored-by: Mustafa Haiderbhai <mhaiderbhai@nvidia.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
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 documentation Improvements or additions to documentation infrastructure isaac-lab Related to Isaac Lab team isaac-mimic Related to Isaac Mimic team isaac-sim Related to Isaac Sim team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant