newton.controllers.ControllerDifferentialIKModelFree#
- class newton.controllers.ControllerDifferentialIKModelFree(*, controlled_dofs_per_robot, axis_weight=None, bandwidth, damping, ik_method=DifferentialIKMethod.DAMPED_LEAST_SQUARES, adaptive_damping_min=None, adaptive_damping_max=None, adaptive_damping_threshold=None, truncated_svd_threshold=None, use_joint_limit_avoidance=False, joint_limit_avoidance_gain=0.0, joint_limit_avoidance_margin=0.0, joint_pos_lower=None, joint_pos_upper=None, use_null_space_posture_control=False, null_space_stiffness=None, null_space_damping=None, null_space_axes=None, device=None, requires_grad=False)[source]#
Bases:
ControllerBaseDifferential-kinematics (Jacobian-based) controller with a caller-supplied Jacobian.
Implements a differential-kinematics control law, selectable per instance via
DifferentialIKMethod(damped least squares by default). This model-free variant expects the tool-point Jacobian and the current tool pose to be computed externally — it is the caller’s responsibility to provide them, and to keep them consistent withinputs.joint_q, before everystep().Every per-DOF port is compact: a 1-D array with one entry per controlled DOF, ordered robot 0’s DOFs first, then robot 1’s, matching
controlled_dofs_per_robot. Every per-robot port has one entry per robot, since the task-space storage is always 6D regardless of a robot’s ownaxis_weight. A port may be bound either to a plain array or to an indexed view of a simulation-sized array, which is how a caller expresses a gather or scatter without the controller owning an index table — for example, using a paired model-based controller’s ownq_start/qd_startproperties (seeControllerDifferentialIK.q_start):inputs.joint_q = state.joint_q[ctrl.q_start] # gather outputs.joint_q_target = control.joint_target_q[ctrl.q_start] # scatter
Views are live and graph-capturable: bind them once, and each step (or graph replay) reads through to the current contents of the underlying array.
Array shapes and devices are validated on each direct call to
step(), but not when a captured graph is replayed, since the checks run in Python at capture time only.Supports heterogeneous robot fleets — robots may have different controlled-DOF counts. The Jacobian is padded to
max_controlled_dofs; every other buffer is compact.Allocate input and output structs via
input()andoutput(). All field names on those structs are fixed — seeInputsandOutputsfor the typed schema.- Parameters:
controlled_dofs_per_robot (wp.array[wp.int32]) – Controlled-DOF count for each robot. Its length sets
controlled_robot_count, its sum setstotal_controlled_dofs(the length of every compact port), and its maximum setsmax_controlled_dofs(the padded width of the Jacobian). Every entry must be positive.axis_weight (wp.array[wp.spatial_vector] | wp.spatial_vector | None) – Non-negative per-axis weight for each of the 6 canonical task axes (position x, y, z, then orientation x, y, z),
diag(w)applied to both the Jacobian and the pose error for that axis before the solve (J_w = diag(w) @ J,e_w = diag(w) @ e) — a genuine soft weight for any nonzero value. An axis weighted exactly0is different in kind, not just degree: it is excluded from the solve structurally (its error and Jacobian rows never enter it at all), not merely driven toward zero by a very small weight — this also shrinks the task’s own dimension, so a robot with fewer than 6 controlled DOFs can still be redundant if enough axes are zeroed. Any combination of active axes is allowed, not just a leading prefix. Pass a singlewp.spatial_vectorto apply the same weights to every robot, or an array of shape [controlled_robot_count] to set them per robot.None(the default) means every axis is weighted1for every robot — full, equally-trusted 6D pose.bandwidth (wp.array[wp.float32] | float | None) – Output velocity scale gain, applied per controlled DOF after the Jacobian solve. Must be non-negative, since a negative value would flip the output velocity’s direction. Checked at construction when baked; a live value is the caller’s own responsibility, since checking it every step would cost a host sync and break
is_graphable(). Pass a scalar to apply the same gain to every controlled DOF, an array of shape [total_controlled_dofs] to set them individually, orNoneto readinputs.bandwidtheach step.damping (wp.array[wp.float32] | float | None) – Damped-least-squares regularization λ, applied per robot to the task-space normal-equations matrix. Pass a scalar to apply the same damping to every robot, an array of shape [controlled_robot_count] to set them individually, or
Noneto readinputs.dampingeach step. Only meaningful whenik_method=DifferentialIKMethod.DAMPED_LEAST_SQUARES(the default); must beNonefor every otherDifferentialIKMethod, which has no λ to set.ik_method (DifferentialIKMethod) – Inverse-Jacobian solve method, a
DifferentialIKMethod. Defaults toDifferentialIKMethod.DAMPED_LEAST_SQUARES.adaptive_damping_min (float | None) – λ used when the smallest singular value of the task Jacobian is at or above
adaptive_damping_threshold. Required (and must be non-negative) whenik_method=DifferentialIKMethod.ADAPTIVE_DAMPING; must beNoneotherwise.adaptive_damping_max (float | None) – λ used at a full singularity (smallest singular value zero), ramping down to
adaptive_damping_minas the smallest singular value rises toadaptive_damping_threshold. Required (and must exceedadaptive_damping_min) whenik_method=DifferentialIKMethod.ADAPTIVE_DAMPING; must beNoneotherwise.adaptive_damping_threshold (float | None) – Smallest-singular-value threshold below which damping starts ramping from
adaptive_damping_mintowardadaptive_damping_max. Required (and must be positive) whenik_method=DifferentialIKMethod.ADAPTIVE_DAMPING; must beNoneotherwise.truncated_svd_threshold (float | None) – Per-direction singular-value threshold — a task-space direction with singular value above this is inverted exactly, one at or below it is dropped from the solve entirely. Required (and must be positive) when
ik_method=DifferentialIKMethod.TRUNCATED_SVD; must beNoneotherwise.use_joint_limit_avoidance (bool) – Project a joint-limit-avoidance bias through the null-space projector. Requires
joint_limit_avoidance_gain,joint_limit_avoidance_margin,joint_pos_lower, andjoint_pos_upper.joint_limit_avoidance_gain (float) – Joint-centering gain, applied once a DOF comes within
joint_limit_avoidance_marginof either limit. Required (and must be positive) whenuse_joint_limit_avoidance=True.joint_limit_avoidance_margin (float) – Distance from either limit at which the avoidance bias starts ramping in [m or rad], same units as
joint_pos_lower/joint_pos_upper. Required (and must be positive) whenuse_joint_limit_avoidance=True.joint_pos_lower (wp.array[wp.float32] | None) – Lower joint position limit per controlled DOF [m or rad], shape [total_controlled_dofs]. Required when
use_joint_limit_avoidance=True; baked at construction, not a live port.joint_pos_upper (wp.array[wp.float32] | None) – Upper joint position limit per controlled DOF [m or rad], shape [total_controlled_dofs]. Required when
use_joint_limit_avoidance=True; baked at construction, not a live port.use_null_space_posture_control (bool) – Project a proportional pull toward
inputs.q_des_nullthrough the null-space projector. Enablesnull_space_stiffness.null_space_stiffness (wp.array[wp.float32] | float | None) – Posture-control proportional gain, applied per controlled DOF. Must be non-negative; checked the same way as
bandwidth. Pass a scalar to apply the same gain to every controlled DOF, an array of shape [total_controlled_dofs] to set them individually, orNoneto readinputs.null_space_stiffnesseach step. Must beNonewhenuse_null_space_posture_control=False.null_space_damping (wp.array[wp.float32] | float | None) – Damping λ_null for the null-space projector’s own
(JJᵀ + λ_null²I)⁻¹, independent of the primary task’sdamping. Must be non-negative; checked the same way asbandwidth. Only meaningful whenuse_joint_limit_avoidanceoruse_null_space_posture_controlis enabled — pass a scalar or an array of shape [controlled_robot_count] to bake a value, or leave itNoneto readinputs.null_space_dampingeach step (the default, and the only valid value when both are disabled). Unlike the primarydamping,λ_null = 0is only safe when every robot has at least as many controlled DOFs as its own task dimension (the number of nonzeronull_space_axesentries) — otherwise the projector’s ownJJᵀis rank-deficient. That stronger, per-robot requirement is checked at construction only when baked; a live value is the caller’s responsibility there, since it needs the null-space task dimension andcontrolled_dofs_per_robotcompared per robot, not just a sign check.null_space_axes (wp.array[wp.spatial_vector] | wp.spatial_vector | None) – Which of the 6 canonical axes the null-space projector guarantees the secondary objective (joint-limit avoidance/posture control) won’t disturb — zero leaves that axis unprotected, nonzero protects it; only the sign matters, unlike
axis_weight’s own soft magnitude. Defaults toaxis_weight(every solved axis protected), but the two are independent: an axis can be softly solved for yet left unprotected, e.g. an under-actuated arm with too few DOFs to protect every solved axis and still have a usable null space left over. Unlikeaxis_weight, an all-zero row is legal — it protects no axes, so the secondary objective is free to move all of them. Only meaningful whenuse_joint_limit_avoidanceoruse_null_space_posture_controlis enabled.device (Any) – Warp device.
requires_grad (bool) – Not supported at this time; must be
False.
- class Inputs#
Bases:
objectInput struct returned by
input().Every compact 1-D field has shape [total_controlled_dofs]; every per-robot field has shape [controlled_robot_count]. Optional fields are
Nonewhen the corresponding gain is baked at construction.- bandwidth: wp.array[wp.float32] | wp.indexedarray[wp.float32] | None#
Output velocity scale gain, shape [total_controlled_dofs].
Nonewhen baked at construction.
- damping: wp.array[wp.float32] | wp.indexedarray[wp.float32] | None#
Damped-least-squares regularization λ, shape [controlled_robot_count].
Nonewhen baked at construction.
- desired_tool_pose_world: wp.array[wp.transformf] | wp.indexedarray[wp.transformf]#
Desired tool pose [m, unitless quaternion], world frame, shape [controlled_robot_count].
- jacobian_tool_world: wp.array3d[wp.float32] | <warp._src.types.indexedarray object>#
Tool-point Jacobian, world frame, shape [controlled_robot_count, 6, max_controlled_dofs]; columns beyond a robot’s own controlled-DOF count are unused. Rows 0-2 map a controlled DOF’s velocity to the tool point’s linear velocity [1 or m], rows 3-5 to its angular velocity [1/m or 1].
- joint_q: wp.array[wp.float32] | wp.indexedarray[wp.float32]#
Current joint positions [m or rad], shape [total_controlled_dofs].
- null_space_damping: wp.array[wp.float32] | wp.indexedarray[wp.float32] | None#
Null-space projector damping λ_null, shape [controlled_robot_count].
Nonewhen both secondary objectives are disabled, or when baked at construction.
- null_space_stiffness: wp.array[wp.float32] | wp.indexedarray[wp.float32] | None#
Posture-control proportional gain, shape [total_controlled_dofs].
Nonewhen disabled, or when baked at construction.
- q_des_null: wp.array[wp.float32] | wp.indexedarray[wp.float32] | None#
Null-space posture target [m or rad], shape [total_controlled_dofs].
Noneunlessuse_null_space_posture_control=True.
- tool_pose_world: wp.array[wp.transformf] | wp.indexedarray[wp.transformf]#
Current tool pose [m, unitless quaternion], world frame, shape [controlled_robot_count].
- class Outputs#
Bases:
objectOutput struct returned by
output().- joint_q_target: wp.array[wp.float32] | wp.indexedarray[wp.float32]#
One-step-ahead target joint position [m or rad], shape [total_controlled_dofs] =
joint_q + joint_qd_target * dt.
- joint_qd_target: wp.array[wp.float32] | wp.indexedarray[wp.float32]#
Target joint velocity [m/s or rad/s], shape [total_controlled_dofs].
- __init__(*, controlled_dofs_per_robot, axis_weight=None, bandwidth, damping, ik_method=DifferentialIKMethod.DAMPED_LEAST_SQUARES, adaptive_damping_min=None, adaptive_damping_max=None, adaptive_damping_threshold=None, truncated_svd_threshold=None, use_joint_limit_avoidance=False, joint_limit_avoidance_gain=0.0, joint_limit_avoidance_margin=0.0, joint_pos_lower=None, joint_pos_upper=None, use_null_space_posture_control=False, null_space_stiffness=None, null_space_damping=None, null_space_axes=None, device=None, requires_grad=False)#
- is_graphable()#
- set_joint_limits(*, joint_pos_lower, joint_pos_upper)#
Update the joint position limits used by joint-limit avoidance, in place.
Unlike
bandwidth/damping/etc., joint limits have no liveinputs.*port – they change far less often, so a setter suits them better than a per-step read. The caller is responsible for keepinginputs.joint_qconsistent with the new limits.- Parameters:
joint_pos_lower (wp.array[wp.float32]) – Lower joint position limit per controlled DOF [m or rad], shape [total_controlled_dofs].
joint_pos_upper (wp.array[wp.float32]) – Upper joint position limit per controlled DOF [m or rad], shape [total_controlled_dofs].
- step(*, inputs, outputs, dt)#
Compute one differential-kinematics step and write joint velocity/position targets.
- property controlled_robot_count: int#
Number of robots, i.e. the length of
controlled_dofs_per_robot.