Using Cables#

Isaac Lab exposes 1D cable / rod assets on the Newton backend. A cable is authored as a single open UsdGeom.BasisCurves prim carrying the PhysicsCurvesDeformableSimAPI schema, and is simulated by Newton’s VBD solver as a chain of per-segment capsule bodies joined by JointType.CABLE joints, with thickness, density, stretch stiffness, and bend stiffness.

Cable support is experimental. The spawner cfg, asset class, and material defaults may change while Newton cable support is under active development.

Note

Cables are only supported on the Newton backend, and only under its VBD solver. CableObject is a backend-dispatched factory: selecting PhysX or OpenUSD PhysX raises the factory import error at construction, so a misconfigured scene fails fast instead of loading the curve as inert geometry.

Quick Start: The Cable Demo#

Before adding cables to a task, run the standalone demo to confirm that the spawner, the VBD solver, collision, and the Kit / Fabric viewport sync all work in your environment:

# Default Newton VBD physics with the Kit visualizer.
uv run python scripts/demos/cables.py

# Explicit Newton VBD physics with the Newton visualizer.
uv run python scripts/demos/cables.py --physics newton_vbd --visualizer newton

# No visualizer and a larger cable pile.
uv run python scripts/demos/cables.py --visualizer none --num_cables 40 --num_segments 15

The demo accepts newton_vbd as its only --physics option. Its --visualizer option accepts kit, newton, rerun, viser, and none; when omitted, the demo uses kit. Use --num_cables and --num_segments to change the pile size and cable resolution. Use --max_steps to stop after a fixed number of simulation steps; its negative default runs until the selected visualizer closes or the process is interrupted.

The demo spawns a pile of randomly oriented cables onto a ground plane under standalone Newton VBD, lets them collide and settle, and periodically restores them to their spawn state. Source: scripts/demos/cables.py.

Authoring a Cable#

A cable is configured with a CableCfg plus a CableMaterialCfg. Adjacent pairs in positions become individual segments, each materialized as a capsule body of diameter CableMaterialCfg.thickness and joined to its neighbour by a Newton cable joint. N control points produce N-1 segment bodies and N-2 cable joints; the root segment is free-floating.

Parameter

Description

positions

Control points in the cable-local frame [m]. Requires at least three finite points, with consecutive points separated by more than 1e-8 m.

physics_material

Required CableMaterialCfg; see Cable Material Parameters below. Thickness is also written to the curve’s widths attribute so the visual radius matches the physics.

collision_props

Optional collision properties. When omitted, the cable is collision-free; when set (typically [UsdPhysicsCollisionCfg(collision_enabled=True)]), the cable collides with the ground and other cables. See Collision below.

visual_material

Optional VisualMaterialCfg for the curve’s appearance.

visual_material_path

Sub-path of the visual material under the cable geometry prim. Defaults to "material".

physics_material_path

Sub-path of the physics material under the cable geometry prim. Defaults to "physics_material".

import isaaclab.sim as sim_utils

cable_spawn = sim_utils.CableCfg(
    positions=[(index * 0.1, 0.0, 0.0) for index in range(10)],
    visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.7, 0.2, 0.2)),
    physics_material=sim_utils.CableMaterialCfg(
        thickness=0.03,
        density=1000.0,
        stretch_stiffness=1.0e9,
        bend_stiffness=1.0e6,
    ),
    collision_props=[sim_utils.UsdPhysicsCollisionCfg(collision_enabled=True)],
)

This authors a straight 0.9 m red cable along the cable-local x-axis: 9 capsule segments (0.1 m long, 0.03 m diameter) joined by 8 cable joints. See Loading Cables from USD for how the curve becomes Newton physics.

Wrap the spawner in a CableObjectCfg to get a runtime asset whose per-segment state can be read, written, and restored:

from isaaclab.assets import CableObject, CableObjectCfg

cable = CableObject(
    cfg=CableObjectCfg(
        prim_path="/World/Env_0/Cable",
        spawn=cable_spawn,
        init_state=CableObjectCfg.InitialStateCfg(pos=(0.0, 0.0, 0.5)),
    )
)

