Skip to content

Commit 44a2209

Browse files
committed
[Docs] Tighten BaseArticulation docstrings to interface contract
Removed consumer-name leakage from the abstract-method docstrings on BaseArticulation (get_jacobians / get_mass_matrix / get_gravity_compensation_forces). Base-class API docs should declare what the method is and the cross-backend contract -- not which controllers consume the result, which conditions trigger fetches, or how the underlying view differs from the new accessor. What's removed: - "Used by OperationalSpaceController when ..." - "Task-space controllers (IK, OSC, RMPFlow) slice this array ..." - "Callers should use this instead of root_view.get_jacobians()" - "callers should gate this method behind their own feature flag" - The wordy "concrete with NotImplementedError so out-of-tree backends..." paragraph -- that's an internal convention, not API contract for callers. What stays / was tightened: - The J . q_dot identity defining the contract. - Backend-implementer requirement that COM-referenced native Jacobians MUST shift to link origin before returning. - Floating-base joint-dim caveat (a real cross-backend contract difference), reworded without naming PhysX / Newton specifically. - Mass matrix doc: state the equation of motion role of M(q). - Gravity comp doc: state the static-equilibrium contract for g(q). Also tightened two adjacent sites that named consumers in implementation comments: - shift_jacobian_com_to_origin kernel docstring no longer says "PhysX (and the IK/OSC controllers)"; refers to the BaseArticulation contract directly. - Newton _create_buffers comment: "jacobian buffers for task-space controllers (IK, OSC, RMPFlow)" -> "jacobian buffers backing get_jacobians".
1 parent f5eaf90 commit 44a2209

3 files changed

Lines changed: 46 additions & 87 deletions

File tree

source/isaaclab/isaaclab/assets/articulation/base_articulation.py

