Conversation
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.
Greptile SummaryThis PR integrates Newton's controller library (
Confidence Score: 3/5The 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
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
%%{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
|
|
|
||
| import torch | ||
| import warp as wp | ||
| from newton_controllers import ControllerDifferentialKinematicsModelFree |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
…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>
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.ControllerAckermannAPI. Released Newton does not provide it; this draft is not ready to merge.Type of change
Release backport
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
uv run isaaclab -f