The inherited init_state sets the cable root’s spawn pose in each environment.

Picking a Solver#

Cables can only be simulated under Newton’s VBD solver, which is the only solver that steps JointType.CABLE joints. A cable-only scene uses a standalone VBDSolverCfg:

from isaaclab_newton.physics import NewtonCfg

from isaaclab_contrib.deformable import VBDSolverCfg

sim_cfg = sim_utils.SimulationCfg(
    dt=0.01,
    device=args_cli.device,
    physics=NewtonCfg(solver_cfg=VBDSolverCfg(iterations=20), num_substeps=8),
)

Mixed rigid + cable scenes (for example a robot manipulating a cable) run the cable under a CouplerProxyCfg entry: define a named VBD entry that owns the cable segments and couple it to the rigid entry. See VBD Solver.

Cable Material Parameters#

CableMaterialCfg defines the cable’s geometry and stiffness. All values are validated at author time; nonfinite or out-of-range values raise ValueError before any prim is created. The attributes are authored in the standard physics: namespace and read back by Newton’s importer.

Parameter

Description

thickness

Full cable thickness (diameter) [m]. Must be finite and positive. Newton uses radius = thickness / 2 for the capsule cross-section, the bending second moment of area, and the collision radius. Default 0.001.

density

Cable density [kg/m^3]. Must be finite and positive. Newton derives per-segment mass from the density and the capsule volume. Default 1000.0.

stretch_stiffness

Axial (stretch) elastic modulus E [Pa], i.e. force per area. Must be finite and nonnegative. Newton converts it to the rod’s per-joint axial stiffness E * A / L, where A is the circular cross-section area and L is the mean segment rest length. Higher values reduce elongation but need more solver iterations or substeps. Default 1.0e9.

bend_stiffness

Bending elastic modulus E [Pa]. Must be finite and nonnegative. Newton converts it to the per-joint bend stiffness E * I / L, where I is the second moment of area of the circular cross-section. 0.0 gives a limp rope; increase for a stiff hose or wire. Default 1.0e6.

shear_stiffness

Transverse shear elastic modulus [Pa]. Must be finite and nonnegative. Optional: when left at None the attribute is not authored and the solver falls back to stretch_stiffness. Default None.

twist_stiffness

Torsional elastic modulus [Pa]. Must be finite and nonnegative. Optional: when left at None the attribute is not authored and the solver falls back to bend_stiffness. Default None.

Note

A Newton cable joint has four degrees of freedom: linear stretch and shear, and angular bend and twist. Leaving shear_stiffness or twist_stiffness unset does not mean the cable has no shear or twist resistance; it means the solver reuses the stretch and bend moduli for them. Set them explicitly to decouple torsion from bending, for example a hose that bends easily but resists twisting. Authoring 0.0 is distinct from leaving them unset: it removes that resistance.

Damping is not exposed. The AOUSD deformable schema defines damping alongside the moduli, but Isaac Lab does not author it.

To target a specific axial E * A or bending E * I, invert these relations to pick the modulus; scripts/demos/cables.py does this from a target stiffness and the segment geometry.

Warning

Newton derives one stretch/bend stiffness pair for the whole cable, using the mean segment length as L. Author positions with roughly uniform spacing: with a strongly uneven spacing the per-joint stiffness is wrong for the outlier segments, since stiffness scales as 1 / L. A segment much longer than the mean comes out too stiff, and a much shorter one too soft.

Collision#

Collision is opt-in through collision_props. When enabled, the importer applies adjacent-segment-only collision filtering: directly connected segments (which share a joint anchor and would otherwise jitter) are filtered, while every other pair collides. As a result:

  • The cable collides with the ground and with other cables.

  • Non-adjacent segments of the same cable collide, so a cable can self-arrest when it loops back on itself.

  • Only immediate neighbours are filtered, matching Newton’s cable-pile behaviour.

When collision_props is omitted, the cable imports as a dynamics-only rod and does not collide.

Runtime State#