Lines changed: 40 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -176,110 +176,70 @@ def root_view(self):
176176
def get_jacobians(self) -> wp.array:
177177
"""Per-env geometric Jacobians, referenced at each link origin in world frame.
178178
179-
Returns the geometric Jacobian ``J`` such that, for any joint-velocity
180-
vector ``q_dot`` consistent with the asset's DoF ordering,
179+
For any joint-velocity vector ``q_dot`` consistent with the
180+
asset's DoF ordering, the returned Jacobian ``J`` satisfies:
181181
182182
.. code-block:: text
183183
184184
J[:, body_idx, 0:3, :] @ q_dot == data.body_link_lin_vel_w[:, body_idx]
185185
J[:, body_idx, 3:6, :] @ q_dot == data.body_link_ang_vel_w[:, body_idx]
186186
187-
That is, the linear-velocity rows ``[0:3]`` give the velocity at the
188-
link origin (the body's USD prim transform / actor frame), in world
189-
frame; the angular rows ``[3:6]`` give the body's angular velocity in
190-
world frame. Both share the world-frame contract used by
191-
:attr:`~isaaclab.assets.ArticulationData.body_link_pos_w`,
192-
:attr:`~isaaclab.assets.ArticulationData.body_link_lin_vel_w`, and the
193-
body-offset shift in
194-
:class:`~isaaclab.envs.mdp.actions.task_space_actions.DifferentialInverseKinematicsAction`.
195-
196-
Backend implementations whose native Jacobian is expressed at a
197-
different reference point (e.g. Newton's ``eval_jacobian``, which is
198-
center-of-mass referenced) MUST apply the corresponding shift before
199-
returning so this contract holds across backends.
200-
201-
Shape is ``(num_instances, num_jacobi_bodies, 6, num_jacobi_joints)``,
202-
where ``num_jacobi_bodies`` excludes the fixed base body (if any) and
203-
``num_jacobi_joints`` is the per-articulation generalized DoF count.
204-
Task-space controllers (IK, OSC, RMPFlow) slice this array to extract
205-
the end-effector Jacobian.
206-
207-
.. note::
208-
Newton and PhysX implementations differ in how the underlying
209-
view exposes the Jacobian. Callers should use this method
210-
instead of calling ``root_view.get_jacobians()`` directly,
211-
which only works on PhysX.
212-
213-
.. note::
214-
Floating-base joint-dim convention differs across backends.
215-
PhysX prepends 6 virtual DoFs to the joint dimension, so its
216-
Jacobian shape is ``(N, num_bodies, 6, num_joints + 6)`` where
217-
``num_joints`` counts only the actuated joints. Newton already
218-
counts the floating-base joint's 6 DoFs inside
219-
``ArticulationView.joint_dof_count``, so the Newton wrapper
220-
returns ``(N, num_bodies, 6, num_joints)``. The total
221-
joint-dim is the same on both backends; only how
222-
:attr:`num_joints` is reported differs. Floating-base
223-
task-space callers should verify their joint indexing against
224-
the active backend's DoF ordering.
225-
226-
This method is concrete with a ``NotImplementedError`` body so
227-
out-of-tree backends that subclass ``BaseArticulation`` do not
228-
break at instantiation; they fail only when this accessor is
229-
actually invoked, matching the deprecation policy in AGENTS.md.
187+
Linear rows ``[0:3]`` give the velocity at the link origin (the
188+
body's USD prim transform / actor frame) in world frame.
189+
Angular rows ``[3:6]`` give the body's angular velocity in
190+
world frame. Both share the contract used by
191+
:attr:`~isaaclab.assets.ArticulationData.body_link_pos_w` and
192+
:attr:`~isaaclab.assets.ArticulationData.body_link_lin_vel_w`.
193+
194+
Implementations whose native Jacobian is expressed at a
195+
different reference point (e.g. body center of mass) MUST shift
196+
the linear rows to the link origin before returning so the
197+
contract above holds across backends.
198+
199+
Floating-base joint-dim convention differs across backends:
200+
some prepend the floating-base 6 DoFs to the joint dimension,
201+
others fold them into the native joint-DoF count. The total
202+
joint dimension is the same; only how :attr:`num_joints` is
203+
reported differs.
230204
231205
Returns:
232-
The per-env geometric Jacobian, link-origin referenced, in world
233-
frame. Shape
206+
The per-env geometric Jacobian. Shape
234207
``(num_instances, num_jacobi_bodies, 6, num_jacobi_joints)``,
235-
dtype ``float32``. Linear rows ``[0:3]`` [m/s], angular rows
236-
``[3:6]`` [rad/s].
208+
dtype ``float32``. Linear rows ``[0:3]`` [m/s], angular
209+
rows ``[3:6]`` [rad/s] for unit ``q_dot``.
237210
"""
238-
raise NotImplementedError(
239-
f"{type(self).__name__} does not implement get_jacobians."
240-
" Concrete IsaacLab backends (PhysX, Newton) override this method."
241-
)
211+
raise NotImplementedError(f"{type(self).__name__} does not implement get_jacobians.")
242212

243213
def get_mass_matrix(self) -> wp.array:
244214
"""Per-env generalized mass matrix in joint space.
245215
246-
Used by :class:`~isaaclab.controllers.OperationalSpaceController`
247-
when ``inertial_dynamics_decoupling`` is enabled or when
248-
``nullspace_control != "none"``. Backend implementations return
249-
shape ``(num_instances, num_jacobi_joints, num_jacobi_joints)``
250-
matching the Jacobian's joint-space dimension.
251-
252-
Concrete with ``NotImplementedError`` for the same backwards-
253-
compatibility reason as :meth:`get_jacobians`.
216+
Returns the symmetric positive-definite inertia matrix
217+
``M(q)`` of the articulation in its generalized joint
218+
coordinates. ``M[i, j]`` is the coefficient relating joint
219+
``j``'s acceleration to the inertial torque on joint ``i`` in
220+
the equation of motion ``M(q) q_ddot + C(q, q_dot) q_dot + g(q) = tau``.
254221
255222
Returns:
256-
The per-env mass matrix as a Warp array. Shape
223+
The per-env mass matrix. Shape
257224
``(num_instances, num_jacobi_joints, num_jacobi_joints)``,
258-
dtype ``float32``.
225+
dtype ``float32`` [kg·m²].
259226
"""
260-
raise NotImplementedError(
261-
f"{type(self).__name__} does not implement get_mass_matrix."
262-
" Concrete IsaacLab backends (PhysX, Newton) override this method."
263-
)
227+
raise NotImplementedError(f"{type(self).__name__} does not implement get_mass_matrix.")
264228

265229
def get_gravity_compensation_forces(self) -> wp.array:
266-
"""Per-env joint-space gravity compensation torques.
230+
"""Per-env gravity compensation torques in joint space.
267231
268-
Used by :class:`~isaaclab.controllers.OperationalSpaceController`
269-
when ``gravity_compensation`` is enabled. Backends that lack a
270-
native primitive (Newton at present) override this method to
271-
raise :class:`NotImplementedError`; callers should gate this
272-
method behind their own feature flag.
232+
Returns ``g(q)`` -- the joint-space gravity-loading term in the
233+
equation of motion ``M(q) q_ddot + C(q, q_dot) q_dot + g(q) = tau``.
234+
Applying ``tau = g(q)`` at ``q_dot = 0`` with no external load
235+
yields ``q_ddot = 0`` (static equilibrium under gravity).
273236
274237
Returns:
275-
The per-env gravity-compensation joint torques as a Warp
276-
array. Shape ``(num_instances, num_jacobi_joints)``, dtype
277-
``float32``.
238+
The per-env gravity-compensation joint torques. Shape
239+
``(num_instances, num_jacobi_joints)``, dtype ``float32``
240+
[N·m].
278241
"""
279-
raise NotImplementedError(
280-
f"{type(self).__name__} does not implement get_gravity_compensation_forces."
281-
" The PhysX backend implements this; Newton does not (no upstream primitive)."
282-
)
242+
raise NotImplementedError(f"{type(self).__name__} does not implement get_gravity_compensation_forces.")
283243

284244
@property
285245
@abstractmethod

source/isaaclab_newton/isaaclab_newton/assets/articulation/articulation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3315,7 +3315,7 @@ def _create_buffers(self):
33153315
self._joint_vel_target_sim = wp.zeros_like(self.data.joint_pos_target.warp, device=self.device)
33163316
self._joint_effort_target_sim = wp.zeros_like(self.data.joint_pos_target.warp, device=self.device)
33173317

3318-
# -- jacobian buffers for task-space controllers (IK, OSC, RMPFlow).
3318+
# -- jacobian buffers backing :meth:`get_jacobians`.
33193319
# Pre-allocated here (not lazily on first call) for capture safety.
33203320
model = SimulationManager.get_model()
33213321
max_links = model.max_joints_per_articulation

source/isaaclab_newton/isaaclab_newton/assets/articulation/kernels.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -634,10 +634,10 @@ def shift_jacobian_com_to_origin(
634634
635635
Newton's ``eval_jacobian`` returns ``J · q_dot = [v_com_world, omega_world]``
636636
per link — the linear rows are the velocity of the link's center of mass,
637-
expressed in world frame. PhysX (and the IsaacLab task-space controllers
638-
that consume :meth:`~isaaclab.assets.BaseArticulation.get_jacobians`) expect
639-
the linear rows to be the velocity at the link **origin** (USD prim
640-
transform), so that ``J · q_dot[body_idx]`` matches
637+
expressed in world frame. The
638+
:meth:`~isaaclab.assets.BaseArticulation.get_jacobians` contract
639+
requires the linear rows to be the velocity at the link **origin**
640+
(USD prim transform) so that ``J · q_dot[body_idx]`` matches
641641
:attr:`~isaaclab.assets.ArticulationData.body_link_lin_vel_w` /
642642
:attr:`~isaaclab.assets.ArticulationData.body_link_ang_vel_w`.
643643
@@ -648,8 +648,7 @@ def shift_jacobian_com_to_origin(
648648
the same ``v_origin = v_com - omega x (R · body_com_pos_b)`` identity.
649649
650650
Notes on layout:
651-
* Jacobian rows ``[0:3]`` are linear velocity, ``[3:6]`` are angular,
652-
matching the IsaacLab convention used by the IK / OSC controllers.
651+
* Jacobian rows ``[0:3]`` are linear velocity, ``[3:6]`` are angular.
653652
* ``body_link_pose`` and ``body_com_pos_b`` are indexed by the
654653
articulation's full body count, so ``link_offset`` must be applied
655654
to map a row in the (already-gathered) ``J`` to its body index in

0 commit comments

Comments
 (0)