CableObject exposes per-segment world state through its data container and integrates with InteractiveScene, scene.get_state / scene.reset_to, and the reset_scene_to_default event term.

  • cable.data.segment_pose_w shape (num_instances, num_segments, 7), position [m] followed by quaternion (x, y, z, w).

  • cable.data.segment_velocity_w shape (num_instances, num_segments, 6), linear [m/s] followed by angular [rad/s].

  • cable.data.default_segment_pose_w / default_segment_velocity_w capture the spawn state for restoration.

Write per-segment state back with the indexed or masked setters. The masked form is CUDA-graph capturable:

cable.write_segment_pose_to_sim_index(
    segment_pose=cable.data.default_segment_pose_w,
)
cable.write_segment_velocity_to_sim_index(
    segment_velocity=cable.data.default_segment_velocity_w,
)

Writes update Newton’s maximal-coordinate body state directly (both simulation states) and flag the affected environments for a solver reset, without running forward kinematics.

Kit / Fabric Visualization#

Cables render in the Kit viewport as UsdGeom.BasisCurves. At render cadence the curve points are refreshed from Newton’s cable segment endpoints so the rendered shape always matches the simulation. Use the default --visualizer kit flag, as in the demo.

Note

Curve points are synchronized through CPU Fabric because the RTX Hydra delegate does not read GPU-backed Fabric arrays for BasisCurves (NVBug 6502662). The on-device sync path can be restored once that bug is fixed. Periodic curves are skipped by the sync.

Loading Cables from USD#

Physics is authored in place on the curve: spawn_cable() applies the PhysicsCurvesDeformableSimAPI schema and binds a deformable-curve material, and Newton imports the curve natively through ModelBuilder.add_usd. Topology comes from the curve’s own points and curveVertexCounts; no custom edge attribute is required, and imported and replicated cables use the same path.

A cable can therefore also be loaded from an external USD (for example one authored in a DCC tool) via UsdFileCfg, provided the curve in that USD already carries:

  • a single open, linear, nonperiodic UsdGeom.BasisCurves under the loaded prim,

  • the PhysicsCurvesDeformableSimAPI applied schema, and

  • a bound deformable-curve material (PhysicsCurvesDeformableMaterialAPI) supplying thickness, density, stretchStiffness, and bendStiffness in the physics: namespace.

A raw exported curve without the physics schema and material will not be recognized as a cable (the importer falls back to a default radius and warns, or skips the curve). Author it through spawn_cable(), or apply the schema and material to the imported prim before construction.

Limitations#

  • Newton + VBD only. Other backends and other Newton solvers are not supported.

  • One standalone, unwelded cable per object. CableObject requires “one standalone, unwelded cable articulation per simulation world”: exactly one BasisCurves prim carrying PhysicsCurvesDeformableSimAPI under prim_path, holding a single open curve that is not welded to another cable. Multi-curve BasisCurves prims, periodic (closed) curves, and hard coincident curve-to-curve PhysicsAttachment welds all fail during initialization.

  • Cable ends can be pinned, not clamped. A PhysicsAttachment to an xform target lowers to a ball joint, so it constrains position only and the cable pivots freely at the anchor. Rigid plugs and end fittings that must transfer orientation are not representable. The joint is also created only when the attachment stiffness is unauthored or infinite; a finite stiffness is kept as metadata and no joint is created. Both cases are import warnings rather than errors, so the cable initializes normally with the attachment missing. Check the importer output when an attachment appears to have no effect.

  • No damping knobs. The four stiffness moduli are exposed; their damping counterparts are not.

  • Uniform point spacing assumed. One stiffness pair is derived from the mean segment length, so uneven spacing mistunes the outlier segments.

  • CPU-only render sync (NVBug 6502662); periodic curves are not synced.

Note

Topologies the runtime object rejects still simulate: the Newton model is built from the whole USD stage, so every curve carrying PhysicsCurvesDeformableSimAPI is imported whether or not a CableObject wraps it. Drive them through NewtonManager get_model() / get_state_0() and your own newton.selection.ArticulationView. There is no Isaac Lab asset wrapper for those cases.

For the public API, see CableObject, CableCfg, and CableMaterialCfg.